1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
use {TextRange, TextUnit};
#[derive(Debug)]
pub struct Edit {
pub atoms: Vec<AtomEdit>,
}
#[derive(Debug)]
pub struct AtomEdit {
pub delete: TextRange,
pub insert: String,
}
#[derive(Debug)]
pub struct EditBuilder {
atoms: Vec<AtomEdit>
}
impl EditBuilder {
pub fn new() -> EditBuilder {
EditBuilder { atoms: Vec::new() }
}
pub fn replace(&mut self, range: TextRange, replacement: String) {
let range = self.translate(range);
self.atoms.push(AtomEdit { delete: range, insert: replacement })
}
pub fn delete(&mut self, range: TextRange) {
self.replace(range, String::new());
}
pub fn insert(&mut self, offset: TextUnit, text: String) {
self.replace(TextRange::offset_len(offset, 0.into()), text)
}
pub fn finish(self) -> Edit {
Edit { atoms: self.atoms }
}
fn translate(&self, range: TextRange) -> TextRange {
let mut range = range;
for atom in self.atoms.iter() {
range = atom.apply_to_range(range)
.expect("conflicting edits");
}
range
}
}
impl Edit {
pub fn apply(&self, text: &str) -> String {
let mut text = text.to_owned();
for atom in self.atoms.iter() {
text = atom.apply(&text);
}
text
}
}
impl AtomEdit {
fn apply(&self, text: &str) -> String {
let prefix = &text[
TextRange::from_to(0.into(), self.delete.start())
];
let suffix = &text[
TextRange::from_to(self.delete.end(), TextUnit::of_str(text))
];
let mut res = String::with_capacity(prefix.len() + self.insert.len() + suffix.len());
res.push_str(prefix);
res.push_str(&self.insert);
res.push_str(suffix);
res
}
fn apply_to_position(&self, pos: TextUnit) -> Option<TextUnit> {
if pos <= self.delete.start() {
return Some(pos);
}
if pos < self.delete.end() {
return None;
}
Some(pos - self.delete.len() + TextUnit::of_str(&self.insert))
}
fn apply_to_range(&self, range: TextRange) -> Option<TextRange> {
Some(TextRange::from_to(
self.apply_to_position(range.start())?,
self.apply_to_position(range.end())?,
))
}
}
|