1use std::{
2 borrow::{Borrow, Cow},
3 cmp::Ordering,
4 collections::BTreeSet,
5 fmt::Display,
6 sync::{
7 atomic::{self, AtomicU64},
8 Arc,
9 },
10};
11
12use lapce_xi_rope::{
13 multiset::Subset,
14 tree::{Node, NodeInfo},
15 Delta, DeltaBuilder, DeltaElement, Interval, Rope, RopeDelta,
16};
17
18use crate::{
19 cursor::CursorMode,
20 editor::EditType,
21 indent::{auto_detect_indent_style, IndentStyle},
22 line_ending::{LineEnding, LineEndingDetermination},
23 mode::Mode,
24 selection::Selection,
25 word::WordCursor,
26};
27
28pub mod diff;
29pub mod rope_text;
30
31use rope_text::*;
32
33#[derive(Clone)]
34enum Contents {
35 Edit {
36 undo_group: usize,
40 inserts: Subset,
43 deletes: Subset,
46 },
47 Undo {
48 toggled_groups: BTreeSet<usize>, deletes_bitxor: Subset,
54 },
55}
56
57#[derive(Clone)]
58struct Revision {
59 num: u64,
60 max_undo_so_far: usize,
61 edit: Contents,
62 cursor_before: Option<CursorMode>,
63 cursor_after: Option<CursorMode>,
64}
65
66#[derive(Debug, Clone)]
67pub struct InvalLines {
68 pub start_line: usize,
69 pub inval_count: usize,
70 pub new_count: usize,
71 pub old_text: Rope,
72}
73
74#[derive(Clone)]
75pub struct Buffer {
76 rev_counter: u64,
77 pristine_rev_id: u64,
78 atomic_rev: Arc<AtomicU64>,
79
80 text: Rope,
81 revs: Vec<Revision>,
82 cur_undo: usize,
83 undos: BTreeSet<usize>,
84 undo_group_id: usize,
85 live_undos: Vec<usize>,
86 deletes_from_union: Subset,
87 undone_groups: BTreeSet<usize>,
88 tombstones: Rope,
89 this_edit_type: EditType,
90 last_edit_type: EditType,
91
92 indent_style: IndentStyle,
93 line_ending: LineEnding,
94}
95
96impl Display for Buffer {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 f.write_str(&self.text().to_string())
99 }
100}
101
102impl Buffer {
103 pub fn new(text: impl Into<Rope>) -> Self {
104 let text = text.into();
105
106 let line_ending = LineEndingDetermination::determine(&text);
108 let line_ending = line_ending.unwrap_or(LineEnding::Lf);
109
110 let text = line_ending.normalize_limited(&text);
112
113 let len = text.len();
114 Self {
115 text,
116
117 rev_counter: 1,
118 pristine_rev_id: 0,
119 atomic_rev: Arc::new(AtomicU64::new(0)),
120
121 revs: vec![Revision {
122 num: 0,
123 max_undo_so_far: 0,
124 edit: Contents::Undo {
125 toggled_groups: BTreeSet::new(),
126 deletes_bitxor: Subset::new(0),
127 },
128 cursor_before: None,
129 cursor_after: None,
130 }],
131 cur_undo: 1,
132 undos: BTreeSet::new(),
133 undo_group_id: 1,
134 live_undos: vec![0],
135 deletes_from_union: Subset::new(len),
136 undone_groups: BTreeSet::new(),
137 tombstones: Rope::default(),
138
139 this_edit_type: EditType::Other,
140 last_edit_type: EditType::Other,
141 indent_style: IndentStyle::DEFAULT_INDENT,
142 line_ending,
143 }
144 }
145
146 pub fn rev(&self) -> u64 {
148 self.revs.last().unwrap().num
149 }
150
151 pub fn set_pristine(&mut self) {
153 self.pristine_rev_id = self.rev();
154 }
155
156 pub fn is_pristine(&self) -> bool {
157 self.is_equivalent_revision(self.pristine_rev_id, self.rev())
158 }
159
160 pub fn set_cursor_before(&mut self, cursor: CursorMode) {
161 if let Some(rev) = self.revs.last_mut() {
162 rev.cursor_before = Some(cursor);
163 }
164 }
165
166 pub fn set_cursor_after(&mut self, cursor: CursorMode) {
167 if let Some(rev) = self.revs.last_mut() {
168 rev.cursor_after = Some(cursor);
169 }
170 }
171
172 fn is_equivalent_revision(&self, base_rev: u64, other_rev: u64) -> bool {
173 let base_subset = self
174 .find_rev(base_rev)
175 .map(|rev_index| self.deletes_from_cur_union_for_index(rev_index));
176 let other_subset = self
177 .find_rev(other_rev)
178 .map(|rev_index| self.deletes_from_cur_union_for_index(rev_index));
179
180 base_subset.is_some() && base_subset == other_subset
181 }
182
183 fn find_rev(&self, rev_id: u64) -> Option<usize> {
184 self.revs
185 .iter()
186 .enumerate()
187 .rev()
188 .find(|&(_, rev)| rev.num == rev_id)
189 .map(|(i, _)| i)
190 }
191
192 pub fn atomic_rev(&self) -> Arc<AtomicU64> {
193 self.atomic_rev.clone()
194 }
195
196 pub fn init_content(&mut self, content: Rope) {
197 if !content.is_empty() {
198 let line_ending = LineEndingDetermination::determine(&content);
199 self.line_ending = line_ending.unwrap_or(self.line_ending);
200
201 let content = self.line_ending.normalize_limited(&content);
202
203 let delta = Delta::simple_edit(Interval::new(0, 0), content, 0);
204 let (new_rev, new_text, new_tombstones, new_deletes_from_union) =
205 self.mk_new_rev(0, delta.clone());
206 self.apply_edit(
207 &delta,
208 new_rev,
209 new_text,
210 new_tombstones,
211 new_deletes_from_union,
212 );
213 }
214 self.set_pristine();
215 }
216
217 pub fn reload(&mut self, content: Rope, set_pristine: bool) -> (Rope, RopeDelta, InvalLines) {
218 let line_ending = LineEndingDetermination::determine(&content);
220 self.line_ending = line_ending.unwrap_or(self.line_ending);
221
222 let content = self.line_ending.normalize_limited(&content);
223
224 let len = self.text.len();
225 let delta = Delta::simple_edit(Interval::new(0, len), content, len);
226 self.this_edit_type = EditType::Other;
227 let (text, delta, inval_lines) = self.add_delta(delta);
228 if set_pristine {
229 self.set_pristine();
230 }
231 (text, delta, inval_lines)
232 }
233
234 pub fn detect_indent(&mut self, default: impl FnOnce() -> IndentStyle) {
235 self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(default);
236 }
237
238 pub fn indent_style(&self) -> IndentStyle {
239 self.indent_style
240 }
241
242 pub fn indent_unit(&self) -> &'static str {
244 self.indent_style.as_str()
245 }
246
247 pub fn line_ending(&self) -> LineEnding {
248 self.line_ending
249 }
250
251 pub fn set_line_ending(&mut self, line_ending: LineEnding) {
252 self.line_ending = line_ending;
253 }
254
255 pub fn reset_edit_type(&mut self) {
256 self.last_edit_type = EditType::Other;
257 }
258
259 pub fn edit<'a, I, E, S>(
262 &mut self,
263 edits: I,
264 edit_type: EditType,
265 ) -> (Rope, RopeDelta, InvalLines)
266 where
267 I: IntoIterator<Item = E>,
268 E: Borrow<(S, &'a str)>,
269 S: AsRef<Selection>,
270 {
271 let mut builder = DeltaBuilder::new(self.len());
272 let mut interval_rope = Vec::new();
273 for edit in edits {
274 let (selection, content) = edit.borrow();
275 let rope = Rope::from(content);
276 for region in selection.as_ref().regions() {
277 interval_rope.push((region.min(), region.max(), rope.clone()));
278 }
279 }
280 interval_rope.sort_by(|a, b| {
281 if a.0 == b.0 && a.1 == b.1 {
282 Ordering::Equal
283 } else if a.1 == b.0 {
284 Ordering::Less
285 } else {
286 a.1.cmp(&b.0)
287 }
288 });
289 for (start, end, rope) in interval_rope.into_iter() {
290 builder.replace(start..end, self.line_ending.normalize(&rope));
296 }
297 let delta = builder.build();
298 self.this_edit_type = edit_type;
299 self.add_delta(delta)
300 }
301
302 pub fn normalize_line_endings(&mut self) -> Option<(Rope, RopeDelta, InvalLines)> {
303 let Some(delta) = self.line_ending.normalize_delta(&self.text) else {
304 return None;
306 };
307 self.this_edit_type = EditType::NormalizeLineEndings;
308 Some(self.add_delta(delta))
309 }
310
311 fn add_delta(&mut self, delta: RopeDelta) -> (Rope, RopeDelta, InvalLines) {
314 let text = self.text.clone();
315
316 let undo_group = self.calculate_undo_group();
317 self.last_edit_type = self.this_edit_type;
318
319 let (new_rev, new_text, new_tombstones, new_deletes_from_union) =
320 self.mk_new_rev(undo_group, delta.clone());
321
322 let inval_lines = self.apply_edit(
323 &delta,
324 new_rev,
325 new_text,
326 new_tombstones,
327 new_deletes_from_union,
328 );
329
330 (text, delta, inval_lines)
331 }
332
333 fn apply_edit(
334 &mut self,
335 delta: &RopeDelta,
336 new_rev: Revision,
337 new_text: Rope,
338 new_tombstones: Rope,
339 new_deletes_from_union: Subset,
340 ) -> InvalLines {
341 self.rev_counter += 1;
342
343 let (iv, newlen) = delta.summary();
344 let old_logical_end_line = self.text.line_of_offset(iv.end) + 1;
345 let old_text = self.text.clone();
346
347 self.revs.push(new_rev);
348 self.text = new_text;
349 self.tombstones = new_tombstones;
350 self.deletes_from_union = new_deletes_from_union;
351
352 let logical_start_line = self.text.line_of_offset(iv.start);
353 let new_logical_end_line = self.text.line_of_offset(iv.start + newlen) + 1;
354 let old_hard_count = old_logical_end_line - logical_start_line;
355 let new_hard_count = new_logical_end_line - logical_start_line;
356
357 InvalLines {
358 start_line: logical_start_line,
359 inval_count: old_hard_count,
360 new_count: new_hard_count,
361 old_text,
362 }
363 }
364
365 fn calculate_undo_group(&mut self) -> usize {
366 let has_undos = !self.live_undos.is_empty();
367 let is_unbroken_group = !self.this_edit_type.breaks_undo_group(self.last_edit_type);
368
369 if has_undos && is_unbroken_group {
370 *self.live_undos.last().unwrap()
371 } else {
372 let undo_group = self.undo_group_id;
373 self.live_undos.truncate(self.cur_undo);
374 self.live_undos.push(undo_group);
375 self.cur_undo += 1;
376 self.undo_group_id += 1;
377 undo_group
378 }
379 }
380
381 fn mk_new_rev(&self, undo_group: usize, delta: RopeDelta) -> (Revision, Rope, Rope, Subset) {
383 let (ins_delta, deletes) = delta.factor();
384
385 let deletes_at_rev = &self.deletes_from_union;
386
387 let union_ins_delta = ins_delta.transform_expand(deletes_at_rev, true);
388 let mut new_deletes = deletes.transform_expand(deletes_at_rev);
389
390 let new_inserts = union_ins_delta.inserted_subset();
391 if !new_inserts.is_empty() {
392 new_deletes = new_deletes.transform_expand(&new_inserts);
393 }
394 let cur_deletes_from_union = &self.deletes_from_union;
395 let text_ins_delta = union_ins_delta.transform_shrink(cur_deletes_from_union);
396 let text_with_inserts = text_ins_delta.apply(&self.text);
397 let rebased_deletes_from_union = cur_deletes_from_union.transform_expand(&new_inserts);
398
399 let undone = self.undone_groups.contains(&undo_group);
400 let new_deletes_from_union = {
401 let to_delete = if undone { &new_inserts } else { &new_deletes };
402 rebased_deletes_from_union.union(to_delete)
403 };
404
405 let (new_text, new_tombstones) = shuffle(
406 &text_with_inserts,
407 &self.tombstones,
408 &rebased_deletes_from_union,
409 &new_deletes_from_union,
410 );
411
412 let head_rev = self.revs.last().unwrap();
413 self.atomic_rev
414 .store(self.rev_counter, atomic::Ordering::Release);
415 (
416 Revision {
417 num: self.rev_counter,
418 max_undo_so_far: std::cmp::max(undo_group, head_rev.max_undo_so_far),
419 edit: Contents::Edit {
420 undo_group,
421 inserts: new_inserts,
422 deletes: new_deletes,
423 },
424 cursor_before: None,
425 cursor_after: None,
426 },
427 new_text,
428 new_tombstones,
429 new_deletes_from_union,
430 )
431 }
432
433 fn deletes_from_union_for_index(&self, rev_index: usize) -> Cow<Subset> {
434 self.deletes_from_union_before_index(rev_index + 1, true)
435 }
436
437 fn deletes_from_cur_union_for_index(&self, rev_index: usize) -> Cow<Subset> {
438 let mut deletes_from_union = self.deletes_from_union_for_index(rev_index);
439 for rev in &self.revs[rev_index + 1..] {
440 if let Contents::Edit { ref inserts, .. } = rev.edit {
441 if !inserts.is_empty() {
442 deletes_from_union = Cow::Owned(deletes_from_union.transform_union(inserts));
443 }
444 }
445 }
446 deletes_from_union
447 }
448
449 fn deletes_from_union_before_index(&self, rev_index: usize, invert_undos: bool) -> Cow<Subset> {
450 let mut deletes_from_union = Cow::Borrowed(&self.deletes_from_union);
451 let mut undone_groups = Cow::Borrowed(&self.undone_groups);
452
453 for rev in self.revs[rev_index..].iter().rev() {
455 deletes_from_union = match rev.edit {
456 Contents::Edit {
457 ref inserts,
458 ref deletes,
459 ref undo_group,
460 ..
461 } => {
462 if undone_groups.contains(undo_group) {
463 Cow::Owned(deletes_from_union.transform_shrink(inserts))
465 } else {
466 let un_deleted = deletes_from_union.subtract(deletes);
467 Cow::Owned(un_deleted.transform_shrink(inserts))
468 }
469 }
470 Contents::Undo {
471 ref toggled_groups,
472 ref deletes_bitxor,
473 } => {
474 if invert_undos {
475 let new_undone = undone_groups
476 .symmetric_difference(toggled_groups)
477 .cloned()
478 .collect();
479 undone_groups = Cow::Owned(new_undone);
480 Cow::Owned(deletes_from_union.bitxor(deletes_bitxor))
481 } else {
482 deletes_from_union
483 }
484 }
485 }
486 }
487 deletes_from_union
488 }
489
490 fn find_first_undo_candidate_index(&self, toggled_groups: &BTreeSet<usize>) -> usize {
491 if let Some(lowest_group) = toggled_groups.iter().cloned().next() {
493 for (i, rev) in self.revs.iter().enumerate().rev() {
494 if rev.max_undo_so_far < lowest_group {
495 return i + 1; }
497 }
498 0
499 } else {
500 self.revs.len()
502 }
503 }
504
505 fn compute_undo(&self, groups: &BTreeSet<usize>) -> (Revision, Subset) {
506 let toggled_groups = self
507 .undone_groups
508 .symmetric_difference(groups)
509 .cloned()
510 .collect();
511 let first_candidate = self.find_first_undo_candidate_index(&toggled_groups);
512 let mut deletes_from_union = self
514 .deletes_from_union_before_index(first_candidate, false)
515 .into_owned();
516
517 for rev in &self.revs[first_candidate..] {
518 if let Contents::Edit {
519 ref undo_group,
520 ref inserts,
521 ref deletes,
522 ..
523 } = rev.edit
524 {
525 if groups.contains(undo_group) {
526 if !inserts.is_empty() {
527 deletes_from_union = deletes_from_union.transform_union(inserts);
528 }
529 } else {
530 if !inserts.is_empty() {
531 deletes_from_union = deletes_from_union.transform_expand(inserts);
532 }
533 if !deletes.is_empty() {
534 deletes_from_union = deletes_from_union.union(deletes);
535 }
536 }
537 }
538 }
539
540 let cursor_before = self
541 .revs
542 .get(first_candidate)
543 .and_then(|rev| rev.cursor_before.clone());
544
545 let cursor_after = self
546 .revs
547 .get(first_candidate)
548 .and_then(|rev| match &rev.edit {
549 Contents::Edit { undo_group, .. } => Some(undo_group),
550 Contents::Undo { .. } => None,
551 })
552 .and_then(|group| {
553 let mut cursor = None;
554 for rev in &self.revs[first_candidate..] {
555 if let Contents::Edit { ref undo_group, .. } = rev.edit {
556 if group == undo_group {
557 cursor = rev.cursor_after.as_ref();
558 } else {
559 break;
560 }
561 }
562 }
563 cursor.cloned()
564 });
565
566 let deletes_bitxor = self.deletes_from_union.bitxor(&deletes_from_union);
567 let max_undo_so_far = self.revs.last().unwrap().max_undo_so_far;
568 self.atomic_rev
569 .store(self.rev_counter, atomic::Ordering::Release);
570 (
571 Revision {
572 num: self.rev_counter,
573 max_undo_so_far,
574 edit: Contents::Undo {
575 toggled_groups,
576 deletes_bitxor,
577 },
578 cursor_before,
579 cursor_after,
580 },
581 deletes_from_union,
582 )
583 }
584
585 fn undo(
586 &mut self,
587 groups: BTreeSet<usize>,
588 ) -> (
589 Rope,
590 RopeDelta,
591 InvalLines,
592 Option<CursorMode>,
593 Option<CursorMode>,
594 ) {
595 let text = self.text.clone();
596 let (new_rev, new_deletes_from_union) = self.compute_undo(&groups);
597 let delta = Delta::synthesize(
598 &self.tombstones,
599 &self.deletes_from_union,
600 &new_deletes_from_union,
601 );
602 let new_text = delta.apply(&self.text);
603 let new_tombstones = shuffle_tombstones(
604 &self.text,
605 &self.tombstones,
606 &self.deletes_from_union,
607 &new_deletes_from_union,
608 );
609 self.undone_groups = groups;
610
611 let cursor_before = new_rev.cursor_before.clone();
612 let cursor_after = new_rev.cursor_after.clone();
613
614 let inval_lines = self.apply_edit(
615 &delta,
616 new_rev,
617 new_text,
618 new_tombstones,
619 new_deletes_from_union,
620 );
621
622 (text, delta, inval_lines, cursor_before, cursor_after)
623 }
624
625 pub fn do_undo(&mut self) -> Option<(Rope, RopeDelta, InvalLines, Option<CursorMode>)> {
626 if self.cur_undo <= 1 {
627 return None;
628 }
629
630 self.cur_undo -= 1;
631 self.undos.insert(self.live_undos[self.cur_undo]);
632 self.last_edit_type = EditType::Undo;
633 let (text, delta, inval_lines, cursor_before, _cursor_after) =
634 self.undo(self.undos.clone());
635
636 Some((text, delta, inval_lines, cursor_before))
637 }
638
639 pub fn do_redo(&mut self) -> Option<(Rope, RopeDelta, InvalLines, Option<CursorMode>)> {
640 if self.cur_undo >= self.live_undos.len() {
641 return None;
642 }
643
644 self.undos.remove(&self.live_undos[self.cur_undo]);
645 self.cur_undo += 1;
646 self.last_edit_type = EditType::Redo;
647 let (text, delta, inval_lines, _cursor_before, cursor_after) =
648 self.undo(self.undos.clone());
649
650 Some((text, delta, inval_lines, cursor_after))
651 }
652
653 pub fn move_word_forward(&self, offset: usize) -> usize {
654 self.move_n_words_forward(offset, 1)
655 }
656
657 pub fn move_word_backward(&self, offset: usize, mode: Mode) -> usize {
658 self.move_n_words_backward(offset, 1, mode)
659 }
660
661 pub fn char_at_offset(&self, offset: usize) -> Option<char> {
662 if self.is_empty() {
663 return None;
664 }
665 let offset = offset.min(self.len());
666 WordCursor::new(&self.text, offset)
667 .inner
668 .peek_next_codepoint()
669 }
670}
671
672impl RopeText for Buffer {
673 fn text(&self) -> &Rope {
674 &self.text
675 }
676}
677
678fn shuffle_tombstones(
679 text: &Rope,
680 tombstones: &Rope,
681 old_deletes_from_union: &Subset,
682 new_deletes_from_union: &Subset,
683) -> Rope {
684 let inverse_tombstones_map = old_deletes_from_union.complement();
687 let move_delta = Delta::synthesize(
688 text,
689 &inverse_tombstones_map,
690 &new_deletes_from_union.complement(),
691 );
692 move_delta.apply(tombstones)
693}
694
695fn shuffle(
696 text: &Rope,
697 tombstones: &Rope,
698 old_deletes_from_union: &Subset,
699 new_deletes_from_union: &Subset,
700) -> (Rope, Rope) {
701 let del_delta = Delta::synthesize(tombstones, old_deletes_from_union, new_deletes_from_union);
703 let new_text = del_delta.apply(text);
704 (
705 new_text,
706 shuffle_tombstones(
707 text,
708 tombstones,
709 old_deletes_from_union,
710 new_deletes_from_union,
711 ),
712 )
713}
714
715pub struct DeltaValueRegion<'a, N: NodeInfo + 'a> {
716 pub old_offset: usize,
717 pub new_offset: usize,
718 pub len: usize,
719 pub node: &'a Node<N>,
720}
721
722pub struct InsertsValueIter<'a, N: NodeInfo + 'a> {
724 pos: usize,
725 last_end: usize,
726 els_iter: std::slice::Iter<'a, DeltaElement<N>>,
727}
728impl<'a, N: NodeInfo + 'a> InsertsValueIter<'a, N> {
729 pub fn new(delta: &'a Delta<N>) -> InsertsValueIter<'a, N> {
730 InsertsValueIter {
731 pos: 0,
732 last_end: 0,
733 els_iter: delta.els.iter(),
734 }
735 }
736}
737impl<'a, N: NodeInfo> Iterator for InsertsValueIter<'a, N> {
738 type Item = DeltaValueRegion<'a, N>;
739
740 fn next(&mut self) -> Option<Self::Item> {
741 for elem in &mut self.els_iter {
742 match *elem {
743 DeltaElement::Copy(b, e) => {
744 self.pos += e - b;
745 self.last_end = e;
746 }
747 DeltaElement::Insert(ref n) => {
748 let result = Some(DeltaValueRegion {
749 old_offset: self.last_end,
750 new_offset: self.pos,
751 len: n.len(),
752 node: n,
753 });
754 self.pos += n.len();
755 self.last_end += n.len();
756 return result;
757 }
758 }
759 }
760 None
761 }
762}
763
764#[cfg(test)]
765mod test;