aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src/conv.rs
diff options
context:
space:
mode:
authorBernardo <[email protected]>2018-12-18 17:46:54 +0000
committerBernardo <[email protected]>2018-12-25 18:59:02 +0000
commit8c9df62c1c6a778a8df9ea028d1dce98c91c4d9d (patch)
tree0d4f3055025ca19b1b375a13b5e4ed1458d90afb /crates/ra_lsp_server/src/conv.rs
parent881c29192d39f657bf518baf399c47a5bfdc922f (diff)
move translate_offset_with_edit to ra_editor
Diffstat (limited to 'crates/ra_lsp_server/src/conv.rs')
-rw-r--r--crates/ra_lsp_server/src/conv.rs305
1 files changed, 0 insertions, 305 deletions
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)]
300struct OffsetNewlineIter<'a> {
301 text: &'a str,
302 offset: TextUnit,
303}
304
305impl<'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)]
321enum TranslatedPos {
322 Before,
323 After,
324}
325
326/// None means it was deleted
327type TranslatedOffset = Option<(TranslatedPos, TextUnit)>;
328
329fn 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
341trait 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
355struct TranslatedAtomEdit<'a> {
356 delete: TextRange,
357 insert: &'a str,
358}
359
360struct TranslatedNewlines<'a, T: TranslatedNewlineIterator> {
361 inner: T,
362 next_inner: Option<TranslatedOffset>,
363 edit: TranslatedAtomEdit<'a>,
364 insert: OffsetNewlineIter<'a>,
365}
366
367impl<'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
395impl<'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
424impl<'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
431impl<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
440struct IteratorWrapper<T: Iterator<Item = TextUnit>>(T);
441
442impl<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
451impl<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
458fn 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)]
469fn 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
495impl TryConvWith for SourceFileEdit { 299impl 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)]
587mod 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}