1use crate::cache::{Cache, LineWidthCache};
2use crate::clipboard::Clipboard;
3use crate::glyph2::{GlyphIter2, TextWrap2};
4use crate::grapheme::Grapheme;
5use crate::range_map::{RangeMap, expand_range_by, ranges_intersect, shrink_range_by};
6use crate::text_store::TextStore;
7use crate::undo_buffer::{StyleChange, TextPositionChange, UndoBuffer, UndoEntry, UndoOp};
8use crate::{TextError, TextPosition, TextRange, upos_type};
9use dyn_clone::clone_box;
10use ratatui::layout::Size;
11use std::borrow::Cow;
12use std::cmp::min;
13use std::ops::Range;
14
15pub mod core_op;
16
17#[derive(Debug)]
19pub struct TextCore<Store> {
20 text: Store,
22
23 cursor: TextPosition,
25 anchor: TextPosition,
27
28 styles: Option<Box<RangeMap>>,
30 undo: Option<Box<dyn UndoBuffer>>,
32 clip: Option<Box<dyn Clipboard>>,
34 cache: Cache,
36
37 glyph_ctrl: bool,
39 wrap_ctrl: bool,
41}
42
43impl<Store: Clone> Clone for TextCore<Store> {
44 fn clone(&self) -> Self {
45 Self {
46 text: self.text.clone(),
47 cursor: self.cursor,
48 anchor: self.anchor,
49 styles: self.styles.clone(),
50 undo: self.undo.as_ref().map(|v| clone_box(v.as_ref())),
51 clip: self.clip.as_ref().map(|v| clone_box(v.as_ref())),
52 cache: Default::default(),
53 glyph_ctrl: self.glyph_ctrl,
54 wrap_ctrl: self.wrap_ctrl,
55 }
56 }
57}
58
59impl<Store: TextStore + Default> TextCore<Store> {
60 pub fn new(undo: Option<Box<dyn UndoBuffer>>, clip: Option<Box<dyn Clipboard>>) -> Self {
61 Self {
62 text: Store::default(),
63 cursor: Default::default(),
64 anchor: Default::default(),
65 styles: Default::default(),
66 undo,
67 clip,
68 cache: Default::default(),
69 glyph_ctrl: false,
70 wrap_ctrl: false,
71 }
72 }
73
74 #[inline]
76 pub fn set_glyph_ctrl(&mut self, show_ctrl: bool) {
77 self.glyph_ctrl = show_ctrl;
78 }
79
80 pub fn glyph_ctrl(&self) -> bool {
82 self.glyph_ctrl
83 }
84
85 #[inline]
87 pub fn set_wrap_ctrl(&mut self, wrap_ctrl: bool) {
88 self.wrap_ctrl = wrap_ctrl;
89 }
90
91 pub fn wrap_ctrl(&self) -> bool {
93 self.wrap_ctrl
94 }
95}
96
97impl<Store: TextStore + Default> TextCore<Store> {
98 pub fn set_clipboard(&mut self, clip: Option<Box<dyn Clipboard + 'static>>) {
100 self.clip = clip;
101 }
102
103 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
105 match &self.clip {
106 None => None,
107 Some(v) => Some(v.as_ref()),
108 }
109 }
110}
111
112impl<Store: TextStore + Default> TextCore<Store> {
113 #[inline]
115 pub fn set_undo_buffer(&mut self, undo: Option<Box<dyn UndoBuffer>>) {
116 self.undo = undo;
117 }
118
119 #[inline]
121 pub fn set_undo_count(&mut self, n: u32) {
122 if let Some(undo) = self.undo.as_mut() {
123 undo.set_undo_count(n);
124 };
125 }
126
127 #[inline]
129 pub fn begin_undo_seq(&mut self) {
130 if let Some(undo) = self.undo.as_mut() {
131 undo.begin_seq();
132 };
133 }
134
135 #[inline]
137 pub fn end_undo_seq(&mut self) {
138 if let Some(undo) = self.undo.as_mut() {
139 undo.end_seq();
140 };
141 }
142
143 #[inline]
145 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
146 match &self.undo {
147 None => None,
148 Some(v) => Some(v.as_ref()),
149 }
150 }
151
152 #[inline]
154 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
155 match &mut self.undo {
156 None => None,
157 Some(v) => Some(v.as_mut()),
158 }
159 }
160
161 pub fn undo(&mut self) -> bool {
163 let Some(undo) = self.undo.as_mut() else {
164 return false;
165 };
166
167 undo.append(UndoOp::Undo);
168
169 self._undo()
170 }
171
172 fn _undo(&mut self) -> bool {
174 let Some(undo) = self.undo.as_mut() else {
175 return false;
176 };
177 let undo_op = undo.undo();
178 let changed = !undo_op.is_empty();
179 for op in undo_op {
180 match op {
181 UndoOp::InsertChar {
182 bytes,
183 cursor,
184 anchor,
185 ..
186 }
187 | UndoOp::InsertStr {
188 bytes,
189 cursor,
190 anchor,
191 ..
192 } => {
193 self.text.remove_b(bytes.clone()).expect("valid_bytes");
194
195 if let Some(sty) = &mut self.styles {
196 sty.remap(|r, _| Some(shrink_range_by(bytes.clone(), r)));
197 }
198 self.anchor = anchor.before;
199 self.cursor = cursor.before;
200 }
201 UndoOp::RemoveStr {
202 bytes,
203 cursor,
204 anchor,
205 txt,
206 styles,
207 }
208 | UndoOp::RemoveChar {
209 bytes,
210 cursor,
211 anchor,
212 txt,
213 styles,
214 } => {
215 self.text.insert_b(bytes.start, txt).expect("valid_bytes");
216
217 if let Some(sty) = &mut self.styles {
218 for s in styles {
219 sty.remove(s.after.clone(), s.style);
220 }
221 for s in styles {
222 sty.add(s.before.clone(), s.style);
223 }
224 sty.remap(|r, _| {
225 if ranges_intersect(bytes.clone(), r.clone()) {
226 Some(r)
227 } else {
228 Some(expand_range_by(bytes.clone(), r))
229 }
230 });
231 }
232 self.anchor = anchor.before;
233 self.cursor = cursor.before;
234 }
235 UndoOp::Cursor { cursor, anchor } => {
236 self.anchor = anchor.before;
237 self.cursor = cursor.before;
238 }
239 UndoOp::SetStyles { styles_before, .. } => {
240 if let Some(sty) = &mut self.styles {
241 sty.set(styles_before.iter().cloned());
242 }
243 }
244 UndoOp::SetText { .. } | UndoOp::Undo | UndoOp::Redo => {
245 unreachable!()
246 }
247 }
248 }
249 changed
250 }
251
252 pub fn redo(&mut self) -> bool {
254 let Some(undo) = self.undo.as_mut() else {
255 return false;
256 };
257
258 undo.append(UndoOp::Redo);
259
260 self._redo()
261 }
262
263 fn _redo(&mut self) -> bool {
264 let Some(undo) = self.undo.as_mut() else {
265 return false;
266 };
267 let redo_op = undo.redo();
268 let changed = !redo_op.is_empty();
269 for op in redo_op {
270 match op {
271 UndoOp::InsertChar {
272 bytes,
273 cursor,
274 anchor,
275 txt,
276 }
277 | UndoOp::InsertStr {
278 bytes,
279 cursor,
280 anchor,
281 txt,
282 } => {
283 self.text.insert_b(bytes.start, txt).expect("valid_bytes");
284 if let Some(sty) = &mut self.styles {
285 sty.remap(|r, _| Some(expand_range_by(bytes.clone(), r)));
286 }
287 self.anchor = anchor.after;
288 self.cursor = cursor.after;
289 }
290 UndoOp::RemoveChar {
291 bytes,
292 cursor,
293 anchor,
294 styles,
295 ..
296 }
297 | UndoOp::RemoveStr {
298 bytes,
299 cursor,
300 anchor,
301 styles,
302 ..
303 } => {
304 self.text.remove_b(bytes.clone()).expect("valid_bytes");
305
306 if let Some(sty) = &mut self.styles {
307 sty.remap(|r, _| {
308 if ranges_intersect(bytes.clone(), r.clone()) {
309 Some(r)
310 } else {
311 Some(shrink_range_by(bytes.clone(), r))
312 }
313 });
314 for s in styles {
315 sty.remove(s.before.clone(), s.style);
316 }
317 for s in styles {
318 sty.add(s.after.clone(), s.style);
319 }
320 }
321
322 self.anchor = anchor.after;
323 self.cursor = cursor.after;
324 }
325 UndoOp::Cursor { cursor, anchor } => {
326 self.anchor = anchor.after;
327 self.cursor = cursor.after;
328 }
329
330 UndoOp::SetStyles { styles_after, .. } => {
331 if let Some(sty) = &mut self.styles {
332 sty.set(styles_after.iter().cloned());
333 }
334 }
335 UndoOp::SetText { .. } | UndoOp::Undo | UndoOp::Redo => {
336 unreachable!()
337 }
338 }
339 }
340 changed
341 }
342
343 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
345 if let Some(undo) = &mut self.undo {
346 undo.recent_replay_log()
347 } else {
348 Vec::default()
349 }
350 }
351
352 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
354 for replay_entry in replay {
355 match &replay_entry.operation {
356 UndoOp::SetText { txt } => {
357 self.text.set_string(txt);
358 if let Some(sty) = &mut self.styles {
359 sty.clear();
360 }
361 if let Some(undo) = self.undo.as_mut() {
362 undo.clear();
363 };
364 }
365 UndoOp::InsertChar { bytes, txt, .. } | UndoOp::InsertStr { bytes, txt, .. } => {
366 self.text.insert_b(bytes.start, txt).expect("valid_range");
367 if let Some(sty) = &mut self.styles {
368 sty.remap(|r, _| Some(expand_range_by(bytes.clone(), r)));
369 }
370 }
371 UndoOp::RemoveChar { bytes, styles, .. }
372 | UndoOp::RemoveStr { bytes, styles, .. } => {
373 self.text.remove_b(bytes.clone()).expect("valid_range");
374 if let Some(sty) = &mut self.styles {
375 sty.remap(|r, _| {
376 if ranges_intersect(bytes.clone(), r.clone()) {
377 Some(r)
378 } else {
379 Some(shrink_range_by(bytes.clone(), r))
380 }
381 });
382 for s in styles {
383 sty.remove(s.before.clone(), s.style);
384 }
385 for s in styles {
386 sty.add(s.after.clone(), s.style);
387 }
388 }
389 }
390 UndoOp::Cursor { .. } => {
391 }
393
394 UndoOp::SetStyles { styles_after, .. } => {
395 self.init_styles();
396 if let Some(sty) = &mut self.styles {
397 sty.set(styles_after.iter().cloned());
398 }
399 }
400 UndoOp::Undo => {
401 self._undo();
402 }
403 UndoOp::Redo => {
404 self._redo();
405 }
406 }
407
408 if let Some(undo) = self.undo.as_mut() {
409 undo.append_from_replay(replay_entry.clone());
410 };
411 }
412 }
413}
414
415impl<Store: TextStore + Default> TextCore<Store> {
416 fn init_styles(&mut self) {
417 if self.styles.is_none() {
418 self.styles = Some(Box::new(RangeMap::default()));
419 }
420 }
421
422 #[inline]
427 pub fn set_styles(&mut self, new_styles: Vec<(Range<usize>, usize)>) {
428 self.init_styles();
429
430 let Some(sty) = &mut self.styles else {
431 return;
432 };
433 if let Some(undo) = &mut self.undo {
434 if undo.undo_styles_enabled() || undo.has_replay_log() {
435 undo.append(UndoOp::SetStyles {
436 styles_before: sty.values().collect::<Vec<_>>(),
437 styles_after: new_styles.clone(),
438 });
439 }
440 }
441 sty.set(new_styles.into_iter());
442 }
443
444 #[inline]
449 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
450 self.init_styles();
451
452 if let Some(sty) = &mut self.styles {
453 sty.add(range.clone(), style);
454 }
455 }
456
457 #[inline]
461 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
462 if let Some(sty) = &mut self.styles {
463 sty.remove(range.clone(), style);
464 }
465 }
466
467 #[inline]
469 pub fn remove_style_fully(&mut self, style: usize) {
470 let Some(sty) = self.styles.as_mut() else {
471 return;
472 };
473 let styles = sty
474 .values()
475 .filter(|(_, s)| *s == style)
476 .collect::<Vec<_>>();
477 for (range, style) in &styles {
478 sty.remove(range.clone(), *style);
479 }
480 }
481
482 #[inline]
487 pub(crate) fn styles_at_page(&self, pos: usize, range: Range<usize>, buf: &mut Vec<usize>) {
488 if let Some(sty) = &self.styles {
489 sty.values_at_page(pos, range, buf);
490 }
491 }
492
493 #[inline]
495 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
496 if let Some(sty) = &self.styles {
497 sty.values_in(range, buf);
498 }
499 }
500
501 #[inline]
503 pub fn styles_in_match(
504 &self,
505 range: Range<usize>,
506 style: usize,
507 buf: &mut Vec<(Range<usize>, usize)>,
508 ) {
509 if let Some(sty) = &self.styles {
510 sty.values_in_match(range, style, buf);
511 }
512 }
513
514 #[inline]
516 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
517 if let Some(sty) = &self.styles {
518 sty.values_at(byte_pos, buf);
519 }
520 }
521
522 #[inline]
524 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
525 if let Some(sty) = &self.styles {
526 sty.value_match(byte_pos, style)
527 } else {
528 None
529 }
530 }
531
532 #[inline]
534 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
535 self.styles.as_ref().map(|v| v.values())
536 }
537}
538
539impl<Store: TextStore + Default> TextCore<Store> {
540 pub fn set_cursor(&mut self, mut cursor: TextPosition, extend_selection: bool) -> bool {
546 let old_cursor = self.cursor;
547 let old_anchor = self.anchor;
548
549 cursor.y = min(cursor.y, self.len_lines());
550 cursor.x = min(cursor.x, self.line_width(cursor.y).expect("valid-line"));
551
552 self.cursor = cursor;
553 if !extend_selection {
554 self.anchor = cursor;
555 }
556
557 if let Some(undo) = self.undo.as_mut() {
558 undo.append(UndoOp::Cursor {
559 cursor: TextPositionChange {
560 before: old_cursor,
561 after: self.cursor,
562 },
563 anchor: TextPositionChange {
564 before: old_anchor,
565 after: self.anchor,
566 },
567 });
568 }
569
570 old_cursor != self.cursor || old_anchor != self.anchor
571 }
572
573 #[inline]
575 pub fn cursor(&self) -> TextPosition {
576 self.cursor
577 }
578
579 #[inline]
581 pub fn anchor(&self) -> TextPosition {
582 self.anchor
583 }
584
585 #[inline]
587 pub fn has_selection(&self) -> bool {
588 self.anchor != self.cursor
589 }
590
591 #[inline]
594 pub fn set_selection(&mut self, anchor: TextPosition, cursor: TextPosition) -> bool {
595 let old_selection = self.selection();
596
597 self.set_cursor(anchor, false);
598 self.set_cursor(cursor, true);
599
600 old_selection != self.selection()
601 }
602
603 #[inline]
605 pub fn select_all(&mut self) -> bool {
606 let old_selection = self.selection();
607
608 self.set_cursor(TextPosition::new(0, self.len_lines()), false);
609 self.set_cursor(TextPosition::new(0, 0), true);
610
611 old_selection != self.selection()
612 }
613
614 #[inline]
616 pub fn selection(&self) -> TextRange {
617 #[allow(clippy::comparison_chain)]
618 if self.cursor.y < self.anchor.y {
619 TextRange {
620 start: self.cursor,
621 end: self.anchor,
622 }
623 } else if self.cursor.y > self.anchor.y {
624 TextRange {
625 start: self.anchor,
626 end: self.cursor,
627 }
628 } else {
629 if self.cursor.x < self.anchor.x {
630 TextRange {
631 start: self.cursor,
632 end: self.anchor,
633 }
634 } else {
635 TextRange {
636 start: self.anchor,
637 end: self.cursor,
638 }
639 }
640 }
641 }
642}
643
644impl<Store: TextStore + Default> TextCore<Store> {
645 pub(crate) fn cache_validity(&self) -> Option<usize> {
650 self.text.cache_validity()
651 }
652}
653
654impl<Store: TextStore + Default> TextCore<Store> {
655 #[inline]
657 pub fn is_empty(&self) -> bool {
658 self.len_bytes() == 0
659 }
660
661 #[inline]
664 pub fn byte_at(&self, pos: TextPosition) -> Result<Range<usize>, TextError> {
665 self.text.byte_range_at(pos)
666 }
667
668 #[inline]
670 pub fn bytes_at_range(&self, range: TextRange) -> Result<Range<usize>, TextError> {
671 self.text.byte_range(range)
672 }
673
674 #[inline]
677 pub fn byte_pos(&self, byte: usize) -> Result<TextPosition, TextError> {
678 self.text.byte_to_pos(byte)
679 }
680
681 #[inline]
683 pub fn byte_range(&self, bytes: Range<usize>) -> Result<TextRange, TextError> {
684 self.text.bytes_to_range(bytes)
685 }
686
687 #[inline]
689 pub fn str_slice(&self, range: TextRange) -> Result<Cow<'_, str>, TextError> {
690 self.text.str_slice(range)
691 }
692
693 #[inline]
695 pub fn str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
696 self.text.str_slice_byte(range)
697 }
698
699 #[inline]
702 pub fn cache(&self) -> &Cache {
703 &self.cache
704 }
705
706 #[allow(clippy::too_many_arguments)]
708 pub(crate) fn fill_cache(
709 &self,
710 rendered: Size,
711 sub_row_offset: upos_type,
712 rows: Range<upos_type>,
713 tab_width: u32,
714 text_wrap: TextWrap2,
715 ctrl_char: bool,
716 left_margin: upos_type,
717 right_margin: upos_type,
718 word_margin: upos_type,
719 ) -> Result<(), TextError> {
720 _ = self.glyphs2(
721 rendered,
722 sub_row_offset,
723 rows,
724 tab_width,
725 text_wrap,
726 ctrl_char,
727 left_margin,
728 right_margin,
729 word_margin,
730 )?;
731 Ok(())
732 }
733
734 #[inline]
737 #[allow(clippy::too_many_arguments)]
738 pub(crate) fn glyphs2(
739 &self,
740 rendered: Size,
741 sub_row_offset: upos_type,
742 rows: Range<upos_type>,
743 tab_width: u32,
744 text_wrap: TextWrap2,
745 ctrl_char: bool,
746 left_margin: upos_type,
747 right_margin: upos_type,
748 word_margin: upos_type,
749 ) -> Result<GlyphIter2<'_, Store::GraphemeIter<'_>>, TextError> {
750 self.cache.validate(
751 text_wrap,
752 left_margin,
753 rendered.width as upos_type,
754 rendered.height as upos_type,
755 ctrl_char,
756 self.cache_validity(),
757 );
758
759 let range = TextRange::new((sub_row_offset, rows.start), (0, rows.end));
760
761 let range_bytes;
762 let mut range_to_bytes = self.cache.range_to_bytes.borrow_mut();
763 if let Some(cache) = range_to_bytes.get(&range) {
764 range_bytes = cache.clone();
765 } else {
766 let cache = self.text.byte_range(range)?;
767 range_to_bytes.insert(range, cache.clone());
768 range_bytes = cache;
769 }
770
771 let iter = self.graphemes_byte(range_bytes.clone(), range_bytes.start)?;
772
773 let mut it = GlyphIter2::new(
774 range.start, range_bytes.start,
776 iter,
777 self.cache.clone(),
778 );
779 it.set_tabs(tab_width);
780 it.set_show_ctrl(self.glyph_ctrl);
781 it.set_wrap_ctrl(self.wrap_ctrl);
782 it.set_lf_breaks(self.text().is_multi_line());
783 it.set_text_wrap(text_wrap);
784 it.set_left_margin(left_margin);
785 it.set_right_margin(right_margin);
786 it.set_word_margin(word_margin);
787 it.prepare()?;
788 Ok(it)
789 }
790
791 #[inline]
793 pub fn grapheme_at(&self, pos: TextPosition) -> Result<Option<Grapheme<'_>>, TextError> {
794 let range_bytes = self.bytes_at_range(TextRange::new(pos, (pos.x + 1, pos.y)))?;
795 let pos_byte = self.byte_at(pos)?.start;
796
797 let mut it = self.text.graphemes_byte(range_bytes, pos_byte)?;
798
799 Ok(it.next())
800 }
801
802 #[inline]
804 pub fn text_graphemes(&self, pos: TextPosition) -> Result<Store::GraphemeIter<'_>, TextError> {
805 let rows = self.len_lines() - 1;
806 let cols = self.line_width(rows).expect("valid_row");
807
808 let range_bytes = self.bytes_at_range(TextRange::new((0, 0), (cols, rows)))?;
809 let pos_byte = self.byte_at(pos)?.start;
810
811 self.text.graphemes_byte(range_bytes, pos_byte)
812 }
813
814 #[inline]
816 pub fn graphemes(
817 &self,
818 range: TextRange,
819 pos: TextPosition,
820 ) -> Result<Store::GraphemeIter<'_>, TextError> {
821 let range_bytes = self.bytes_at_range(range)?;
822 let pos_byte = self.byte_at(pos)?.start;
823
824 self.text.graphemes_byte(range_bytes, pos_byte)
825 }
826
827 #[inline]
829 pub fn graphemes_byte(
830 &self,
831 range: Range<usize>,
832 pos: usize,
833 ) -> Result<Store::GraphemeIter<'_>, TextError> {
834 self.text.graphemes_byte(range, pos)
835 }
836
837 #[inline]
841 pub fn line_at(&self, row: upos_type) -> Result<Cow<'_, str>, TextError> {
842 self.text.line_at(row)
843 }
844
845 #[inline]
849 pub fn lines_at(
850 &self,
851 row: upos_type,
852 ) -> Result<impl Iterator<Item = Cow<'_, str>>, TextError> {
853 self.text.lines_at(row)
854 }
855
856 #[inline]
858 pub fn line_graphemes(&self, row: upos_type) -> Result<Store::GraphemeIter<'_>, TextError> {
859 self.text.line_graphemes(row)
860 }
861
862 #[inline]
864 pub fn line_width(&self, row: upos_type) -> Result<upos_type, TextError> {
865 self.cache.validate_byte_pos(self.cache_validity());
866
867 let mut line_width = self.cache.line_width.borrow_mut();
868 if let Some(cache) = line_width.get(&row) {
869 Ok(cache.width)
870 } else {
871 let width = self.text.line_width(row)?;
872 let byte_pos = self.text.byte_range_at(TextPosition::new(width, row))?;
873 line_width.insert(
874 row,
875 LineWidthCache {
876 width,
877 byte_pos: byte_pos.start,
878 },
879 );
880 Ok(width)
881 }
882 }
883
884 #[inline]
886 pub fn len_lines(&self) -> upos_type {
887 self.text.len_lines()
888 }
889
890 #[inline]
892 pub fn len_bytes(&self) -> usize {
893 self.text.len_bytes()
894 }
895}
896
897impl<Store: TextStore + Default> TextCore<Store> {
898 pub fn clear(&mut self) {
900 self.text.set_string("");
901 self.cursor = TextPosition::default();
902 self.anchor = TextPosition::default();
903 if let Some(sty) = &mut self.styles {
904 sty.clear();
905 }
906 if let Some(undo) = &mut self.undo {
907 undo.clear();
908
909 if undo.has_replay_log() {
910 undo.append(UndoOp::SetText {
911 txt: self.text.string(),
912 });
913 }
914 }
915 }
916
917 pub fn text(&self) -> &Store {
919 &self.text
920 }
921
922 pub fn set_text(&mut self, t: Store) -> bool {
925 self.text = t;
926 if let Some(sty) = &mut self.styles {
927 sty.clear();
928 }
929 self.cache.clear();
930
931 self.cursor.y = 0;
932 self.cursor.x = 0;
933 self.anchor.y = 0;
934 self.anchor.x = 0;
935
936 if let Some(undo) = &mut self.undo {
937 undo.clear();
938
939 if undo.has_replay_log() {
940 undo.append(UndoOp::SetText {
941 txt: self.text.string(),
942 });
943 }
944 }
945
946 true
947 }
948
949 pub fn insert_char(&mut self, pos: TextPosition, c: char) -> Result<bool, TextError> {
955 let (inserted_range, inserted_bytes) = self.text.insert_char(pos, c)?;
956
957 let old_cursor = self.cursor;
958 let old_anchor = self.anchor;
959
960 if let Some(sty) = &mut self.styles {
961 sty.remap(|r, _| Some(expand_range_by(inserted_bytes.clone(), r)));
962 }
963 self.cursor = inserted_range.expand_pos(self.cursor);
964 self.anchor = inserted_range.expand_pos(self.anchor);
965
966 if let Some(undo) = self.undo.as_mut() {
967 undo.append(UndoOp::InsertChar {
968 bytes: inserted_bytes.clone(),
969 cursor: TextPositionChange {
970 before: old_cursor,
971 after: self.cursor,
972 },
973 anchor: TextPositionChange {
974 before: old_anchor,
975 after: self.anchor,
976 },
977 txt: c.to_string(),
978 });
979 }
980
981 Ok(true)
982 }
983
984 pub fn insert_str(&mut self, pos: TextPosition, t: &str) -> Result<bool, TextError> {
986 let old_cursor = self.cursor;
987 let old_anchor = self.anchor;
988
989 let (inserted_range, inserted_bytes) = self.text.insert_str(pos, t)?;
990
991 if let Some(sty) = &mut self.styles {
992 sty.remap(|r, _| Some(expand_range_by(inserted_bytes.clone(), r)));
993 }
994 self.anchor = inserted_range.expand_pos(self.anchor);
995 self.cursor = inserted_range.expand_pos(self.cursor);
996
997 if let Some(undo) = self.undo.as_mut() {
998 undo.append(UndoOp::InsertStr {
999 bytes: inserted_bytes.clone(),
1000 cursor: TextPositionChange {
1001 before: old_cursor,
1002 after: self.cursor,
1003 },
1004 anchor: TextPositionChange {
1005 before: old_anchor,
1006 after: self.anchor,
1007 },
1008 txt: t.to_string(),
1009 });
1010 }
1011
1012 Ok(true)
1013 }
1014
1015 pub fn remove_char_range(&mut self, range: TextRange) -> Result<bool, TextError> {
1020 self._remove_range(range, true)
1021 }
1022
1023 pub fn remove_str_range(&mut self, range: TextRange) -> Result<bool, TextError> {
1027 self._remove_range(range, false)
1028 }
1029
1030 fn _remove_range(&mut self, range: TextRange, char_range: bool) -> Result<bool, TextError> {
1031 let old_cursor = self.cursor;
1032 let old_anchor = self.anchor;
1033
1034 if range.is_empty() {
1035 return Ok(false);
1036 }
1037
1038 let (old_text, (_removed_range, removed_bytes)) = self.text.remove(range)?;
1039
1040 let mut changed_style = Vec::new();
1042 if let Some(sty) = &mut self.styles {
1043 sty.remap(|r, s| {
1044 let new_range = shrink_range_by(removed_bytes.clone(), r.clone());
1045 if ranges_intersect(r.clone(), removed_bytes.clone()) {
1046 changed_style.push(StyleChange {
1047 before: r.clone(),
1048 after: new_range.clone(),
1049 style: s,
1050 });
1051 if new_range.is_empty() {
1052 None
1053 } else {
1054 Some(new_range)
1055 }
1056 } else {
1057 Some(new_range)
1058 }
1059 });
1060 }
1061 self.anchor = range.shrink_pos(self.anchor);
1062 self.cursor = range.shrink_pos(self.cursor);
1063
1064 if let Some(undo) = &mut self.undo {
1065 if char_range {
1066 undo.append(UndoOp::RemoveChar {
1067 bytes: removed_bytes.clone(),
1068 cursor: TextPositionChange {
1069 before: old_cursor,
1070 after: self.cursor,
1071 },
1072 anchor: TextPositionChange {
1073 before: old_anchor,
1074 after: self.anchor,
1075 },
1076 txt: old_text,
1077 styles: changed_style,
1078 });
1079 } else {
1080 undo.append(UndoOp::RemoveStr {
1081 bytes: removed_bytes.clone(),
1082 cursor: TextPositionChange {
1083 before: old_cursor,
1084 after: self.cursor,
1085 },
1086 anchor: TextPositionChange {
1087 before: old_anchor,
1088 after: self.anchor,
1089 },
1090 txt: old_text,
1091 styles: changed_style,
1092 });
1093 }
1094 }
1095
1096 Ok(true)
1097 }
1098}