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