aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
authorBernardo <[email protected]>2018-12-21 17:51:31 +0000
committerBernardo <[email protected]>2018-12-25 19:03:14 +0000
commitd6312085a1ac97030fa768366585b9cfb6c955cd (patch)
treebdd36cd3efd76fc3a1561847ed66ccece7b75303 /crates/ra_editor/src
parenta005d2a614031a18c9a5bf6557789a41f1b25c31 (diff)
remove slower impl, add benchmarks
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/lib.rs4
-rw-r--r--crates/ra_editor/src/line_index_utils.rs218
2 files changed, 23 insertions, 199 deletions
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index 619497f0b..7145c6cfb 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -2,7 +2,8 @@ mod code_actions;
2mod extend_selection; 2mod extend_selection;
3mod folding_ranges; 3mod folding_ranges;
4mod line_index; 4mod line_index;
5mod line_index_utils; 5// public for benchmarkig
6pub mod line_index_utils;
6mod symbols; 7mod symbols;
7#[cfg(test)] 8#[cfg(test)]
8mod test_utils; 9mod test_utils;
@@ -13,7 +14,6 @@ pub use self::{
13 extend_selection::extend_selection, 14 extend_selection::extend_selection,
14 folding_ranges::{folding_ranges, Fold, FoldKind}, 15 folding_ranges::{folding_ranges, Fold, FoldKind},
15 line_index::{LineCol, LineIndex}, 16 line_index::{LineCol, LineIndex},
16 line_index_utils::translate_offset_with_edit,
17 symbols::{file_structure, file_symbols, FileSymbol, StructureNode}, 17 symbols::{file_structure, file_symbols, FileSymbol, StructureNode},
18 typing::{join_lines, on_enter, on_eq_typed}, 18 typing::{join_lines, on_enter, on_eq_typed},
19}; 19};
diff --git a/crates/ra_editor/src/line_index_utils.rs b/crates/ra_editor/src/line_index_utils.rs
index 5ce2446c1..e62c5089d 100644
--- a/crates/ra_editor/src/line_index_utils.rs
+++ b/crates/ra_editor/src/line_index_utils.rs
@@ -25,136 +25,6 @@ impl<'a> Iterator for OffsetNewlineIter<'a> {
25} 25}
26 26
27#[derive(Debug)] 27#[derive(Debug)]
28struct AltEdit<'a> {
29 insert_newlines: OffsetNewlineIter<'a>,
30 delete: TextRange,
31 diff: i64,
32}
33
34fn translate_range_by(range: TextRange, diff: i64) -> TextRange {
35 if diff == 0 {
36 range
37 } else {
38 let start = translate_by(range.start(), diff);
39 let end = translate_by(range.end(), diff);
40 TextRange::from_to(start, end)
41 }
42}
43
44fn translate_by(x: TextUnit, diff: i64) -> TextUnit {
45 if diff == 0 {
46 x
47 } else {
48 TextUnit::from((x.to_usize() as i64 + diff) as u32)
49 }
50}
51
52fn to_alt_edits<'a>(offset: TextUnit, edits: &'a [AtomTextEdit]) -> Vec<AltEdit<'a>> {
53 let mut xs: Vec<AltEdit<'a>> = Vec::with_capacity(edits.len());
54 // collect and sort edits
55 for edit in edits {
56 // TODO discard after translating?
57 // if edit.delete.start() >= offset {
58 // continue;
59 // }
60 let insert_index = xs.upper_bound_by_key(&edit.delete.start(), |x| x.delete.start());
61 let diff = edit.insert.len() as i64 - edit.delete.len().to_usize() as i64;
62 xs.insert(
63 insert_index,
64 AltEdit {
65 insert_newlines: OffsetNewlineIter {
66 offset: edit.delete.start(),
67 text: &edit.insert,
68 },
69 delete: edit.delete,
70 diff: diff,
71 },
72 );
73 }
74 // translate edits by previous edits
75 for i in 1..xs.len() {
76 let (x, prevs) = xs[0..=i].split_last_mut().unwrap();
77 for prev in prevs {
78 x.delete = translate_range_by(x.delete, prev.diff);
79 x.insert_newlines.offset = translate_by(x.insert_newlines.offset, prev.diff);
80 }
81 }
82 xs
83}
84
85#[derive(Debug)]
86enum NextNewline {
87 Use,
88 Discard,
89 Replace(TextUnit),
90 New(TextUnit),
91}
92
93fn next_newline(candidate: Option<TextUnit>, edits: &mut [AltEdit]) -> NextNewline {
94 let mut candidate = match candidate {
95 None => {
96 for edit in edits {
97 if let Some(inserted) = edit.insert_newlines.next() {
98 return NextNewline::New(inserted);
99 }
100 }
101 return NextNewline::Use; // END
102 }
103 Some(x) => x,
104 };
105
106 for edit in edits {
107 if candidate <= edit.delete.start() {
108 return NextNewline::Replace(candidate);
109 } else if candidate <= edit.delete.end() {
110 return match edit.insert_newlines.next() {
111 Some(x) => NextNewline::Replace(x),
112 None => NextNewline::Discard,
113 };
114 } else {
115 if let Some(inserted) = edit.insert_newlines.next() {
116 return NextNewline::New(inserted);
117 }
118 candidate = translate_by(candidate, edit.diff);
119 }
120 }
121 return NextNewline::Replace(candidate);
122}
123
124pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 {
125 let mut edits = to_alt_edits(offset, edits);
126 let mut orig_newlines = line_index.newlines().iter().map(|x| *x).peekable();
127
128 let mut count = 0;
129
130 loop {
131 let res = next_newline(orig_newlines.peek().map(|x| *x), &mut edits);
132 let next = match res {
133 NextNewline::Use => orig_newlines.next(),
134 NextNewline::Discard => {
135 orig_newlines.next();
136 continue;
137 }
138 NextNewline::Replace(new) => {
139 orig_newlines.next();
140 Some(new)
141 }
142 NextNewline::New(new) => Some(new),
143 };
144 match next {
145 Some(n) if n <= offset => {
146 count += 1;
147 }
148 _ => {
149 break;
150 }
151 }
152 }
153
154 count
155}
156
157#[derive(Debug)]
158enum NextNewlines<'a> { 28enum NextNewlines<'a> {
159 Use, 29 Use,
160 ReplaceMany(OffsetNewlineIter<'a>), 30 ReplaceMany(OffsetNewlineIter<'a>),
@@ -188,7 +58,7 @@ impl<'a, 'b> Edits<'a, 'b> {
188 self.acc_diff += self.current.as_ref().map_or(0, |x| x.diff); 58 self.acc_diff += self.current.as_ref().map_or(0, |x| x.diff);
189 match self.edits.split_first() { 59 match self.edits.split_first() {
190 Some((next, rest)) => { 60 Some((next, rest)) => {
191 let delete = translate_range_by(next.delete, self.acc_diff); 61 let delete = self.translate_range(next.delete);
192 let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64; 62 let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64;
193 self.current = Some(TranslatedEdit { 63 self.current = Some(TranslatedEdit {
194 delete, 64 delete,
@@ -241,9 +111,27 @@ impl<'a, 'b> Edits<'a, 'b> {
241 }; 111 };
242 res 112 res
243 } 113 }
114
115 fn translate_range(&self, range: TextRange) -> TextRange {
116 if self.acc_diff == 0 {
117 range
118 } else {
119 let start = self.translate(range.start());
120 let end = self.translate(range.end());
121 TextRange::from_to(start, end)
122 }
123 }
124
125 fn translate(&self, x: TextUnit) -> TextUnit {
126 if self.acc_diff == 0 {
127 x
128 } else {
129 TextUnit::from((x.to_usize() as i64 + self.acc_diff) as u32)
130 }
131 }
244} 132}
245 133
246pub fn count_newlines_alt(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 { 134pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 {
247 let mut sorted_edits: Vec<&AtomTextEdit> = Vec::with_capacity(edits.len()); 135 let mut sorted_edits: Vec<&AtomTextEdit> = Vec::with_capacity(edits.len());
248 for edit in edits { 136 for edit in edits {
249 let insert_index = 137 let insert_index =
@@ -257,7 +145,7 @@ pub fn count_newlines_alt(offset: TextUnit, line_index: &LineIndex, edits: &[Ato
257 145
258 for &orig_newline in line_index.newlines() { 146 for &orig_newline in line_index.newlines() {
259 loop { 147 loop {
260 let translated_newline = translate_by(orig_newline, state.acc_diff); 148 let translated_newline = state.translate(orig_newline);
261 match state.next_newlines(translated_newline) { 149 match state.next_newlines(translated_newline) {
262 NextNewlines::Use => { 150 NextNewlines::Use => {
263 if offset < translated_newline { 151 if offset < translated_newline {
@@ -369,69 +257,5 @@ mod test {
369 let actual_lines = count_newlines(x.offset, &line_index, &x.edits); 257 let actual_lines = count_newlines(x.offset, &line_index, &x.edits);
370 assert_eq!(actual_lines, expected.line); 258 assert_eq!(actual_lines, expected.line);
371 } 259 }
372
373 #[test]
374 fn test_translate_offset_with_edit_alt(x in arb_text_with_offset_and_edits()) {
375 let line_index = LineIndex::new(&x.text);
376 let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
377 let actual_lines = count_newlines_alt(x.offset, &line_index, &x.edits);
378 assert_eq!(actual_lines, expected.line);
379 }
380 }
381
382 #[test]
383 fn test_translate_offset_with_edit_alt_1() {
384 let x = ArbTextWithOffsetAndEdits {
385 text: String::from("aA\n"),
386 offset: 2.into(),
387 edits: vec![AtomTextEdit::delete(TextRange::from_to(1.into(), 2.into()))],
388 };
389 let line_index = LineIndex::new(&x.text);
390 let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
391 let actual_lines = count_newlines_alt(x.offset, &line_index, &x.edits);
392 assert_eq!(actual_lines, expected.line);
393 }
394
395 #[test]
396 fn test_translate_offset_with_edit_alt_2() {
397 let x = ArbTextWithOffsetAndEdits {
398 text: String::from("\nqꀸ#"),
399 offset: 5.into(),
400 edits: vec![AtomTextEdit::insert(1.into(), "\n".into())],
401 };
402 let line_index = LineIndex::new(&x.text);
403 let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
404 let actual_lines = count_newlines_alt(x.offset, &line_index, &x.edits);
405 assert_eq!(actual_lines, expected.line);
406 }
407
408 #[test]
409 fn test_translate_offset_with_edit_alt_3() {
410 let x = ArbTextWithOffsetAndEdits {
411 text: String::from("\n\n\n"),
412 offset: 0.into(),
413 edits: vec![AtomTextEdit::delete(TextRange::from_to(0.into(), 2.into()))],
414 };
415 let line_index = LineIndex::new(&x.text);
416 let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
417 let actual_lines = count_newlines_alt(x.offset, &line_index, &x.edits);
418 assert_eq!(actual_lines, expected.line);
419 } 260 }
420
421 #[test]
422 fn test_translate_offset_with_edit_alt_4() {
423 let x = ArbTextWithOffsetAndEdits {
424 text: String::from("☻54翑\"A"),
425 offset: 5.into(),
426 edits: vec![
427 AtomTextEdit::delete(TextRange::from_to(0.into(), 8.into())),
428 AtomTextEdit::insert(9.into(), String::from("\n")),
429 ],
430 };
431 let line_index = LineIndex::new(&x.text);
432 let expected = translate_after_edit(&x.text, x.offset, x.edits.clone());
433 let actual_lines = count_newlines_alt(x.offset, &line_index, &x.edits);
434 assert_eq!(actual_lines, expected.line);
435 }
436
437} 261}