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                    if end_line.ending() == LineEnding::None {
339                        end_line.set_ending(line.ending());
340                    }
341                    line.append(&end_line);
342                }
343            }
344
345            let mut text = String::new();
346            let mut last_ending: Option<LineEnding> = None;
347            for line in change_lines {
348                if let Some(ending) = last_ending {
349                    text.push_str(ending.as_str());
350                }
351                text.push_str(line.text());
352                last_ending = Some(line.ending());
353            }
354
355            ChangeItem {
356                start,
357                end,
358                text,
359                insert: false,
360            }
361        });
362
363        if let Some(ref mut change) = self.change {
364            change.items.push(change_item);
365        }
366    }
367
368    fn insert_at(
369        &mut self,
370        mut cursor: Cursor,
371        data: &str,
372        attrs_list: Option<AttrsList>,
373    ) -> Cursor {
374        let mut remaining_split_len = data.len();
375        if remaining_split_len == 0 {
376            return cursor;
377        }
378
379        let change_item = self.with_buffer_mut(|buffer| {
380            // Save cursor for change tracking
381            let start = cursor;
382
383            // Ensure there are enough lines in the buffer to handle this cursor
384            while cursor.line >= buffer.lines.len() {
385                // Get last line ending
386                let mut last_ending = LineEnding::None;
387                if let Some(last_line) = buffer.lines.last_mut() {
388                    last_ending = last_line.ending();
389                    // Ensure a valid line ending is always set on interior lines
390                    if last_ending == LineEnding::None {
391                        last_line.set_ending(LineEnding::default());
392                    }
393                }
394                let line = BufferLine::new(
395                    String::new(),
396                    last_ending,
397                    AttrsList::new(&attrs_list.as_ref().map_or_else(
398                        || {
399                            buffer
400                                .lines
401                                .last()
402                                .map_or_else(Attrs::new, |line| line.attrs_list().defaults())
403                        },
404                        |x| x.defaults(),
405                    )),
406                    Shaping::Advanced,
407                );
408                buffer.lines.push(line);
409            }
410
411            let line: &mut BufferLine = &mut buffer.lines[cursor.line];
412            let insert_line = cursor.line + 1;
413
414            // Collect text after insertion as a line
415            let after: BufferLine = line.split_off(cursor.index);
416            let after_len = after.text().len();
417
418            // Collect attributes
419            let mut final_attrs = attrs_list.unwrap_or_else(|| {
420                AttrsList::new(&line.attrs_list().get_span(cursor.index.saturating_sub(1)))
421            });
422
423            // Append the inserted text, line by line
424            let mut lines: Vec<_> = LineIter::new(data).collect();
425            // Ensure there is always an ending line with no line ending
426            if lines.last().map(|line| line.1).unwrap_or(LineEnding::None) != LineEnding::None {
427                lines.push((Default::default(), LineEnding::None));
428            }
429            let mut lines_iter = lines.into_iter();
430
431            // Add first line
432            if let Some((range, ending)) = lines_iter.next() {
433                let data_line = &data[range];
434                let mut these_attrs = final_attrs.split_off(data_line.len());
435                remaining_split_len -= data_line.len() + ending.as_str().len();
436                core::mem::swap(&mut these_attrs, &mut final_attrs);
437                line.append(&BufferLine::new(
438                    data_line,
439                    ending,
440                    these_attrs,
441                    Shaping::Advanced,
442                ));
443            }
444            // Add last line
445            if let Some((range, ending)) = lines_iter.next_back() {
446                let data_line = &data[range];
447                remaining_split_len -= data_line.len() + ending.as_str().len();
448                let mut tmp = BufferLine::new(
449                    data_line,
450                    ending,
451                    final_attrs.split_off(remaining_split_len),
452                    Shaping::Advanced,
453                );
454                tmp.append(&after);
455                buffer.lines.insert(insert_line, tmp);
456                cursor.line += 1;
457            } else {
458                line.append(&after);
459            }
460            // Add middle lines
461            for (range, ending) in lines_iter.rev() {
462                let data_line = &data[range];
463                remaining_split_len -= data_line.len() + ending.as_str().len();
464                let tmp = BufferLine::new(
465                    data_line,
466                    ending,
467                    final_attrs.split_off(remaining_split_len),
468                    Shaping::Advanced,
469                );
470                buffer.lines.insert(insert_line, tmp);
471                cursor.line += 1;
472            }
473
474            assert_eq!(remaining_split_len, 0);
475
476            // Append the text after insertion
477            cursor.index = buffer.lines[cursor.line].text().len() - after_len;
478
479            ChangeItem {
480                start,
481                end: cursor,
482                text: data.to_string(),
483                insert: true,
484            }
485        });
486
487        if let Some(ref mut change) = self.change {
488            change.items.push(change_item);
489        }
490
491        cursor
492    }
493
494    fn copy_selection(&self) -> Option<String> {
495        let (start, end) = self.selection_bounds()?;
496        self.with_buffer(|buffer| {
497            let mut selection = String::new();
498            // Take the selection from the first line
499            {
500                // Add selected part of line to string
501                if start.line == end.line {
502                    selection.push_str(&buffer.lines[start.line].text()[start.index..end.index]);
503                } else {
504                    selection.push_str(&buffer.lines[start.line].text()[start.index..]);
505                    selection.push('\n');
506                }
507            }
508
509            // Take the selection from all interior lines (if they exist)
510            for line_i in start.line + 1..end.line {
511                selection.push_str(buffer.lines[line_i].text());
512                selection.push('\n');
513            }
514
515            // Take the selection from the last line
516            if end.line > start.line {
517                // Add selected part of line to string
518                selection.push_str(&buffer.lines[end.line].text()[..end.index]);
519            }
520
521            Some(selection)
522        })
523    }
524
525    fn delete_selection(&mut self) -> bool {
526        let Some((start, end)) = self.selection_bounds() else {
527            return false;
528        };
529
530        // Reset cursor to start of selection
531        self.cursor = start;
532
533        // Reset selection to None
534        self.selection = Selection::None;
535
536        // Delete from start to end of selection
537        self.delete_range(start, end);
538
539        true
540    }
541
542    fn apply_change(&mut self, change: &Change) -> bool {
543        // Cannot apply changes if there is a pending change
544        if let Some(pending) = self.change.take() {
545            if !pending.items.is_empty() {
546                //TODO: is this a good idea?
547                log::warn!("pending change caused apply_change to be ignored!");
548                self.change = Some(pending);
549                return false;
550            }
551        }
552
553        for item in &change.items {
554            //TODO: edit cursor if needed?
555            if item.insert {
556                self.cursor = self.insert_at(item.start, &item.text, None);
557            } else {
558                self.cursor = item.start;
559                self.delete_range(item.start, item.end);
560            }
561        }
562        true
563    }
564
565    fn start_change(&mut self) {
566        if self.change.is_none() {
567            self.change = Some(Change::default());
568        }
569    }
570
571    fn finish_change(&mut self) -> Option<Change> {
572        self.change.take()
573    }
574
575    fn action(&mut self, font_system: &mut FontSystem, action: Action) {
576        let old_cursor = self.cursor;
577
578        match action {
579            Action::Motion(motion) => {
580                let cursor = self.cursor;
581                let cursor_x_opt = self.cursor_x_opt;
582                if let Some((new_cursor, new_cursor_x_opt)) = self.with_buffer_mut(|buffer| {
583                    buffer.cursor_motion(font_system, cursor, cursor_x_opt, motion)
584                }) {
585                    self.cursor = new_cursor;
586                    self.cursor_x_opt = new_cursor_x_opt;
587                }
588            }
589            Action::Escape => {
590                match self.selection {
591                    Selection::None => {}
592                    _ => self.with_buffer_mut(|buffer| buffer.set_redraw(true)),
593                }
594                self.selection = Selection::None;
595            }
596            Action::Insert(character) => {
597                if character.is_control() && !['\t', '\n', '\u{92}'].contains(&character) {
598                    // Filter out special chars (except for tab), use Action instead
599                    log::debug!("Refusing to insert control character {character:?}");
600                } else if character == '\n' {
601                    self.action(font_system, Action::Enter);
602                } else {
603                    let mut str_buf = [0u8; 8];
604                    let str_ref = character.encode_utf8(&mut str_buf);
605                    self.insert_string(str_ref, None);
606                }
607            }
608            Action::Enter => {
609                //TODO: what about indenting more after opening brackets or parentheses?
610                if self.auto_indent {
611                    let mut string = String::from("\n");
612                    self.with_buffer(|buffer| {
613                        let line = &buffer.lines[self.cursor.line];
614                        let text = line.text();
615                        for c in text.chars() {
616                            if c.is_whitespace() {
617                                string.push(c);
618                            } else {
619                                break;
620                            }
621                        }
622                    });
623                    self.insert_string(&string, None);
624                } else {
625                    self.insert_string("\n", None);
626                }
627
628                // Ensure line is properly shaped and laid out (for potential immediate commands)
629                let line_i = self.cursor.line;
630                self.with_buffer_mut(|buffer| {
631                    buffer.line_layout(font_system, line_i);
632                });
633            }
634            Action::Backspace => {
635                if self.delete_selection() {
636                    // Deleted selection
637                } else {
638                    // Save current cursor as end
639                    let end = self.cursor;
640
641                    if self.cursor.index > 0 {
642                        // Move cursor to previous character index
643                        self.cursor.index = self.with_buffer(|buffer| {
644                            buffer.lines[self.cursor.line].text()[..self.cursor.index]
645                                .char_indices()
646                                .next_back()
647                                .map_or(0, |(i, _)| i)
648                        });
649                    } else if self.cursor.line > 0 {
650                        // Move cursor to previous line
651                        self.cursor.line -= 1;
652                        self.cursor.index =
653                            self.with_buffer(|buffer| buffer.lines[self.cursor.line].text().len());
654                    }
655
656                    if self.cursor != end {
657                        // Delete range
658                        self.delete_range(self.cursor, end);
659                    }
660                }
661            }
662            Action::Delete => {
663                if self.delete_selection() {
664                    // Deleted selection
665                } else {
666                    // Save current cursor as start and end
667                    let mut start = self.cursor;
668                    let mut end = self.cursor;
669
670                    self.with_buffer(|buffer| {
671                        if start.index < buffer.lines[start.line].text().len() {
672                            let line = &buffer.lines[start.line];
673
674                            let range_opt = line
675                                .text()
676                                .grapheme_indices(true)
677                                .take_while(|(i, _)| *i <= start.index)
678                                .last()
679                                .map(|(i, c)| i..(i + c.len()));
680
681                            if let Some(range) = range_opt {
682                                start.index = range.start;
683                                end.index = range.end;
684                            }
685                        } else if start.line + 1 < buffer.lines.len() {
686                            end.line += 1;
687                            end.index = 0;
688                        }
689                    });
690
691                    if start != end {
692                        self.cursor = start;
693                        self.delete_range(start, end);
694                    }
695                }
696            }
697            Action::Indent => {
698                // Get start and end of selection
699                let (start, end) = match self.selection_bounds() {
700                    Some(some) => some,
701                    None => (self.cursor, self.cursor),
702                };
703
704                // For every line in selection
705                let tab_width: usize = self.tab_width().into();
706                for line_i in start.line..=end.line {
707                    // Determine indexes of last indent and first character after whitespace
708                    let mut after_whitespace = 0;
709                    let mut required_indent = 0;
710                    self.with_buffer(|buffer| {
711                        let line = &buffer.lines[line_i];
712                        let text = line.text();
713
714                        if self.selection == Selection::None {
715                            //Selection::None counts whitespace from the cursor backwards
716                            let whitespace_length = match line.text()[0..self.cursor.index]
717                                .chars()
718                                .rev()
719                                .position(|c| !c.is_whitespace())
720                            {
721                                Some(length) => length,
722                                // The whole line is whitespace
723                                None => self.cursor.index,
724                            };
725                            required_indent = tab_width - (whitespace_length % tab_width);
726                            after_whitespace = self.cursor.index;
727                        } else {
728                            // Other selections count whitespace from  the start of the line
729                            for (count, (index, c)) in text.char_indices().enumerate() {
730                                if !c.is_whitespace() {
731                                    after_whitespace = index;
732                                    required_indent = tab_width - (count % tab_width);
733                                    break;
734                                }
735                            }
736                        }
737                    });
738
739                    self.insert_at(
740                        Cursor::new(line_i, after_whitespace),
741                        &" ".repeat(required_indent),
742                        None,
743                    );
744
745                    // Adjust cursor
746                    if self.cursor.line == line_i {
747                        //TODO: should we be forcing cursor index to current indent location?
748                        if self.cursor.index < after_whitespace {
749                            self.cursor.index = after_whitespace;
750                        }
751                        self.cursor.index += required_indent;
752                    }
753
754                    // Adjust selection
755                    match self.selection {
756                        Selection::None => {}
757                        Selection::Normal(ref mut select)
758                        | Selection::Line(ref mut select)
759                        | Selection::Word(ref mut select) => {
760                            if select.line == line_i && select.index >= after_whitespace {
761                                select.index += required_indent;
762                            }
763                        }
764                    }
765                    // Request redraw
766                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
767                }
768            }
769            Action::Unindent => {
770                // Get start and end of selection
771                let (start, end) = match self.selection_bounds() {
772                    Some(some) => some,
773                    None => (self.cursor, self.cursor),
774                };
775
776                // For every line in selection
777                let tab_width: usize = self.tab_width().into();
778                for line_i in start.line..=end.line {
779                    // Determine indexes of last indent and first character after whitespace
780                    let mut last_indent = 0;
781                    let mut after_whitespace = 0;
782                    self.with_buffer(|buffer| {
783                        let line = &buffer.lines[line_i];
784                        let text = line.text();
785                        // Default to end of line if no non-whitespace found
786                        after_whitespace = text.len();
787                        for (count, (index, c)) in text.char_indices().enumerate() {
788                            if !c.is_whitespace() {
789                                after_whitespace = index;
790                                break;
791                            }
792                            if count % tab_width == 0 {
793                                last_indent = index;
794                            }
795                        }
796                    });
797
798                    // No de-indent required
799                    if last_indent == after_whitespace {
800                        continue;
801                    }
802
803                    // Delete one indent
804                    self.delete_range(
805                        Cursor::new(line_i, last_indent),
806                        Cursor::new(line_i, after_whitespace),
807                    );
808
809                    // Adjust cursor
810                    if self.cursor.line == line_i && self.cursor.index > last_indent {
811                        self.cursor.index -= after_whitespace - last_indent;
812                    }
813
814                    // Adjust selection
815                    match self.selection {
816                        Selection::None => {}
817                        Selection::Normal(ref mut select)
818                        | Selection::Line(ref mut select)
819                        | Selection::Word(ref mut select) => {
820                            if select.line == line_i && select.index > last_indent {
821                                select.index -= after_whitespace - last_indent;
822                            }
823                        }
824                    }
825
826                    // Request redraw
827                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
828                }
829            }
830            Action::Click { x, y } => {
831                self.set_selection(Selection::None);
832
833                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
834                {
835                    if new_cursor != self.cursor {
836                        self.cursor = new_cursor;
837                        self.with_buffer_mut(|buffer| buffer.set_redraw(true));
838                    }
839                }
840            }
841            Action::DoubleClick { x, y } => {
842                self.set_selection(Selection::None);
843
844                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
845                {
846                    if new_cursor != self.cursor {
847                        self.cursor = new_cursor;
848                        self.with_buffer_mut(|buffer| buffer.set_redraw(true));
849                    }
850                    self.selection = Selection::Word(self.cursor);
851                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
852                }
853            }
854            Action::TripleClick { x, y } => {
855                self.set_selection(Selection::None);
856
857                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
858                {
859                    if new_cursor != self.cursor {
860                        self.cursor = new_cursor;
861                    }
862                    self.selection = Selection::Line(self.cursor);
863                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
864                }
865            }
866            Action::Drag { x, y } => {
867                if self.selection == Selection::None {
868                    self.selection = Selection::Normal(self.cursor);
869                    self.with_buffer_mut(|buffer| buffer.set_redraw(true));
870                }
871
872                if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
873                {
874                    if new_cursor != self.cursor {
875                        self.cursor = new_cursor;
876                        self.with_buffer_mut(|buffer| buffer.set_redraw(true));
877                    }
878                }
879            }
880            Action::Scroll { pixels } => {
881                self.with_buffer_mut(|buffer| {
882                    let mut scroll = buffer.scroll();
883                    //TODO: align to layout lines
884                    scroll.vertical += pixels;
885                    buffer.set_scroll(scroll);
886                });
887            }
888        }
889
890        if old_cursor != self.cursor {
891            self.cursor_moved = true;
892            self.with_buffer_mut(|buffer| buffer.set_redraw(true));
893
894            /*TODO
895            if let Some(glyph) = run.glyphs.get(new_cursor_glyph) {
896                let font_opt = self.buffer.font_system().get_font(glyph.cache_key.font_id);
897                let text_glyph = &run.text[glyph.start..glyph.end];
898                log::debug!(
899                    "{}, {}: '{}' ('{}'): '{}' ({:?})",
900                    self.cursor.line,
901                    self.cursor.index,
902                    font_opt.as_ref().map_or("?", |font| font.info.family.as_str()),
903                    font_opt.as_ref().map_or("?", |font| font.info.post_script_name.as_str()),
904                    text_glyph,
905                    text_glyph
906                );
907            }
908            */
909        }
910    }
911
912    fn cursor_position(&self) -> Option<(i32, i32)> {
913        self.with_buffer(|buffer| {
914            buffer
915                .layout_runs()
916                .find_map(|run| cursor_position(&self.cursor, &run))
917        })
918    }
919}
920
921impl BorrowedWithFontSystem<'_, Editor<'_>> {
922    #[cfg(feature = "swash")]
923    pub fn draw<F>(
924        &mut self,
925        cache: &mut crate::SwashCache,
926        text_color: Color,
927        cursor_color: Color,
928        selection_color: Color,
929        selected_text_color: Color,
930        f: F,
931    ) where
932        F: FnMut(i32, i32, u32, u32, Color),
933    {
934        self.inner.draw(
935            self.font_system,
936            cache,
937            text_color,
938            cursor_color,
939            selection_color,
940            selected_text_color,
941            f,
942        );
943    }
944}