aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/edit.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-12 16:50:16 +0100
committerAleksey Kladov <[email protected]>2018-08-12 16:50:16 +0100
commit66be735aa98c32fb062d1c756fa9303ff2d13002 (patch)
treed679bef9b4005f969cfa5a369c6804195de6c779 /crates/libeditor/src/edit.rs
parent56aa6e20e0279c69e0130905573b1607056cfaf9 (diff)
flip comma
Diffstat (limited to 'crates/libeditor/src/edit.rs')
-rw-r--r--crates/libeditor/src/edit.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/crates/libeditor/src/edit.rs b/crates/libeditor/src/edit.rs
new file mode 100644
index 000000000..163ecf6de
--- /dev/null
+++ b/crates/libeditor/src/edit.rs
@@ -0,0 +1,93 @@
1use {TextRange, TextUnit};
2
3#[derive(Debug)]
4pub struct Edit {
5 pub atoms: Vec<AtomEdit>,
6}
7
8#[derive(Debug)]
9pub struct AtomEdit {
10 pub delete: TextRange,
11 pub insert: String,
12}
13
14#[derive(Debug)]
15pub struct EditBuilder {
16 atoms: Vec<AtomEdit>
17}
18
19impl EditBuilder {
20 pub fn new() -> EditBuilder {
21 EditBuilder { atoms: Vec::new() }
22 }
23
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 })
27 }
28
29 pub fn delete(&mut self, range: TextRange) {
30 self.replace(range, String::new());
31 }
32
33 pub fn insert(&mut self, offset: TextUnit, text: String) {
34 self.replace(TextRange::offset_len(offset, 0.into()), text)
35 }
36
37 pub fn finish(self) -> Edit {
38 Edit { atoms: self.atoms }
39 }
40
41 fn translate(&self, range: TextRange) -> TextRange {
42 let mut range = range;
43 for atom in self.atoms.iter() {
44 range = atom.apply_to_range(range)
45 .expect("conflicting edits");
46 }
47 range
48 }
49}
50
51impl Edit {
52 pub fn apply(&self, text: &str) -> String {
53 let mut text = text.to_owned();
54 for atom in self.atoms.iter() {
55 text = atom.apply(&text);
56 }
57 text
58 }
59}
60
61impl AtomEdit {
62 fn apply(&self, text: &str) -> String {
63 let prefix = &text[
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
76 fn apply_to_position(&self, pos: TextUnit) -> Option<TextUnit> {
77 if pos <= self.delete.start() {
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 }
92}
93