aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/edit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src/edit.rs')
-rw-r--r--crates/libeditor/src/edit.rs75
1 files changed, 31 insertions, 44 deletions
diff --git a/crates/libeditor/src/edit.rs b/crates/libeditor/src/edit.rs
index 163ecf6de..15a2a904f 100644
--- a/crates/libeditor/src/edit.rs
+++ b/crates/libeditor/src/edit.rs
@@ -1,11 +1,11 @@
1use {TextRange, TextUnit}; 1use {TextRange, TextUnit};
2 2
3#[derive(Debug)] 3#[derive(Debug, Clone)]
4pub struct Edit { 4pub struct Edit {
5 pub atoms: Vec<AtomEdit>, 5 atoms: Vec<AtomEdit>,
6} 6}
7 7
8#[derive(Debug)] 8#[derive(Debug, Clone)]
9pub struct AtomEdit { 9pub struct AtomEdit {
10 pub delete: TextRange, 10 pub delete: TextRange,
11 pub insert: String, 11 pub insert: String,
@@ -22,7 +22,6 @@ impl EditBuilder {
22 } 22 }
23 23
24 pub fn replace(&mut self, range: TextRange, replacement: String) { 24 pub fn replace(&mut self, range: TextRange, replacement: String) {
25 let range = self.translate(range);
26 self.atoms.push(AtomEdit { delete: range, insert: replacement }) 25 self.atoms.push(AtomEdit { delete: range, insert: replacement })
27 } 26 }
28 27
@@ -35,59 +34,47 @@ impl EditBuilder {
35 } 34 }
36 35
37 pub fn finish(self) -> Edit { 36 pub fn finish(self) -> Edit {
38 Edit { atoms: self.atoms } 37 let mut atoms = self.atoms;
39 } 38 atoms.sort_by_key(|a| a.delete.start());
40 39 for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) {
41 fn translate(&self, range: TextRange) -> TextRange { 40 assert!(a1.end() <= a2.start())
42 let mut range = range;
43 for atom in self.atoms.iter() {
44 range = atom.apply_to_range(range)
45 .expect("conflicting edits");
46 } 41 }
47 range 42 Edit { atoms }
48 } 43 }
49} 44}
50 45
51impl Edit { 46impl Edit {
47 pub fn into_atoms(self) -> Vec<AtomEdit> {
48 self.atoms
49 }
50
52 pub fn apply(&self, text: &str) -> String { 51 pub fn apply(&self, text: &str) -> String {
53 let mut text = text.to_owned(); 52 let mut total_len = text.len();
54 for atom in self.atoms.iter() { 53 for atom in self.atoms.iter() {
55 text = atom.apply(&text); 54 total_len += atom.insert.len();
55 total_len -= atom.end() - atom.start();
56 } 56 }
57 text 57 let mut buf = String::with_capacity(total_len);
58 let mut prev = 0;
59 for atom in self.atoms.iter() {
60 if atom.start() > prev {
61 buf.push_str(&text[prev..atom.start()]);
62 }
63 buf.push_str(&atom.insert);
64 prev = atom.end();
65 }
66 buf.push_str(&text[prev..text.len()]);
67 assert_eq!(buf.len(), total_len);
68 buf
58 } 69 }
59} 70}
60 71
61impl AtomEdit { 72impl AtomEdit {
62 fn apply(&self, text: &str) -> String { 73 fn start(&self) -> usize {
63 let prefix = &text[ 74 u32::from(self.delete.start()) as usize
64 TextRange::from_to(0.into(), self.delete.start())
65 ];
66 let suffix = &text[
67 TextRange::from_to(self.delete.end(), TextUnit::of_str(text))
68 ];
69 let mut res = String::with_capacity(prefix.len() + self.insert.len() + suffix.len());
70 res.push_str(prefix);
71 res.push_str(&self.insert);
72 res.push_str(suffix);
73 res
74 } 75 }
75 76
76 fn apply_to_position(&self, pos: TextUnit) -> Option<TextUnit> { 77 fn end(&self) -> usize {
77 if pos <= self.delete.start() { 78 u32::from(self.delete.end()) as usize
78 return Some(pos);
79 }
80 if pos < self.delete.end() {
81 return None;
82 }
83 Some(pos - self.delete.len() + TextUnit::of_str(&self.insert))
84 }
85
86 fn apply_to_range(&self, range: TextRange) -> Option<TextRange> {
87 Some(TextRange::from_to(
88 self.apply_to_position(range.start())?,
89 self.apply_to_position(range.end())?,
90 ))
91 } 79 }
92} 80}
93