diff options
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 305 |
2 files changed, 1 insertions, 308 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index d73ff158f..3c8c240cd 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -34,8 +34,6 @@ ra_analysis = { path = "../ra_analysis" } | |||
34 | gen_lsp_server = { path = "../gen_lsp_server" } | 34 | gen_lsp_server = { path = "../gen_lsp_server" } |
35 | ra_vfs = { path = "../ra_vfs" } | 35 | ra_vfs = { path = "../ra_vfs" } |
36 | 36 | ||
37 | proptest = "0.8.7" | ||
38 | |||
39 | [dev-dependencies] | 37 | [dev-dependencies] |
40 | tempdir = "0.3.7" | 38 | tempdir = "0.3.7" |
41 | test_utils = { path = "../test_utils" } \ No newline at end of file | 39 | test_utils = { path = "../test_utils" } |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 6d0ebbcd9..051f1f995 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -296,202 +296,6 @@ fn translate_offset_with_edit( | |||
296 | } | 296 | } |
297 | } | 297 | } |
298 | 298 | ||
299 | #[derive(Debug)] | ||
300 | struct OffsetNewlineIter<'a> { | ||
301 | text: &'a str, | ||
302 | offset: TextUnit, | ||
303 | } | ||
304 | |||
305 | impl<'a> Iterator for OffsetNewlineIter<'a> { | ||
306 | type Item = TextUnit; | ||
307 | fn next(&mut self) -> Option<TextUnit> { | ||
308 | let next_idx = self | ||
309 | .text | ||
310 | .char_indices() | ||
311 | .filter_map(|(i, c)| if c == '\n' { Some(i + 1) } else { None }) | ||
312 | .next()?; | ||
313 | let next = self.offset + TextUnit::from_usize(next_idx); | ||
314 | self.text = &self.text[next_idx..]; | ||
315 | self.offset = next; | ||
316 | Some(next) | ||
317 | } | ||
318 | } | ||
319 | |||
320 | #[derive(Debug, Clone, Copy, PartialEq)] | ||
321 | enum TranslatedPos { | ||
322 | Before, | ||
323 | After, | ||
324 | } | ||
325 | |||
326 | /// None means it was deleted | ||
327 | type TranslatedOffset = Option<(TranslatedPos, TextUnit)>; | ||
328 | |||
329 | fn translate_offset(offset: TextUnit, edit: &TranslatedAtomEdit) -> TranslatedOffset { | ||
330 | if offset <= edit.delete.start() { | ||
331 | Some((TranslatedPos::Before, offset)) | ||
332 | } else if offset <= edit.delete.end() { | ||
333 | None | ||
334 | } else { | ||
335 | let diff = edit.insert.len() as i64 - edit.delete.len().to_usize() as i64; | ||
336 | let after = TextUnit::from((offset.to_usize() as i64 + diff) as u32); | ||
337 | Some((TranslatedPos::After, after)) | ||
338 | } | ||
339 | } | ||
340 | |||
341 | trait TranslatedNewlineIterator { | ||
342 | fn translate(&self, offset: TextUnit) -> TextUnit; | ||
343 | fn translate_range(&self, range: TextRange) -> TextRange { | ||
344 | TextRange::from_to(self.translate(range.start()), self.translate(range.end())) | ||
345 | } | ||
346 | fn next_translated(&mut self) -> Option<TextUnit>; | ||
347 | fn boxed<'a>(self) -> Box<TranslatedNewlineIterator + 'a> | ||
348 | where | ||
349 | Self: 'a + Sized, | ||
350 | { | ||
351 | Box::new(self) | ||
352 | } | ||
353 | } | ||
354 | |||
355 | struct TranslatedAtomEdit<'a> { | ||
356 | delete: TextRange, | ||
357 | insert: &'a str, | ||
358 | } | ||
359 | |||
360 | struct TranslatedNewlines<'a, T: TranslatedNewlineIterator> { | ||
361 | inner: T, | ||
362 | next_inner: Option<TranslatedOffset>, | ||
363 | edit: TranslatedAtomEdit<'a>, | ||
364 | insert: OffsetNewlineIter<'a>, | ||
365 | } | ||
366 | |||
367 | impl<'a, T: TranslatedNewlineIterator> TranslatedNewlines<'a, T> { | ||
368 | fn from(inner: T, edit: &'a AtomTextEdit) -> Self { | ||
369 | let delete = inner.translate_range(edit.delete); | ||
370 | let mut res = TranslatedNewlines { | ||
371 | inner, | ||
372 | next_inner: None, | ||
373 | edit: TranslatedAtomEdit { | ||
374 | delete, | ||
375 | insert: &edit.insert, | ||
376 | }, | ||
377 | insert: OffsetNewlineIter { | ||
378 | offset: delete.start(), | ||
379 | text: &edit.insert, | ||
380 | }, | ||
381 | }; | ||
382 | // prepare next_inner | ||
383 | res.advance_inner(); | ||
384 | res | ||
385 | } | ||
386 | |||
387 | fn advance_inner(&mut self) { | ||
388 | self.next_inner = self | ||
389 | .inner | ||
390 | .next_translated() | ||
391 | .map(|x| translate_offset(x, &self.edit)); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | impl<'a, T: TranslatedNewlineIterator> TranslatedNewlineIterator for TranslatedNewlines<'a, T> { | ||
396 | fn translate(&self, offset: TextUnit) -> TextUnit { | ||
397 | let offset = self.inner.translate(offset); | ||
398 | let (_, offset) = | ||
399 | translate_offset(offset, &self.edit).expect("translate_unit returned None"); | ||
400 | offset | ||
401 | } | ||
402 | |||
403 | fn next_translated(&mut self) -> Option<TextUnit> { | ||
404 | match self.next_inner { | ||
405 | None => self.insert.next(), | ||
406 | Some(next) => match next { | ||
407 | None => self.insert.next().or_else(|| { | ||
408 | self.advance_inner(); | ||
409 | self.next_translated() | ||
410 | }), | ||
411 | Some((TranslatedPos::Before, next)) => { | ||
412 | self.advance_inner(); | ||
413 | Some(next) | ||
414 | } | ||
415 | Some((TranslatedPos::After, next)) => self.insert.next().or_else(|| { | ||
416 | self.advance_inner(); | ||
417 | Some(next) | ||
418 | }), | ||
419 | }, | ||
420 | } | ||
421 | } | ||
422 | } | ||
423 | |||
424 | impl<'a> Iterator for Box<dyn TranslatedNewlineIterator + 'a> { | ||
425 | type Item = TextUnit; | ||
426 | fn next(&mut self) -> Option<TextUnit> { | ||
427 | self.next_translated() | ||
428 | } | ||
429 | } | ||
430 | |||
431 | impl<T: TranslatedNewlineIterator + ?Sized> TranslatedNewlineIterator for Box<T> { | ||
432 | fn translate(&self, offset: TextUnit) -> TextUnit { | ||
433 | self.as_ref().translate(offset) | ||
434 | } | ||
435 | fn next_translated(&mut self) -> Option<TextUnit> { | ||
436 | self.as_mut().next_translated() | ||
437 | } | ||
438 | } | ||
439 | |||
440 | struct IteratorWrapper<T: Iterator<Item = TextUnit>>(T); | ||
441 | |||
442 | impl<T: Iterator<Item = TextUnit>> TranslatedNewlineIterator for IteratorWrapper<T> { | ||
443 | fn translate(&self, offset: TextUnit) -> TextUnit { | ||
444 | offset | ||
445 | } | ||
446 | fn next_translated(&mut self) -> Option<TextUnit> { | ||
447 | self.0.next() | ||
448 | } | ||
449 | } | ||
450 | |||
451 | impl<T: Iterator<Item = TextUnit>> Iterator for IteratorWrapper<T> { | ||
452 | type Item = TextUnit; | ||
453 | fn next(&mut self) -> Option<TextUnit> { | ||
454 | self.0.next() | ||
455 | } | ||
456 | } | ||
457 | |||
458 | fn translate_newlines<'a>( | ||
459 | mut newlines: Box<TranslatedNewlineIterator + 'a>, | ||
460 | edits: &'a [AtomTextEdit], | ||
461 | ) -> Box<TranslatedNewlineIterator + 'a> { | ||
462 | for edit in edits { | ||
463 | newlines = TranslatedNewlines::from(newlines, edit).boxed(); | ||
464 | } | ||
465 | newlines | ||
466 | } | ||
467 | |||
468 | #[allow(dead_code)] | ||
469 | fn translate_offset_with_edit_fast( | ||
470 | pre_edit_index: &LineIndex, | ||
471 | offset: TextUnit, | ||
472 | edits: &[AtomTextEdit], | ||
473 | ) -> LineCol { | ||
474 | // println!("{:?}", pre_edit_index.newlines()); | ||
475 | let mut newlines: Box<TranslatedNewlineIterator> = Box::new(IteratorWrapper( | ||
476 | pre_edit_index.newlines().iter().map(|x| *x), | ||
477 | )); | ||
478 | |||
479 | newlines = translate_newlines(newlines, edits); | ||
480 | |||
481 | let mut line = 0; | ||
482 | for n in newlines { | ||
483 | if n > offset { | ||
484 | break; | ||
485 | } | ||
486 | line += 1; | ||
487 | } | ||
488 | |||
489 | LineCol { | ||
490 | line: line, | ||
491 | col_utf16: 0, | ||
492 | } | ||
493 | } | ||
494 | |||
495 | impl TryConvWith for SourceFileEdit { | 299 | impl TryConvWith for SourceFileEdit { |
496 | type Ctx = ServerWorld; | 300 | type Ctx = ServerWorld; |
497 | type Output = TextDocumentEdit; | 301 | type Output = TextDocumentEdit; |
@@ -582,112 +386,3 @@ where | |||
582 | self.iter.next().map(|item| item.conv_with(self.ctx)) | 386 | self.iter.next().map(|item| item.conv_with(self.ctx)) |
583 | } | 387 | } |
584 | } | 388 | } |
585 | |||
586 | #[cfg(test)] | ||
587 | mod test { | ||
588 | use proptest::{prelude::*, proptest, proptest_helper}; | ||
589 | use super::*; | ||
590 | use ra_text_edit::test_utils::{arb_text, arb_offset, arb_edits}; | ||
591 | |||
592 | #[derive(Debug)] | ||
593 | struct ArbTextWithOffsetAndEdits { | ||
594 | text: String, | ||
595 | offset: TextUnit, | ||
596 | edits: Vec<AtomTextEdit>, | ||
597 | } | ||
598 | |||
599 | fn arb_text_with_offset_and_edits() -> BoxedStrategy<ArbTextWithOffsetAndEdits> { | ||
600 | arb_text() | ||
601 | .prop_flat_map(|text| { | ||
602 | (arb_offset(&text), arb_edits(&text), Just(text)).prop_map( | ||
603 | |(offset, edits, text)| ArbTextWithOffsetAndEdits { | ||
604 | text, | ||
605 | offset, | ||
606 | edits, | ||
607 | }, | ||
608 | ) | ||
609 | }) | ||
610 | .boxed() | ||
611 | } | ||
612 | |||
613 | fn edit_text(pre_edit_text: &str, mut edits: Vec<AtomTextEdit>) -> String { | ||
614 | // apply edits ordered from last to first | ||
615 | // since they should not overlap we can just use start() | ||
616 | edits.sort_by_key(|x| -(x.delete.start().to_usize() as isize)); | ||
617 | |||
618 | let mut text = pre_edit_text.to_owned(); | ||
619 | |||
620 | for edit in &edits { | ||
621 | let range = edit.delete.start().to_usize()..edit.delete.end().to_usize(); | ||
622 | text.replace_range(range, &edit.insert); | ||
623 | } | ||
624 | |||
625 | text | ||
626 | } | ||
627 | |||
628 | fn translate_after_edit( | ||
629 | pre_edit_text: &str, | ||
630 | offset: TextUnit, | ||
631 | edits: Vec<AtomTextEdit>, | ||
632 | ) -> LineCol { | ||
633 | let text = edit_text(pre_edit_text, edits); | ||
634 | let line_index = LineIndex::new(&text); | ||
635 | line_index.line_col(offset) | ||
636 | } | ||
637 | |||
638 | proptest! { | ||
639 | #[test] | ||
640 | fn test_translate_offset_with_edit(x in arb_text_with_offset_and_edits()) { | ||
641 | let line_index = LineIndex::new(&x.text); | ||
642 | let expected = translate_after_edit(&x.text, x.offset, x.edits.clone()); | ||
643 | let actual = translate_offset_with_edit_fast(&line_index, x.offset, &x.edits); | ||
644 | assert_eq!(actual.line, expected.line); | ||
645 | } | ||
646 | } | ||
647 | |||
648 | #[test] | ||
649 | fn test_translate_offset_with_edit_1() { | ||
650 | let x = ArbTextWithOffsetAndEdits { | ||
651 | text: "jbnan".to_owned(), | ||
652 | offset: 3.into(), | ||
653 | edits: vec![ | ||
654 | AtomTextEdit::delete(TextRange::from_to(1.into(), 3.into())), | ||
655 | AtomTextEdit::insert(4.into(), "\n".into()), | ||
656 | ], | ||
657 | }; | ||
658 | let line_index = LineIndex::new(&x.text); | ||
659 | let expected = translate_after_edit(&x.text, x.offset, x.edits.clone()); | ||
660 | let actual = translate_offset_with_edit_fast(&line_index, x.offset, &x.edits); | ||
661 | // assert_eq!(actual, expected); | ||
662 | assert_eq!(actual.line, expected.line); | ||
663 | } | ||
664 | |||
665 | #[test] | ||
666 | fn test_translate_offset_with_edit_2() { | ||
667 | let x = ArbTextWithOffsetAndEdits { | ||
668 | text: "aa\n".to_owned(), | ||
669 | offset: 1.into(), | ||
670 | edits: vec![AtomTextEdit::delete(TextRange::from_to(0.into(), 2.into()))], | ||
671 | }; | ||
672 | let line_index = LineIndex::new(&x.text); | ||
673 | let expected = translate_after_edit(&x.text, x.offset, x.edits.clone()); | ||
674 | let actual = translate_offset_with_edit_fast(&line_index, x.offset, &x.edits); | ||
675 | // assert_eq!(actual, expected); | ||
676 | assert_eq!(actual.line, expected.line); | ||
677 | } | ||
678 | |||
679 | #[test] | ||
680 | fn test_translate_offset_with_edit_3() { | ||
681 | let x = ArbTextWithOffsetAndEdits { | ||
682 | text: "".to_owned(), | ||
683 | offset: 0.into(), | ||
684 | edits: vec![AtomTextEdit::insert(0.into(), "\n".into())], | ||
685 | }; | ||
686 | let line_index = LineIndex::new(&x.text); | ||
687 | let expected = translate_after_edit(&x.text, x.offset, x.edits.clone()); | ||
688 | let actual = translate_offset_with_edit_fast(&line_index, x.offset, &x.edits); | ||
689 | // assert_eq!(actual, expected); | ||
690 | assert_eq!(actual.line, expected.line); | ||
691 | } | ||
692 | |||
693 | } | ||