1#[cfg(not(feature = "std"))]
4use alloc::{
5 string::{String, ToString},
6 vec::Vec,
7};
8use core::{cmp, iter::once};
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, Selection, Shaping,
16};
17
18#[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 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 = match run.glyphs.get(cursor_glyph) {
69 Some(glyph) => {
70 if glyph.level.is_rtl() {
72 (glyph.x + glyph.w - cursor_glyph_offset) as i32
73 } else {
74 (glyph.x + cursor_glyph_offset) as i32
75 }
76 }
77 None => match run.glyphs.last() {
78 Some(glyph) => {
79 if glyph.level.is_rtl() {
81 glyph.x as i32
82 } else {
83 (glyph.x + glyph.w) as i32
84 }
85 }
86 None => {
87 0
89 }
90 },
91 };
92
93 Some((x, run.line_top as i32))
94}
95
96impl<'buffer> Editor<'buffer> {
97 pub fn new(buffer: impl Into<BufferRef<'buffer>>) -> Self {
99 Self {
100 buffer_ref: buffer.into(),
101 cursor: Cursor::default(),
102 cursor_x_opt: None,
103 selection: Selection::None,
104 cursor_moved: false,
105 auto_indent: false,
106 change: None,
107 }
108 }
109
110 #[cfg(feature = "swash")]
112 #[allow(clippy::too_many_arguments)]
113 pub fn draw<F>(
114 &self,
115 font_system: &mut FontSystem,
116 cache: &mut crate::SwashCache,
117 text_color: Color,
118 cursor_color: Color,
119 selection_color: Color,
120 selected_text_color: Color,
121 mut f: F,
122 ) where
123 F: FnMut(i32, i32, u32, u32, Color),
124 {
125 let selection_bounds = self.selection_bounds();
126 self.with_buffer(|buffer| {
127 for run in buffer.layout_runs() {
128 let line_i = run.line_i;
129 let line_y = run.line_y;
130 let line_top = run.line_top;
131 let line_height = run.line_height;
132
133 if let Some((start, end)) = selection_bounds {
135 if line_i >= start.line && line_i <= end.line {
136 let mut range_opt = None;
137 for glyph in run.glyphs.iter() {
138 let cluster = &run.text[glyph.start..glyph.end];
140 let total = cluster.grapheme_indices(true).count();
141 let mut c_x = glyph.x;
142 let c_w = glyph.w / total as f32;
143 for (i, c) in cluster.grapheme_indices(true) {
144 let c_start = glyph.start + i;
145 let c_end = glyph.start + i + c.len();
146 if (start.line != line_i || c_end > start.index)
147 && (end.line != line_i || c_start < end.index)
148 {
149 range_opt = match range_opt.take() {
150 Some((min, max)) => Some((
151 cmp::min(min, c_x as i32),
152 cmp::max(max, (c_x + c_w) as i32),
153 )),
154 None => Some((c_x as i32, (c_x + c_w) as i32)),
155 };
156 } else if let Some((min, max)) = range_opt.take() {
157 f(
158 min,
159 line_top as i32,
160 cmp::max(0, max - min) as u32,
161 line_height as u32,
162 selection_color,
163 );
164 }
165 c_x += c_w;
166 }
167 }
168
169 if run.glyphs.is_empty() && end.line > line_i {
170 range_opt = Some((0, buffer.size().0.unwrap_or(0.0) as i32));
172 }
173
174 if let Some((mut min, mut max)) = range_opt.take() {
175 if end.line > line_i {
176 if run.rtl {
178 min = 0;
179 } else {
180 max = buffer.size().0.unwrap_or(0.0) as i32;
181 }
182 }
183 f(
184 min,
185 line_top as i32,
186 cmp::max(0, max - min) as u32,
187 line_height as u32,
188 selection_color,
189 );
190 }
191 }
192 }
193
194 if let Some((x, y)) = cursor_position(&self.cursor, &run) {
196 f(x, y, 1, line_height as u32, cursor_color);
197 }
198
199 for glyph in run.glyphs.iter() {
200 let physical_glyph = glyph.physical((0., 0.), 1.0);
201
202 let mut glyph_color = match glyph.color_opt {
203 Some(some) => some,
204 None => text_color,
205 };
206 if text_color != selected_text_color {
207 if let Some((start, end)) = selection_bounds {
208 if line_i >= start.line
209 && line_i <= end.line
210 && (start.line != line_i || glyph.end > start.index)
211 && (end.line != line_i || glyph.start < end.index)
212 {
213 glyph_color = selected_text_color;
214 }
215 }
216 }
217
218 cache.with_pixels(
219 font_system,
220 physical_glyph.cache_key,
221 glyph_color,
222 |x, y, color| {
223 f(
224 physical_glyph.x + x,
225 line_y as i32 + physical_glyph.y + y,
226 1,
227 1,
228 color,
229 );
230 },
231 );
232 }
233 }
234 });
235 }
236}
237
238impl<'buffer> Edit<'buffer> for Editor<'buffer> {
239 fn buffer_ref(&self) -> &BufferRef<'buffer> {
240 &self.buffer_ref
241 }
242
243 fn buffer_ref_mut(&mut self) -> &mut BufferRef<'buffer> {
244 &mut self.buffer_ref
245 }
246
247 fn cursor(&self) -> Cursor {
248 self.cursor
249 }
250
251 fn set_cursor(&mut self, cursor: Cursor) {
252 if self.cursor != cursor {
253 self.cursor = cursor;
254 self.cursor_moved = true;
255 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
256 }
257 }
258
259 fn selection(&self) -> Selection {
260 self.selection
261 }
262
263 fn set_selection(&mut self, selection: Selection) {
264 if self.selection != selection {
265 self.selection = selection;
266 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
267 }
268 }
269
270 fn auto_indent(&self) -> bool {
271 self.auto_indent
272 }
273
274 fn set_auto_indent(&mut self, auto_indent: bool) {
275 self.auto_indent = auto_indent;
276 }
277
278 fn tab_width(&self) -> u16 {
279 self.with_buffer(|buffer| buffer.tab_width())
280 }
281
282 fn set_tab_width(&mut self, font_system: &mut FontSystem, tab_width: u16) {
283 self.with_buffer_mut(|buffer| buffer.set_tab_width(font_system, tab_width));
284 }
285
286 fn shape_as_needed(&mut self, font_system: &mut FontSystem, prune: bool) {
287 if self.cursor_moved {
288 let cursor = self.cursor;
289 self.with_buffer_mut(|buffer| buffer.shape_until_cursor(font_system, cursor, prune));
290 self.cursor_moved = false;
291 } else {
292 self.with_buffer_mut(|buffer| buffer.shape_until_scroll(font_system, prune));
293 }
294 }
295
296 fn delete_range(&mut self, start: Cursor, end: Cursor) {
297 let change_item = self.with_buffer_mut(|buffer| {
298 let mut change_lines = Vec::new();
300
301 let end_line_opt = if end.line > start.line {
303 let after = buffer.lines[end.line].split_off(end.index);
305
306 let removed = buffer.lines.remove(end.line);
308 change_lines.insert(0, removed.text().to_string());
309
310 Some(after)
311 } else {
312 None
313 };
314
315 for line_i in (start.line + 1..end.line).rev() {
317 let removed = buffer.lines.remove(line_i);
318 change_lines.insert(0, removed.text().to_string());
319 }
320
321 {
323 let after_opt = if start.line == end.line {
325 Some(buffer.lines[start.line].split_off(end.index))
326 } else {
327 None
328 };
329
330 let removed = buffer.lines[start.line].split_off(start.index);
332 change_lines.insert(0, removed.text().to_string());
333
334 if let Some(after) = after_opt {
336 buffer.lines[start.line].append(after);
337 }
338
339 if let Some(end_line) = end_line_opt {
341 buffer.lines[start.line].append(end_line);
342 }
343 }
344
345 ChangeItem {
346 start,
347 end,
348 text: change_lines.join("\n"),
349 insert: false,
350 }
351 });
352
353 if let Some(ref mut change) = self.change {
354 change.items.push(change_item);
355 }
356 }
357
358 fn insert_at(
359 &mut self,
360 mut cursor: Cursor,
361 data: &str,
362 attrs_list: Option<AttrsList>,
363 ) -> Cursor {
364 let mut remaining_split_len = data.len();
365 if remaining_split_len == 0 {
366 return cursor;
367 }
368
369 let change_item = self.with_buffer_mut(|buffer| {
370 let start = cursor;
372
373 while cursor.line >= buffer.lines.len() {
375 let ending = buffer
376 .lines
377 .last()
378 .map(|line| line.ending())
379 .unwrap_or_default();
380 let line = BufferLine::new(
381 String::new(),
382 ending,
383 AttrsList::new(attrs_list.as_ref().map_or_else(
384 || {
385 buffer
386 .lines
387 .last()
388 .map_or(Attrs::new(), |line| line.attrs_list().defaults())
389 },
390 |x| x.defaults(),
391 )),
392 Shaping::Advanced,
393 );
394 buffer.lines.push(line);
395 }
396
397 let line: &mut BufferLine = &mut buffer.lines[cursor.line];
398 let insert_line = cursor.line + 1;
399 let ending = line.ending();
400
401 let after: BufferLine = line.split_off(cursor.index);
403 let after_len = after.text().len();
404
405 let mut final_attrs = attrs_list.unwrap_or_else(|| {
407 AttrsList::new(line.attrs_list().get_span(cursor.index.saturating_sub(1)))
408 });
409
410 let addendum = once("").filter(|_| data.ends_with('\n'));
414 let mut lines_iter = data.split_inclusive('\n').chain(addendum);
415 if let Some(data_line) = lines_iter.next() {
416 let mut these_attrs = final_attrs.split_off(data_line.len());
417 remaining_split_len -= data_line.len();
418 core::mem::swap(&mut these_attrs, &mut final_attrs);
419 line.append(BufferLine::new(
420 data_line
421 .strip_suffix(char::is_control)
422 .unwrap_or(data_line),
423 ending,
424 these_attrs,
425 Shaping::Advanced,
426 ));
427 } else {
428 panic!("str::lines() did not yield any elements");
429 }
430 if let Some(data_line) = lines_iter.next_back() {
431 remaining_split_len -= data_line.len();
432 let mut tmp = BufferLine::new(
433 data_line
434 .strip_suffix(char::is_control)
435 .unwrap_or(data_line),
436 ending,
437 final_attrs.split_off(remaining_split_len),
438 Shaping::Advanced,
439 );
440 tmp.append(after);
441 buffer.lines.insert(insert_line, tmp);
442 cursor.line += 1;
443 } else {
444 line.append(after);
445 }
446 for data_line in lines_iter.rev() {
447 remaining_split_len -= data_line.len();
448 let tmp = BufferLine::new(
449 data_line
450 .strip_suffix(char::is_control)
451 .unwrap_or(data_line),
452 ending,
453 final_attrs.split_off(remaining_split_len),
454 Shaping::Advanced,
455 );
456 buffer.lines.insert(insert_line, tmp);
457 cursor.line += 1;
458 }
459
460 assert_eq!(remaining_split_len, 0);
461
462 cursor.index = buffer.lines[cursor.line].text().len() - after_len;
464
465 ChangeItem {
466 start,
467 end: cursor,
468 text: data.to_string(),
469 insert: true,
470 }
471 });
472
473 if let Some(ref mut change) = self.change {
474 change.items.push(change_item);
475 }
476
477 cursor
478 }
479
480 fn copy_selection(&self) -> Option<String> {
481 let (start, end) = self.selection_bounds()?;
482 self.with_buffer(|buffer| {
483 let mut selection = String::new();
484 {
486 if start.line == end.line {
488 selection.push_str(&buffer.lines[start.line].text()[start.index..end.index]);
489 } else {
490 selection.push_str(&buffer.lines[start.line].text()[start.index..]);
491 selection.push('\n');
492 }
493 }
494
495 for line_i in start.line + 1..end.line {
497 selection.push_str(buffer.lines[line_i].text());
498 selection.push('\n');
499 }
500
501 if end.line > start.line {
503 selection.push_str(&buffer.lines[end.line].text()[..end.index]);
505 }
506
507 Some(selection)
508 })
509 }
510
511 fn delete_selection(&mut self) -> bool {
512 let (start, end) = match self.selection_bounds() {
513 Some(some) => some,
514 None => return false,
515 };
516
517 self.cursor = start;
519
520 self.selection = Selection::None;
522
523 self.delete_range(start, end);
525
526 true
527 }
528
529 fn apply_change(&mut self, change: &Change) -> bool {
530 if let Some(pending) = self.change.take() {
532 if !pending.items.is_empty() {
533 log::warn!("pending change caused apply_change to be ignored!");
535 self.change = Some(pending);
536 return false;
537 }
538 }
539
540 for item in change.items.iter() {
541 if item.insert {
543 self.cursor = self.insert_at(item.start, &item.text, None);
544 } else {
545 self.cursor = item.start;
546 self.delete_range(item.start, item.end);
547 }
548 }
549 true
550 }
551
552 fn start_change(&mut self) {
553 if self.change.is_none() {
554 self.change = Some(Change::default());
555 }
556 }
557
558 fn finish_change(&mut self) -> Option<Change> {
559 self.change.take()
560 }
561
562 fn action(&mut self, font_system: &mut FontSystem, action: Action) {
563 let old_cursor = self.cursor;
564
565 match action {
566 Action::Motion(motion) => {
567 let cursor = self.cursor;
568 let cursor_x_opt = self.cursor_x_opt;
569 if let Some((new_cursor, new_cursor_x_opt)) = self.with_buffer_mut(|buffer| {
570 buffer.cursor_motion(font_system, cursor, cursor_x_opt, motion)
571 }) {
572 self.cursor = new_cursor;
573 self.cursor_x_opt = new_cursor_x_opt;
574 }
575 }
576 Action::Escape => {
577 match self.selection {
578 Selection::None => {}
579 _ => self.with_buffer_mut(|buffer| buffer.set_redraw(true)),
580 }
581 self.selection = Selection::None;
582 }
583 Action::Insert(character) => {
584 if character.is_control() && !['\t', '\n', '\u{92}'].contains(&character) {
585 log::debug!("Refusing to insert control character {:?}", character);
587 } else if character == '\n' {
588 self.action(font_system, Action::Enter);
589 } else {
590 let mut str_buf = [0u8; 8];
591 let str_ref = character.encode_utf8(&mut str_buf);
592 self.insert_string(str_ref, None);
593 }
594 }
595 Action::Enter => {
596 if self.auto_indent {
598 let mut string = String::from("\n");
599 self.with_buffer(|buffer| {
600 let line = &buffer.lines[self.cursor.line];
601 let text = line.text();
602 for c in text.chars() {
603 if c.is_whitespace() {
604 string.push(c);
605 } else {
606 break;
607 }
608 }
609 });
610 self.insert_string(&string, None);
611 } else {
612 self.insert_string("\n", None);
613 }
614
615 let line_i = self.cursor.line;
617 self.with_buffer_mut(|buffer| {
618 buffer.line_layout(font_system, line_i);
619 });
620 }
621 Action::Backspace => {
622 if self.delete_selection() {
623 } else {
625 let end = self.cursor;
627
628 if self.cursor.index > 0 {
629 self.cursor.index = self.with_buffer(|buffer| {
631 buffer.lines[self.cursor.line].text()[..self.cursor.index]
632 .char_indices()
633 .next_back()
634 .map_or(0, |(i, _)| i)
635 });
636 } else if self.cursor.line > 0 {
637 self.cursor.line -= 1;
639 self.cursor.index =
640 self.with_buffer(|buffer| buffer.lines[self.cursor.line].text().len());
641 }
642
643 if self.cursor != end {
644 self.delete_range(self.cursor, end);
646 }
647 }
648 }
649 Action::Delete => {
650 if self.delete_selection() {
651 } else {
653 let mut start = self.cursor;
655 let mut end = self.cursor;
656
657 self.with_buffer(|buffer| {
658 if start.index < buffer.lines[start.line].text().len() {
659 let line = &buffer.lines[start.line];
660
661 let range_opt = line
662 .text()
663 .grapheme_indices(true)
664 .take_while(|(i, _)| *i <= start.index)
665 .last()
666 .map(|(i, c)| i..(i + c.len()));
667
668 if let Some(range) = range_opt {
669 start.index = range.start;
670 end.index = range.end;
671 }
672 } else if start.line + 1 < buffer.lines.len() {
673 end.line += 1;
674 end.index = 0;
675 }
676 });
677
678 if start != end {
679 self.cursor = start;
680 self.delete_range(start, end);
681 }
682 }
683 }
684 Action::Indent => {
685 let (start, end) = match self.selection_bounds() {
687 Some(some) => some,
688 None => (self.cursor, self.cursor),
689 };
690
691 let tab_width: usize = self.tab_width().into();
693 for line_i in start.line..=end.line {
694 let mut after_whitespace = 0;
696 let mut required_indent = 0;
697 self.with_buffer(|buffer| {
698 let line = &buffer.lines[line_i];
699 let text = line.text();
700 after_whitespace = text.len();
702 for (count, (index, c)) in text.char_indices().enumerate() {
703 if !c.is_whitespace() {
704 after_whitespace = index;
705 required_indent = tab_width - (count % tab_width);
706 break;
707 }
708 }
709 });
710
711 if required_indent == 0 {
713 required_indent = tab_width;
714 }
715
716 self.insert_at(
717 Cursor::new(line_i, after_whitespace),
718 &" ".repeat(required_indent),
719 None,
720 );
721
722 if self.cursor.line == line_i {
724 if self.cursor.index < after_whitespace {
726 self.cursor.index = after_whitespace;
727 }
728 self.cursor.index += required_indent;
729 }
730
731 match self.selection {
733 Selection::None => {}
734 Selection::Normal(ref mut select)
735 | Selection::Line(ref mut select)
736 | Selection::Word(ref mut select) => {
737 if select.line == line_i && select.index >= after_whitespace {
738 select.index += required_indent;
739 }
740 }
741 }
742
743 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
745 }
746 }
747 Action::Unindent => {
748 let (start, end) = match self.selection_bounds() {
750 Some(some) => some,
751 None => (self.cursor, self.cursor),
752 };
753
754 let tab_width: usize = self.tab_width().into();
756 for line_i in start.line..=end.line {
757 let mut last_indent = 0;
759 let mut after_whitespace = 0;
760 self.with_buffer(|buffer| {
761 let line = &buffer.lines[line_i];
762 let text = line.text();
763 after_whitespace = text.len();
765 for (count, (index, c)) in text.char_indices().enumerate() {
766 if !c.is_whitespace() {
767 after_whitespace = index;
768 break;
769 }
770 if count % tab_width == 0 {
771 last_indent = index;
772 }
773 }
774 });
775
776 if last_indent == after_whitespace {
778 continue;
779 }
780
781 self.delete_range(
783 Cursor::new(line_i, last_indent),
784 Cursor::new(line_i, after_whitespace),
785 );
786
787 if self.cursor.line == line_i && self.cursor.index > last_indent {
789 self.cursor.index -= after_whitespace - last_indent;
790 }
791
792 match self.selection {
794 Selection::None => {}
795 Selection::Normal(ref mut select)
796 | Selection::Line(ref mut select)
797 | Selection::Word(ref mut select) => {
798 if select.line == line_i && select.index > last_indent {
799 select.index -= after_whitespace - last_indent;
800 }
801 }
802 }
803
804 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
806 }
807 }
808 Action::Click { x, y } => {
809 self.set_selection(Selection::None);
810
811 if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
812 {
813 if new_cursor != self.cursor {
814 self.cursor = new_cursor;
815 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
816 }
817 }
818 }
819 Action::DoubleClick { x, y } => {
820 self.set_selection(Selection::None);
821
822 if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
823 {
824 if new_cursor != self.cursor {
825 self.cursor = new_cursor;
826 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
827 }
828 self.selection = Selection::Word(self.cursor);
829 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
830 }
831 }
832 Action::TripleClick { x, y } => {
833 self.set_selection(Selection::None);
834
835 if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
836 {
837 if new_cursor != self.cursor {
838 self.cursor = new_cursor;
839 }
840 self.selection = Selection::Line(self.cursor);
841 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
842 }
843 }
844 Action::Drag { x, y } => {
845 if self.selection == Selection::None {
846 self.selection = Selection::Normal(self.cursor);
847 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
848 }
849
850 if let Some(new_cursor) = self.with_buffer(|buffer| buffer.hit(x as f32, y as f32))
851 {
852 if new_cursor != self.cursor {
853 self.cursor = new_cursor;
854 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
855 }
856 }
857 }
858 Action::Scroll { lines } => {
859 self.with_buffer_mut(|buffer| {
860 let mut scroll = buffer.scroll();
861 scroll.vertical += lines as f32 * buffer.metrics().line_height;
863 buffer.set_scroll(scroll);
864 });
865 }
866 }
867
868 if old_cursor != self.cursor {
869 self.cursor_moved = true;
870 self.with_buffer_mut(|buffer| buffer.set_redraw(true));
871
872 }
888 }
889
890 fn cursor_position(&self) -> Option<(i32, i32)> {
891 self.with_buffer(|buffer| {
892 buffer
893 .layout_runs()
894 .find_map(|run| cursor_position(&self.cursor, &run))
895 })
896 }
897}
898
899impl BorrowedWithFontSystem<'_, Editor<'_>> {
900 #[cfg(feature = "swash")]
901 pub fn draw<F>(
902 &mut self,
903 cache: &mut crate::SwashCache,
904 text_color: Color,
905 cursor_color: Color,
906 selection_color: Color,
907 selected_text_color: Color,
908 f: F,
909 ) where
910 F: FnMut(i32, i32, u32, u32, Color),
911 {
912 self.inner.draw(
913 self.font_system,
914 cache,
915 text_color,
916 cursor_color,
917 selection_color,
918 selected_text_color,
919 f,
920 );
921 }
922}