cosmic_text/edit/
editor.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3#[cfg(not(feature = "std"))]
4use alloc::{
5    string::{String, ToString},
6    vec::Vec,
7};
8use core::{cmp, iter::once};
9use unicode_segmentation::UnicodeSegmentation;
10
11#[cfg(feature = "swash")]
12use crate::Color;
13use crate::{
14    Action, Attrs, AttrsList, BorrowedWithFontSystem, BufferLine, BufferRef, Change, ChangeItem,
15    Cursor, Edit, FontSystem, LayoutRun, Selection, Shaping,
16};
17
18/// A wrapper of [`Buffer`] for easy editing
19#[derive(Debug, Clone)]
20pub struct Editor<'buffer> {
21    buffer_ref: BufferRef<'buffer>,
22    cursor: Cursor,
23    cursor_x_opt: Option<i32>,
24    selection: Selection,
25    cursor_moved: bool,
26    auto_indent: bool,
27    change: Option<Change>,
28}
29
30fn cursor_glyph_opt(cursor: &Cursor, run: &LayoutRun) -> Option<(usize, f32)> {
31    if cursor.line == run.line_i {
32        for (glyph_i, glyph) in run.glyphs.iter().enumerate() {
33            if cursor.index == glyph.start {
34                return Some((glyph_i, 0.0));
35            } else if cursor.index > glyph.start && cursor.index < glyph.end {
36                // Guess x offset based on characters
37                let mut before = 0;
38                let mut total = 0;
39
40                let cluster = &run.text[glyph.start..glyph.end];
41                for (i, _) in cluster.grapheme_indices(true) {
42                    if glyph.start + i < cursor.index {
43                        before += 1;
44                    }
45                    total += 1;
46                }
47
48                let offset = glyph.w * (before as f32) / (total as f32);
49                return Some((glyph_i, offset));
50            }
51        }
52        match run.glyphs.last() {
53            Some(glyph) => {
54                if cursor.index == glyph.end {
55                    return Some((run.glyphs.len(), 0.0));
56                }
57            }
58            None => {
59                return Some((0, 0.0));
60            }
61        }
62    }
63    None
64}
65
66fn cursor_position(cursor: &Cursor, run: &LayoutRun) -> Option<(i32, i32)> {
67    let (cursor_glyph, cursor_glyph_offset) = cursor_glyph_opt(cursor, run)?;
68    let x = match run.glyphs.get(cursor_glyph) {
69        Some(glyph) => {
70            // Start of detected glyph
71            if glyph.level.is_rtl() {
72                (glyph.x + glyph.w - cursor_glyph_offset) as i32
73            } else {
74                (glyph.x + cursor_glyph_offset) as i32
75            }
76        }
77        None => match run.glyphs.last() {
78            Some(glyph) => {
79                // End of last glyph
80                if glyph.level.is_rtl() {
81                    glyph.x as i32
82                } else {
83                    (glyph.x + glyph.w) as i32
84                }
85            }
86            None => {
87                // Start of empty line
88                0
89            }
90        },
91    };
92
93    Some((x, run.line_top as i32))
94}
95
96impl<'buffer> Editor<'buffer> {
97    /// Create a new [`Editor`] with the provided [`Buffer`]
98    pub fn new(buffer: impl Into<BufferRef<'buffer>>) -> Self {
99        Self {
100            buffer_ref: buffer.into(),
101            cursor: Cursor::default(),
102            cursor_x_opt: None,
103            selection: Selection::None,
104            cursor_moved: false,
105            auto_indent: false,
106            change: None,
107        }
108    }
109
110    /// Draw the editor
111    #[cfg(feature = "swash")]
112    #[allow(clippy::too_many_arguments)]
113    pub fn draw<F>(
114        &self,
115        font_system: &mut FontSystem,
116        cache: &mut crate::SwashCache,
117        text_color: Color,
118        cursor_color: Color,
119        selection_color: Color,
120        selected_text_color: Color,
121        mut f: F,
122    ) where
123        F: FnMut(i32, i32, u32, u32, Color),
124    {
125        let selection_bounds = self.selection_bounds();
126        self.with_buffer(|buffer| {
127            for run in buffer.layout_runs() {
128                let line_i = run.line_i;
129                let line_y = run.line_y;
130                let line_top = run.line_top;
131                let line_height = run.line_height;
132
133                // Highlight selection
134                if let Some((start, end)) = selection_bounds {
135                    if line_i >= start.line && line_i <= end.line {
136                        let mut range_opt = None;
137                        for glyph in run.glyphs.iter() {
138                            // Guess x offset based on characters
139                            let cluster = &run.text[glyph.start..glyph.end];
140                            let total = cluster.grapheme_indices(true).count();
141                            let mut c_x = glyph.x;
142                            let c_w = glyph.w / total as f32;
143                            for (i, c) in cluster.grapheme_indices(true) {
144                                let c_start = glyph.start + i;
145                                let c_end = glyph.start + i + c.len();
146                                if (start.line != line_i || c_end > start.index)
147                                    && (end.line != line_i || c_start < end.index)
148                                {
149                                    range_opt = match range_opt.take() {
150                                        Some((min, max)) => Some((
151                                            cmp::min(min, c_x as i32),
152                                            cmp::max(max, (c_x + c_w) as i32),
153                                        )),
154                                        None => Some((c_x as i32, (c_x + c_w) as i32)),
155                                    };
156                                } else if let Some((min, max)) = range_opt.take() {
157                                    f(
158                                        min,
159                                        line_top as i32,
160                                        cmp::max(0, max - min) as u32,
161                                        line_height as u32,
162                                        selection_color,
163                                    );
164                                }
165                                c_x += c_w;
166                            }
167                        }
168
169                        if run.glyphs.is_empty() && end.line > line_i {
170                            // Highlight all of internal empty lines
171                            range_opt = Some((0, buffer.size().0.unwrap_or(0.0) as i32));
172                        }
173
174                        if let Some((mut min, mut max)) = range_opt.take() {
175                            if end.line > line_i {
176                                // Draw to end of line
177                                if run.rtl {
178                                    min = 0;
179                                } else {
180                                    max = buffer.size().0.unwrap_or(0.0) as i32;
181                                }
182                            }
183                            f(
184                                min,
185                                line_top as i32,
186                                cmp::max(0, max - min) as u32,
187                                line_height as u32,
188                                selection_color,
189                            );
190                        }
191                    }
192                }
193
194                // Draw cursor
195                if let Some((x, y)) = cursor_position(&self.cursor, &run) {
196                    f(x, y, 1, line_height as u32, cursor_color);
197                }
198
199                for glyph in run.glyphs.iter() {
200                    let physical_glyph = glyph.physical((0., 0.), 1.0);
201
202                    let mut glyph_color = match glyph.color_opt {
203                        Some(some) => some,
204                        None => text_color,
205                    };
206                    if text_color != selected_text_color {
207                        if let Some((start, end)) = selection_bounds {
208                            if line_i >= start.line
209                                && line_i <= end.line
210                                && (start.line != line_i || glyph.end > start.index)
211                                && (end.line != line_i || glyph.start < end.index)
212                            {
213                                glyph_color = selected_text_color;
214                            }
215                        }
216                    }
217
218                    cache.with_pixels(
219                        font_system,
220                        physical_glyph.cache_key,
221                        glyph_color,
222                        |x, y, color| {
223                            f(
224                                physical_glyph.x + x,
225                                line_y as i32 + physical_glyph.y + y,
226                                1,
227                                1,
228                                color,
229                            );
230                        },
231                    );
232                }
233            }
234        });
235    }
236}
237
238impl<'buffer> Edit<'buffer> for Editor<'buffer> {
239    fn buffer_ref(&self) -> &BufferRef<'buffer> {
240        &self.buffer_ref
241    }
242
243    fn buffer_ref_mut(&mut self) -> &mut BufferRef<'buffer> {
244        &mut self.buffer_ref
245    }
246
247    fn cursor(&self) -> Cursor {
248        self.cursor
249    }
250
251    fn set_cursor(&mut self, cursor: Cursor) {
252        if self.cursor != cursor {
253            self.cursor = cursor;
254            self.cursor_moved = true;
255            self.with_buffer_mut(|buffer| buffer.set_redraw(true));
256        }
257    }
258
259    fn selection(&self) -> Selection {
260        self.selection
261    }
262
263    fn set_selection(&mut self, selection: Selection) {
264        if self.selection != selection {
265            self.selection = selection;
266            self.with_buffer_mut(|buffer| buffer.set_redraw(true));
267        }
268    }
269
270    fn auto_indent(&self) -> bool {
271        self.auto_indent
272    }
273
274    fn set_auto_indent(&mut self, auto_indent: bool) {
275        self.auto_indent = auto_indent;
276    }
277
278    fn tab_width(&self) -> u16 {
279        self.with_buffer(|buffer| buffer.tab_width())
280    }
281
282    fn set_tab_width(&mut self, font_system: &mut FontSystem, tab_width: u16) {
283        self.with_buffer_mut(|buffer| buffer.set_tab_width(font_system, tab_width));
284    }
285
286    fn shape_as_needed(&mut self, font_system: &mut FontSystem, prune: bool) {
287        if self.cursor_moved {
288            let cursor = self.cursor;
289            self.with_buffer_mut(|buffer| buffer.shape_until_cursor(font_system, cursor, prune));
290            self.cursor_moved = false;
291        } else {
292            self.with_buffer_mut(|buffer| buffer.shape_until_scroll(font_system, prune));
293        }
294    }
295
296    fn delete_range(&mut self, start: Cursor, end: Cursor) {
297        let change_item = self.with_buffer_mut(|buffer| {
298            // Collect removed data for change tracking
299            let mut change_lines = Vec::new();
300
301            // Delete the selection from the last line
302            let end_line_opt = if end.line > start.line {
303                // Get part of line after selection
304                let after = buffer.lines[end.line].split_off(end.index);
305
306                // Remove end line
307                let removed = buffer.lines.remove(end.line);
308                change_lines.insert(0, removed.text().to_string());
309
310                Some(after)
311            } else {
312                None
313            };
314
315            // Delete interior lines (in reverse for safety)
316            for line_i in (start.line + 1..end.line).rev() {
317                let removed = buffer.lines.remove(line_i);
318                change_lines.insert(0, removed.text().to_string());
319            }
320
321            // Delete the selection from the first line
322            {
323                // Get part after selection if start line is also end line
324                let after_opt = if start.line == end.line {
325                    Some(buffer.lines[start.line].split_off(end.index))
326                } else {
327                    None
328                };
329
330                // Delete selected part of line
331                let removed = buffer.lines[start.line].split_off(start.index);
332                change_lines.insert(0, removed.text().to_string());
333
334                // Re-add part of line after selection
335                if let Some(after) = after_opt {
336                    buffer.lines[start.line].append(after);
337                }
338
339                // Re-add valid parts of end line
340                if let Some(end_line) = end_line_opt {
341                    buffer.lines[start.line].append(end_line);
342                }
343            }
344
345            ChangeItem {
346                start,
347                end,
348                text: change_lines.join("\n"),
349                insert: false,
350            }
351        });
352
353        if let Some(ref mut change) = self.change {
354            change.items.push(change_item);
355        }
356    }
357
358    fn insert_at(
359        &mut self,
360        mut cursor: Cursor,
361        data: &str,
362        attrs_list: Option<AttrsList>,
363    ) -> Cursor {
364        let mut remaining_split_len = data.len();
365        if remaining_split_len == 0 {
366            return cursor;
367        }
368
369        let change_item = self.with_buffer_mut(|buffer| {
370            // Save cursor for change tracking
371            let start = cursor;
372
373            // Ensure there are enough lines in the buffer to handle this cursor
374            while cursor.line >= buffer.lines.len() {
375                let ending = buffer
376                    .lines
377                    .last()
378                    .map(|line| line.ending())
379                    .unwrap_or_default();
380                let line = BufferLine::new(
381                    String::new(),
382                    ending,
383                    AttrsList::new(attrs_list.as_ref().map_or_else(
384                        || {
385                            buffer
386                                .lines
387                                .last()
388                                .map_or(Attrs::new(), |line| line.attrs_list().defaults())
389                        },
390                        |x| x.defaults(),
391                    )),
392                    Shaping::Advanced,
393                );
394                buffer.lines.push(line);
395            }
396
397            let line: &mut BufferLine = &mut buffer.lines[cursor.line];
398            let insert_line = cursor.line + 1;
399            let ending = line.ending();
400
401            // Collect text after insertion as a line
402            let after: BufferLine = line.split_off(cursor.index);
403            let after_len = after.text().len();
404
405            // Collect attributes
406            let mut final_attrs = attrs_list.unwrap_or_else(|| {
407                AttrsList::new(line.attrs_list().get_span(cursor.index.saturating_sub(1)))
408            });
409
410            // Append the inserted text, line by line
411            // we want to see a blank entry if the string ends with a newline
412            //TODO: adjust this to get line ending from data?
413            let addendum = once("").filter(|_| data.ends_with('\n'));
414            let mut lines_iter = data.split_inclusive('\n').chain(addendum);
415            if let Some(data_line) = lines_iter.next() {
416                let mut these_attrs = final_attrs.split_off(data_line.len());
417                remaining_split_len -= data_line.len();
418                core::mem::swap(&mut these_attrs, &mut final_attrs);
419                line.append(BufferLine::new(
420                    data_line
421                        .strip_suffix(char::is_control)
422                        .unwrap_or(data_line),
423                    ending,
424                    these_attrs,
425                    Shaping::Advanced,
426                ));
427            } else {
428                panic!("str::lines() did not yield any elements");
429            }
430            if let Some(data_line) = lines_iter.next_back() {
431                remaining_split_len -= data_line.len();
432                let mut tmp = BufferLine::new(
433                    data_line
434                        .strip_suffix(char::is_control)
435                        .unwrap_or(data_line),
436                    ending,
437                    final_attrs.split_off(remaining_split_len),
438                    Shaping::Advanced,
439                );
440                tmp.append(after);
441                buffer.lines.insert(insert_line, tmp);
442                cursor.line += 1;
443            } else {
444                line.append(after);
445            }
446            for data_line in lines_iter.rev() {
447                remaining_split_len -= data_line.len();
448                let tmp = BufferLine::new(
449                    data_line
450                        .strip_suffix(char::is_control)
451                        .unwrap_or(data_line),
452                    ending,
453                    final_attrs.split_off(remaining_split_len),
454                    Shaping::Advanced,
455                );
456                buffer.lines.insert(insert_line, tmp);
457                cursor.line += 1;
458            }
459
460            assert_eq!(remaining_split_len, 0);
461
462            // Append the text after insertion
463            cursor.index = buffer.lines[cursor.line].text().len() - after_len;
464
465            ChangeItem {
466                start,
467                end: cursor,
468                text: data.to_string(),
469                insert: true,
470            }
471        });
472
473        if let Some(ref mut change) = self.change {
474            change.items.push(change_item);
475        }
476
477        cursor
478    }
479
480    fn copy_selection(&self) -> Option<String> {
481        let (start, end) = self.selection_bounds()?;
482        self.with_buffer(|buffer| {
483            let mut selection = String::new();
484            // Take the selection from the first line
485            {
486                // Add selected part of line to string
487                if start.line == end.line {
488                    selection.push_str(&buffer.lines[start.line].text()[start.index..end.index]);
489                } else {
490                    selection.push_str(&buffer.lines[start.line].text()[start.index..]);
491                    selection.push('\n');
492                }
493            }
494
495            // Take the selection from all interior lines (if they exist)
496            for line_i in start.line + 1..end.line {
497                selection.push_str(buffer.lines[line_i].text());
498                selection.push('\n');
499            }
500
501            // Take the selection from the last line
502            if end.line > start.line {
503                // Add selected part of line to string
504                selection.push_str(&buffer.lines[end.line].text()[..end.index]);
505            }
506
507            Some(selection)
508        })
509    }
510
511    fn delete_selection(&mut self) -> bool {
512        let (start, end) = match self.selection_bounds() {
513            Some(some) => some,
514            None => return false,
515        };
516
517        // Reset cursor to start of selection
518        self.cursor = start;
519
520        // Reset selection to None
521        self.selection = Selection::None;
522
523        // Delete from start to end of selection
524        self.delete_range(start, end);
525
526        true
527    }
528
529    fn apply_change(&mut self, change: &Change) -> bool {
530        // Cannot apply changes if there is a pending change
531        if let Some(pending) = self.change.take() {
532            if !pending.items.is_empty() {
533                //TODO: is this a good idea?
534                log::warn!("pending change caused apply_change to be ignored!");
535                self.change = Some(pending);
536                return false;
537            }
538        }
539
540        for item in change.items.iter() {
541            //TODO: edit cursor if needed?
542            if item.insert {
543                self.cursor = self.insert_at(item.start, &item.text, None);
544            } else {
545                self.cursor = item.start;
546                self.delete_range(item.start, item.end);
547            }
548        }
549        true
550    }
551
552    fn start_change(&mut self) {
553        if self.change.is_none() {
554            self.change = Some(Change::default());
555        }
556    }
557
558    fn finish_change(&mut self) -> Option<Change> {
559        self.change.take()
560    }
561
562    fn action(&mut self, font_system: &mut FontSystem, action: Action) {
563        let old_cursor = self.cursor;
564
565        match action {
566            Action::Motion(motion) => {
567                let cursor = self.cursor;
568                let cursor_x_opt = self.cursor_x_opt;
569                if let Some((new_cursor, new_cursor_x_opt)) = self.with_buffer_mut(|buffer| {
570                    buffer.cursor_motion(font_system, cursor, cursor_x_opt, motion)
571                }) {
572                    self.cursor = new_cursor;
573                    self.cursor_x_opt = new_cursor_x_opt;
574                }
575            }
576            Action::Escape => {
577                match self.selection {
578                    Selection::None => {}
579                    _ => self.with_buffer_mut(|buffer| buffer.set_redraw(true)),
580                }
581                self.selection = Selection::None;
582            }
583            Action::Insert(character) => {
584                if character.is_control() && !['\t', '\n', '\u{92}'].contains(&character) {
585                    // Filter out special chars (except for tab), use Action instead
586                    log::debug!("Refusing to insert control character {:?}", character);
587                } else if character == '\n' {
588                    self.action(font_system, Action::Enter);
589                } else {
590                    let mut str_buf = [0u8; 8];
591                    let str_ref = character.encode_utf8(&mut str_buf);
592                    self.insert_string(str_ref, None);
593                }
594            }
595            Action::Enter => {
596                //TODO: what about indenting more after opening brackets or parentheses?
597                if self.auto_indent {
598                    let mut string = String::from("\n");
599                    self.with_buffer(|buffer| {
600                        let line = &buffer.lines[self.cursor.line];
601                        let text = line.text();
602                        for c in text.chars() {
603                            if c.is_whitespace() {
604                                string.push(c);
605                            } else {
606                                break;
607                            }
608                        }
609                    });
610                    self.insert_string(&string, None);
611                } else {
612                    self.insert_string("\n", None);
613                }
614
615                // Ensure line is properly shaped and laid out (for potential immediate commands)
616                let line_i = self.cursor.line;
617                self.with_buffer_mut(|buffer| {
618                    buffer.line_layout(font_system, line_i);
619                });
620            }
621            Action::Backspace => {
622                if self.delete_selection() {
623                    // Deleted selection
624                } else {
625                    // Save current cursor as end
626                    let end = self.cursor;
627
628                    if self.cursor.index > 0 {
629                        // Move cursor to previous character index
630                        self.cursor.index = self.with_buffer(|buffer| {
631                            buffer.lines[self.cursor.line].text()[..self.cursor.index]
632                                .char_indices()
633                                .next_back()
634                                .map_or(0, |(i, _)| i)
635                        });
636                    } else if self.cursor.line > 0 {
637                        // Move cursor to previous line
638                        self.cursor.line -= 1;
639                        self.cursor.index =
640                            self.with_buffer(|buffer| buffer.lines[self.cursor.line].text().len());
641                    }
642
643                    if self.cursor != end {
644                        // Delete range
645                        self.delete_range(self.cursor, end);
646                    }
647                }
648            }
649            Action::Delete => {
650                if self.delete_selection() {
651                    // Deleted selection
652                } else {
653                    // Save current cursor as start and end
654                    let mut start = self.cursor;
655                    let mut end = self.cursor;
656
657                    self.with_buffer(|buffer| {
658                        if start.index < buffer.lines[start.line].text().len() {
659                            let line = &buffer.lines[start.line];
660
661                            let range_opt = line
662                                .text()
663                                .grapheme_indices(true)
664                                .take_while(|(i, _)| *i <= start.index)
665                                .last()
666                                .map(|(i, c)| i..(i + c.len()));
667
668                            if let Some(range) = range_opt {
669                                start.index = range.start;
670                                end.index = range.end;
671                            }
672                        } else if start.line + 1 < buffer.lines.len() {
673                            end.line += 1;
674                            end.index = 0;
675                        }
676                    });
677
678                    if start != end {
679                        self.cursor = start;
680                        self.delete_range(start, end);
681                    }
682                }
683            }
684            Action::Indent => {
685                // Get start and end of selection
686                let (start, end) = match self.selection_bounds() {
687                    Some(some) => some,
688                    None => (self.cursor, self.cursor),
689                };
690
691                // For every line in selection
692                let tab_width: usize = self.tab_width().into();
693                for line_i in start.line..=end.line {
694                    // Determine indexes of last indent and first character after whitespace
695                    let mut after_whitespace = 0;
696                    let mut required_indent = 0;
697                    self.with_buffer(|buffer| {
698                        let line = &buffer.lines[line_i];
699                        let text = line.text();
700                        // Default to end of line if no non-whitespace found
701                        after_whitespace = text.len();
702                        for (count, (index, c)) in text.char_indices().enumerate() {
703                            if !c.is_whitespace() {
704                                after_whitespace = index;
705                                required_indent = tab_width - (count % tab_width);
706                                break;
707                            }
708                        }
709                    });
710
711                    // No indent required (not possible?)
712                    if required_indent == 0 {
713                        required_indent = tab_width;
714                    }
715
716                    self.insert_at(
717                        Cursor::new(line_i, after_whitespace),
718                        &" ".repeat(required_indent),
719                        None,
720                    );
721
722                    // Adjust cursor
723                    if self.cursor.line == line_i {
724                        //TODO: should we be forcing cursor index to current indent location?
725                        if self.cursor.index < after_whitespace {
726                            self.cursor.index = after_whitespace;
727                        }
728                        self.cursor.index += required_indent;
729                    }
730
731                    // Adjust selection
732                    match self.selection {
733                        Selection::None => {}
734                        Selection::Normal(ref mut select)
735                        | Selection::Line(ref mut select)
736                        | Selection::Word(ref mut select) => {
737                            if select.line == line_i && select.index >= after_whitespace {
738                                select.index += required_indent;
739                            }
740                        }
741                    }
742
743                    // Request redraw
744                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
745                }
746            }
747            Action::Unindent => {
748                // Get start and end of selection
749                let (start, end) = match self.selection_bounds() {
750                    Some(some) => some,
751                    None => (self.cursor, self.cursor),
752                };
753
754                // For every line in selection
755                let tab_width: usize = self.tab_width().into();
756                for line_i in start.line..=end.line {
757                    // Determine indexes of last indent and first character after whitespace
758                    let mut last_indent = 0;
759                    let mut after_whitespace = 0;
760                    self.with_buffer(|buffer| {
761                        let line = &buffer.lines[line_i];
762                        let text = line.text();
763                        // Default to end of line if no non-whitespace found
764                        after_whitespace = text.len();
765                        for (count, (index, c)) in text.char_indices().enumerate() {
766                            if !c.is_whitespace() {
767                                after_whitespace = index;
768                                break;
769                            }
770                            if count % tab_width == 0 {
771                                last_indent = index;
772                            }
773                        }
774                    });
775
776                    // No de-indent required
777                    if last_indent == after_whitespace {
778                        continue;
779                    }
780
781                    // Delete one indent
782                    self.delete_range(
783                        Cursor::new(line_i, last_indent),
784                        Cursor::new(line_i, after_whitespace),
785                    );
786
787                    // Adjust cursor
788                    if self.cursor.line == line_i && self.cursor.index > last_indent {
789                        self.cursor.index -= after_whitespace - last_indent;
790                    }
791
792                    // Adjust selection
793                    match self.selection {
794                        Selection::None => {}
795                        Selection::Normal(ref mut select)
796                        | Selection::Line(ref mut select)
797                        | Selection::Word(ref mut select) => {
798                            if select.line == line_i && select.index > last_indent {
799                                select.index -= after_whitespace - last_indent;
800                            }
801                        }
802                    }
803
804                    // Request redraw
805                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
806                }
807            }
808            Action::Click { x, y } => {
809                self.set_selection(Selection::None);
810
811                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
812                {
813                    if new_cursor != self.cursor {
814                        self.cursor = new_cursor;
815                        self.with_buffer_mut(|buffer| buffer.set_redraw(true));
816                    }
817                }
818            }
819            Action::DoubleClick { x, y } => {
820                self.set_selection(Selection::None);
821
822                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
823                {
824                    if new_cursor != self.cursor {
825                        self.cursor = new_cursor;
826                        self.with_buffer_mut(|buffer| buffer.set_redraw(true));
827                    }
828                    self.selection = Selection::Word(self.cursor);
829                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
830                }
831            }
832            Action::TripleClick { x, y } => {
833                self.set_selection(Selection::None);
834
835                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
836                {
837                    if new_cursor != self.cursor {
838                        self.cursor = new_cursor;
839                    }
840                    self.selection = Selection::Line(self.cursor);
841                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
842                }
843            }
844            Action::Drag { x, y } => {
845                if self.selection == Selection::None {
846                    self.selection = Selection::Normal(self.cursor);
847                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
848                }
849
850                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
851                {
852                    if new_cursor != self.cursor {
853                        self.cursor = new_cursor;
854                        self.with_buffer_mut(|buffer| buffer.set_redraw(true));
855                    }
856                }
857            }
858            Action::Scroll { lines } => {
859                self.with_buffer_mut(|buffer| {
860                    let mut scroll = buffer.scroll();
861                    //TODO: align to layout lines
862                    scroll.vertical += lines as f32 * buffer.metrics().line_height;
863                    buffer.set_scroll(scroll);
864                });
865            }
866        }
867
868        if old_cursor != self.cursor {
869            self.cursor_moved = true;
870            self.with_buffer_mut(|buffer| buffer.set_redraw(true));
871
872            /*TODO
873            if let Some(glyph) = run.glyphs.get(new_cursor_glyph) {
874                let font_opt = self.buffer.font_system().get_font(glyph.cache_key.font_id);
875                let text_glyph = &run.text[glyph.start..glyph.end];
876                log::debug!(
877                    "{}, {}: '{}' ('{}'): '{}' ({:?})",
878                    self.cursor.line,
879                    self.cursor.index,
880                    font_opt.as_ref().map_or("?", |font| font.info.family.as_str()),
881                    font_opt.as_ref().map_or("?", |font| font.info.post_script_name.as_str()),
882                    text_glyph,
883                    text_glyph
884                );
885            }
886            */
887        }
888    }
889
890    fn cursor_position(&self) -> Option<(i32, i32)> {
891        self.with_buffer(|buffer| {
892            buffer
893                .layout_runs()
894                .find_map(|run| cursor_position(&self.cursor, &run))
895        })
896    }
897}
898
899impl BorrowedWithFontSystem<'_, Editor<'_>> {
900    #[cfg(feature = "swash")]
901    pub fn draw<F>(
902        &mut self,
903        cache: &mut crate::SwashCache,
904        text_color: Color,
905        cursor_color: Color,
906        selection_color: Color,
907        selected_text_color: Color,
908        f: F,
909    ) where
910        F: FnMut(i32, i32, u32, u32, Color),
911    {
912        self.inner.draw(
913            self.font_system,
914            cache,
915            text_color,
916            cursor_color,
917            selection_color,
918            selected_text_color,
919            f,
920        );
921    }
922}