cosmic_text/edit/
editor.rs

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