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