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