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