diff options
author | Bernardo <[email protected]> | 2018-12-25 19:49:18 +0000 |
---|---|---|
committer | Bernardo <[email protected]> | 2018-12-25 19:49:18 +0000 |
commit | e9c186e48a77b536053c0f75ac9ea5b2fd322cfa (patch) | |
tree | 250b7f1c4b29e1ca009f6ff913733401caefdb2c /crates | |
parent | 863ed19946d6f707ce09dd77bf26b26be73e097c (diff) |
change to `TextEdit` to avoid allocation and sort
rename newline to step where applicable
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_editor/src/line_index_utils.rs | 86 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 10 | ||||
-rw-r--r-- | crates/ra_text_edit/src/test_utils.rs | 12 |
3 files changed, 51 insertions, 57 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 @@ | |||
1 | use ra_text_edit::AtomTextEdit; | 1 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
2 | use ra_syntax::{TextUnit, TextRange}; | 2 | use ra_syntax::{TextUnit, TextRange}; |
3 | use crate::{LineIndex, LineCol, line_index::Utf16Char}; | 3 | use crate::{LineIndex, LineCol, line_index::Utf16Char}; |
4 | use superslice::Ext; | ||
5 | 4 | ||
6 | #[derive(Debug, Clone)] | 5 | #[derive(Debug, Clone)] |
7 | enum Step { | 6 | enum Step { |
@@ -55,12 +54,12 @@ impl<'a> Iterator for LineIndexStepIter<'a> { | |||
55 | } | 54 | } |
56 | 55 | ||
57 | #[derive(Debug)] | 56 | #[derive(Debug)] |
58 | struct OffsetNewlineIter<'a> { | 57 | struct OffsetStepIter<'a> { |
59 | text: &'a str, | 58 | text: &'a str, |
60 | offset: TextUnit, | 59 | offset: TextUnit, |
61 | } | 60 | } |
62 | 61 | ||
63 | impl<'a> Iterator for OffsetNewlineIter<'a> { | 62 | impl<'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)] |
96 | enum NextNewlines<'a> { | 95 | enum 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 | ||
109 | struct Edits<'a, 'b> { | 108 | struct 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 | ||
115 | impl<'a, 'b> Edits<'a, 'b> { | 114 | impl<'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 { | |||
251 | pub fn translate_offset_with_edit( | 250 | pub 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 | } |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 63827aeea..5a911d9d2 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -235,13 +235,15 @@ impl TryConvWith for SourceChange { | |||
235 | None => None, | 235 | None => None, |
236 | Some(pos) => { | 236 | Some(pos) => { |
237 | let line_index = world.analysis().file_line_index(pos.file_id); | 237 | let line_index = world.analysis().file_line_index(pos.file_id); |
238 | let edits = self | 238 | let edit = self |
239 | .source_file_edits | 239 | .source_file_edits |
240 | .iter() | 240 | .iter() |
241 | .find(|it| it.file_id == pos.file_id) | 241 | .find(|it| it.file_id == pos.file_id) |
242 | .map(|it| it.edit.as_atoms()) | 242 | .map(|it| &it.edit); |
243 | .unwrap_or(&[]); | 243 | let line_col = match edit { |
244 | let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); | 244 | Some(edit) => translate_offset_with_edit(&*line_index, pos.offset, edit), |
245 | None => line_index.line_col(pos.offset), | ||
246 | }; | ||
245 | let position = | 247 | let position = |
246 | Position::new(u64::from(line_col.line), u64::from(line_col.col_utf16)); | 248 | Position::new(u64::from(line_col.line), u64::from(line_col.col_utf16)); |
247 | Some(TextDocumentPositionParams { | 249 | Some(TextDocumentPositionParams { |
diff --git a/crates/ra_text_edit/src/test_utils.rs b/crates/ra_text_edit/src/test_utils.rs index f0b8dfde1..745f21c93 100644 --- a/crates/ra_text_edit/src/test_utils.rs +++ b/crates/ra_text_edit/src/test_utils.rs | |||
@@ -69,17 +69,17 @@ pub fn arb_text_edit(text: &str) -> BoxedStrategy<TextEdit> { | |||
69 | } | 69 | } |
70 | 70 | ||
71 | #[derive(Debug, Clone)] | 71 | #[derive(Debug, Clone)] |
72 | pub struct ArbTextWithEdits { | 72 | pub struct ArbTextWithEdit { |
73 | pub text: String, | 73 | pub text: String, |
74 | pub edits: TextEdit, | 74 | pub edit: TextEdit, |
75 | } | 75 | } |
76 | 76 | ||
77 | pub fn arb_text_with_edits() -> BoxedStrategy<ArbTextWithEdits> { | 77 | pub fn arb_text_with_edit() -> BoxedStrategy<ArbTextWithEdit> { |
78 | let text = arb_text(); | 78 | let text = arb_text(); |
79 | text.prop_flat_map(|s| { | 79 | text.prop_flat_map(|s| { |
80 | let edits = arb_text_edit(&s); | 80 | let edit = arb_text_edit(&s); |
81 | (Just(s), edits) | 81 | (Just(s), edit) |
82 | }) | 82 | }) |
83 | .prop_map(|(text, edits)| ArbTextWithEdits { text, edits }) | 83 | .prop_map(|(text, edit)| ArbTextWithEdit { text, edit }) |
84 | .boxed() | 84 | .boxed() |
85 | } | 85 | } |