diff options
Diffstat (limited to 'crates/libeditor/src/edit.rs')
-rw-r--r-- | crates/libeditor/src/edit.rs | 75 |
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 @@ | |||
1 | use {TextRange, TextUnit}; | 1 | use {TextRange, TextUnit}; |
2 | 2 | ||
3 | #[derive(Debug)] | 3 | #[derive(Debug, Clone)] |
4 | pub struct Edit { | 4 | pub struct Edit { |
5 | pub atoms: Vec<AtomEdit>, | 5 | atoms: Vec<AtomEdit>, |
6 | } | 6 | } |
7 | 7 | ||
8 | #[derive(Debug)] | 8 | #[derive(Debug, Clone)] |
9 | pub struct AtomEdit { | 9 | pub 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 | ||
51 | impl Edit { | 46 | impl 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 | ||
61 | impl AtomEdit { | 72 | impl 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 | |||