aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/line_index_utils.rs86
1 files changed, 39 insertions, 47 deletions
diff --git a/crates/ra_editor/src/line_index_utils.rs b/crates/ra_editor/src/line_index_utils.rs
index b8b149442..ec3269bbb 100644
--- a/crates/ra_editor/src/line_index_utils.rs
+++ b/crates/ra_editor/src/line_index_utils.rs
@@ -1,7 +1,6 @@
1use ra_text_edit::AtomTextEdit; 1use ra_text_edit::{AtomTextEdit, TextEdit};
2use ra_syntax::{TextUnit, TextRange}; 2use ra_syntax::{TextUnit, TextRange};
3use crate::{LineIndex, LineCol, line_index::Utf16Char}; 3use crate::{LineIndex, LineCol, line_index::Utf16Char};
4use superslice::Ext;
5 4
6#[derive(Debug, Clone)] 5#[derive(Debug, Clone)]
7enum Step { 6enum Step {
@@ -55,12 +54,12 @@ impl<'a> Iterator for LineIndexStepIter<'a> {
55} 54}
56 55
57#[derive(Debug)] 56#[derive(Debug)]
58struct OffsetNewlineIter<'a> { 57struct OffsetStepIter<'a> {
59 text: &'a str, 58 text: &'a str,
60 offset: TextUnit, 59 offset: TextUnit,
61} 60}
62 61
63impl<'a> Iterator for OffsetNewlineIter<'a> { 62impl<'a> Iterator for OffsetStepIter<'a> {
64 type Item = Step; 63 type Item = Step;
65 fn next(&mut self) -> Option<Step> { 64 fn next(&mut self) -> Option<Step> {
66 let (next, next_offset) = self 65 let (next, next_offset) = self
@@ -93,10 +92,10 @@ impl<'a> Iterator for OffsetNewlineIter<'a> {
93} 92}
94 93
95#[derive(Debug)] 94#[derive(Debug)]
96enum NextNewlines<'a> { 95enum NextSteps<'a> {
97 Use, 96 Use,
98 ReplaceMany(OffsetNewlineIter<'a>), 97 ReplaceMany(OffsetStepIter<'a>),
99 AddMany(OffsetNewlineIter<'a>), 98 AddMany(OffsetStepIter<'a>),
100} 99}
101 100
102#[derive(Debug)] 101#[derive(Debug)]
@@ -106,16 +105,16 @@ struct TranslatedEdit<'a> {
106 diff: i64, 105 diff: i64,
107} 106}
108 107
109struct Edits<'a, 'b> { 108struct Edits<'a> {
110 edits: &'b [&'a AtomTextEdit], 109 edits: &'a [AtomTextEdit],
111 current: Option<TranslatedEdit<'a>>, 110 current: Option<TranslatedEdit<'a>>,
112 acc_diff: i64, 111 acc_diff: i64,
113} 112}
114 113
115impl<'a, 'b> Edits<'a, 'b> { 114impl<'a> Edits<'a> {
116 fn new(sorted_edits: &'b [&'a AtomTextEdit]) -> Edits<'a, 'b> { 115 fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> {
117 let mut x = Edits { 116 let mut x = Edits {
118 edits: sorted_edits, 117 edits: text_edit.as_atoms(),
119 current: None, 118 current: None,
120 acc_diff: 0, 119 acc_diff: 0,
121 }; 120 };
@@ -141,9 +140,9 @@ impl<'a, 'b> Edits<'a, 'b> {
141 } 140 }
142 } 141 }
143 142
144 fn next_inserted_newlines(&mut self) -> Option<OffsetNewlineIter<'a>> { 143 fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> {
145 let cur = self.current.as_ref()?; 144 let cur = self.current.as_ref()?;
146 let res = Some(OffsetNewlineIter { 145 let res = Some(OffsetStepIter {
147 offset: cur.delete.start(), 146 offset: cur.delete.start(),
148 text: &cur.insert, 147 text: &cur.insert,
149 }); 148 });
@@ -151,7 +150,7 @@ impl<'a, 'b> Edits<'a, 'b> {
151 res 150 res
152 } 151 }
153 152
154 fn next_step(&mut self, step: &Step) -> NextNewlines { 153 fn next_steps(&mut self, step: &Step) -> NextSteps {
155 let step_pos = match step { 154 let step_pos = match step {
156 &Step::Newline(n) => n, 155 &Step::Newline(n) => n,
157 &Step::Utf16Char(r) => r.end(), 156 &Step::Utf16Char(r) => r.end(),
@@ -159,27 +158,27 @@ impl<'a, 'b> Edits<'a, 'b> {
159 let res = match &mut self.current { 158 let res = match &mut self.current {
160 Some(edit) => { 159 Some(edit) => {
161 if step_pos <= edit.delete.start() { 160 if step_pos <= edit.delete.start() {
162 NextNewlines::Use 161 NextSteps::Use
163 } else if step_pos <= edit.delete.end() { 162 } else if step_pos <= edit.delete.end() {
164 let iter = OffsetNewlineIter { 163 let iter = OffsetStepIter {
165 offset: edit.delete.start(), 164 offset: edit.delete.start(),
166 text: &edit.insert, 165 text: &edit.insert,
167 }; 166 };
168 // empty slice 167 // empty slice to avoid returning steps again
169 edit.insert = &edit.insert[edit.insert.len()..]; 168 edit.insert = &edit.insert[edit.insert.len()..];
170 NextNewlines::ReplaceMany(iter) 169 NextSteps::ReplaceMany(iter)
171 } else { 170 } else {
172 let iter = OffsetNewlineIter { 171 let iter = OffsetStepIter {
173 offset: edit.delete.start(), 172 offset: edit.delete.start(),
174 text: &edit.insert, 173 text: &edit.insert,
175 }; 174 };
176 // empty slice 175 // empty slice to avoid returning steps again
177 edit.insert = &edit.insert[edit.insert.len()..]; 176 edit.insert = &edit.insert[edit.insert.len()..];
178 self.advance_edit(); 177 self.advance_edit();
179 NextNewlines::AddMany(iter) 178 NextSteps::AddMany(iter)
180 } 179 }
181 } 180 }
182 None => NextNewlines::Use, 181 None => NextSteps::Use,
183 }; 182 };
184 res 183 res
185 } 184 }
@@ -251,16 +250,9 @@ impl RunningLineCol {
251pub fn translate_offset_with_edit( 250pub fn translate_offset_with_edit(
252 line_index: &LineIndex, 251 line_index: &LineIndex,
253 offset: TextUnit, 252 offset: TextUnit,
254 edits: &[AtomTextEdit], 253 text_edit: &TextEdit,
255) -> LineCol { 254) -> LineCol {
256 let mut sorted_edits: Vec<&AtomTextEdit> = Vec::with_capacity(edits.len()); 255 let mut state = Edits::from_text_edit(&text_edit);
257 for edit in edits {
258 let insert_index =
259 sorted_edits.upper_bound_by_key(&edit.delete.start(), |x| x.delete.start());
260 sorted_edits.insert(insert_index, &edit);
261 }
262
263 let mut state = Edits::new(&sorted_edits);
264 256
265 let mut res = RunningLineCol::new(); 257 let mut res = RunningLineCol::new();
266 258
@@ -291,18 +283,18 @@ pub fn translate_offset_with_edit(
291 for orig_step in LineIndexStepIter::from(line_index) { 283 for orig_step in LineIndexStepIter::from(line_index) {
292 loop { 284 loop {
293 let translated_step = state.translate_step(&orig_step); 285 let translated_step = state.translate_step(&orig_step);
294 match state.next_step(&translated_step) { 286 match state.next_steps(&translated_step) {
295 NextNewlines::Use => { 287 NextSteps::Use => {
296 test_step!(translated_step); 288 test_step!(translated_step);
297 break; 289 break;
298 } 290 }
299 NextNewlines::ReplaceMany(ns) => { 291 NextSteps::ReplaceMany(ns) => {
300 for n in ns { 292 for n in ns {
301 test_step!(n); 293 test_step!(n);
302 } 294 }
303 break; 295 break;
304 } 296 }
305 NextNewlines::AddMany(ns) => { 297 NextSteps::AddMany(ns) => {
306 for n in ns { 298 for n in ns {
307 test_step!(n); 299 test_step!(n);
308 } 300 }
@@ -312,7 +304,7 @@ pub fn translate_offset_with_edit(
312 } 304 }
313 305
314 loop { 306 loop {
315 match state.next_inserted_newlines() { 307 match state.next_inserted_steps() {
316 None => break, 308 None => break,
317 Some(ns) => { 309 Some(ns) => {
318 for n in ns { 310 for n in ns {
@@ -330,26 +322,26 @@ mod test {
330 use super::*; 322 use super::*;
331 use proptest::{prelude::*, proptest, proptest_helper}; 323 use proptest::{prelude::*, proptest, proptest_helper};
332 use crate::line_index; 324 use crate::line_index;
333 use ra_text_edit::test_utils::{arb_offset, arb_text_with_edits}; 325 use ra_text_edit::test_utils::{arb_offset, arb_text_with_edit};
334 use ra_text_edit::TextEdit; 326 use ra_text_edit::TextEdit;
335 327
336 #[derive(Debug)] 328 #[derive(Debug)]
337 struct ArbTextWithOffsetAndEdits { 329 struct ArbTextWithEditAndOffset {
338 text: String, 330 text: String,
339 edits: TextEdit, 331 edit: TextEdit,
340 edited_text: String, 332 edited_text: String,
341 offset: TextUnit, 333 offset: TextUnit,
342 } 334 }
343 335
344 fn arb_text_with_edits_and_offset() -> BoxedStrategy<ArbTextWithOffsetAndEdits> { 336 fn arb_text_with_edit_and_offset() -> BoxedStrategy<ArbTextWithEditAndOffset> {
345 arb_text_with_edits() 337 arb_text_with_edit()
346 .prop_flat_map(|x| { 338 .prop_flat_map(|x| {
347 let edited_text = x.edits.apply(&x.text); 339 let edited_text = x.edit.apply(&x.text);
348 let arb_offset = arb_offset(&edited_text); 340 let arb_offset = arb_offset(&edited_text);
349 (Just(x), Just(edited_text), arb_offset).prop_map(|(x, edited_text, offset)| { 341 (Just(x), Just(edited_text), arb_offset).prop_map(|(x, edited_text, offset)| {
350 ArbTextWithOffsetAndEdits { 342 ArbTextWithEditAndOffset {
351 text: x.text, 343 text: x.text,
352 edits: x.edits, 344 edit: x.edit,
353 edited_text, 345 edited_text,
354 offset, 346 offset,
355 } 347 }
@@ -360,10 +352,10 @@ mod test {
360 352
361 proptest! { 353 proptest! {
362 #[test] 354 #[test]
363 fn test_translate_offset_with_edit(x in arb_text_with_edits_and_offset()) { 355 fn test_translate_offset_with_edit(x in arb_text_with_edit_and_offset()) {
364 let expected = line_index::to_line_col(&x.edited_text, x.offset); 356 let expected = line_index::to_line_col(&x.edited_text, x.offset);
365 let line_index = LineIndex::new(&x.text); 357 let line_index = LineIndex::new(&x.text);
366 let actual = translate_offset_with_edit(&line_index, x.offset, x.edits.as_atoms()); 358 let actual = translate_offset_with_edit(&line_index, x.offset, &x.edit);
367 359
368 assert_eq!(actual, expected); 360 assert_eq!(actual, expected);
369 } 361 }