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