aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/algo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src/algo.rs')
-rw-r--r--crates/syntax/src/algo.rs125
1 files changed, 89 insertions, 36 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 30adb7217..320c430c9 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -111,18 +111,28 @@ pub enum InsertPosition<T> {
111 111
112type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>; 112type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
113 113
114#[derive(Debug, Hash, PartialEq, Eq)]
115enum TreeDiffInsertPos {
116 After(SyntaxElement),
117 AsFirstChild(SyntaxElement),
118}
119
114#[derive(Debug)] 120#[derive(Debug)]
115pub struct TreeDiff { 121pub struct TreeDiff {
116 replacements: FxHashMap<SyntaxElement, SyntaxElement>, 122 replacements: FxHashMap<SyntaxElement, SyntaxElement>,
117 deletions: Vec<SyntaxElement>, 123 deletions: Vec<SyntaxElement>,
118 // the vec as well as the indexmap are both here to preserve order 124 // the vec as well as the indexmap are both here to preserve order
119 insertions: FxIndexMap<SyntaxElement, Vec<SyntaxElement>>, 125 insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
120} 126}
121 127
122impl TreeDiff { 128impl TreeDiff {
123 pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { 129 pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
124 for (anchor, to) in self.insertions.iter() { 130 for (anchor, to) in self.insertions.iter() {
125 to.iter().for_each(|to| builder.insert(anchor.text_range().end(), to.to_string())); 131 let offset = match anchor {
132 TreeDiffInsertPos::After(it) => it.text_range().end(),
133 TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
134 };
135 to.iter().for_each(|to| builder.insert(offset, to.to_string()));
126 } 136 }
127 for (from, to) in self.replacements.iter() { 137 for (from, to) in self.replacements.iter() {
128 builder.replace(from.text_range(), to.to_string()) 138 builder.replace(from.text_range(), to.to_string())
@@ -188,19 +198,20 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
188 let lhs_child = lhs_children.next(); 198 let lhs_child = lhs_children.next();
189 match (lhs_child.clone(), rhs_children.next()) { 199 match (lhs_child.clone(), rhs_children.next()) {
190 (None, None) => break, 200 (None, None) => break,
191 (None, Some(element)) => match last_lhs.clone() { 201 (None, Some(element)) => {
192 Some(prev) => { 202 let insert_pos = match last_lhs.clone() {
193 mark::hit!(diff_insert); 203 Some(prev) => {
194 diff.insertions.entry(prev).or_insert_with(Vec::new).push(element); 204 mark::hit!(diff_insert);
195 } 205 TreeDiffInsertPos::After(prev)
196 // first iteration, this means we got no anchor element to insert after 206 }
197 // therefor replace the parent node instead 207 // first iteration, insert into out parent as the first child
198 None => { 208 None => {
199 mark::hit!(diff_replace_parent); 209 mark::hit!(diff_insert_as_first_child);
200 diff.replacements.insert(lhs.clone().into(), rhs.clone().into()); 210 TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
201 break; 211 }
202 } 212 };
203 }, 213 diff.insertions.entry(insert_pos).or_insert_with(Vec::new).push(element);
214 }
204 (Some(element), None) => { 215 (Some(element), None) => {
205 mark::hit!(diff_delete); 216 mark::hit!(diff_delete);
206 diff.deletions.push(element); 217 diff.deletions.push(element);
@@ -224,8 +235,15 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
224 } 235 }
225 } 236 }
226 let drain = look_ahead_scratch.drain(..); 237 let drain = look_ahead_scratch.drain(..);
227 if let Some(prev) = last_lhs.clone().filter(|_| insert) { 238 if insert {
228 diff.insertions.entry(prev).or_insert_with(Vec::new).extend(drain); 239 let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
240 TreeDiffInsertPos::After(prev)
241 } else {
242 mark::hit!(insert_first_child);
243 TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
244 };
245
246 diff.insertions.entry(insert_pos).or_insert_with(Vec::new).extend(drain);
229 rhs_children = rhs_children_clone; 247 rhs_children = rhs_children_clone;
230 } else { 248 } else {
231 go(diff, lhs_ele, rhs_ele) 249 go(diff, lhs_ele, rhs_ele)
@@ -632,18 +650,19 @@ mod tests {
632 650
633 #[test] 651 #[test]
634 fn replace_parent() { 652 fn replace_parent() {
635 mark::check!(diff_replace_parent); 653 mark::check!(diff_insert_as_first_child);
636 check_diff( 654 check_diff(
637 r#""#, 655 r#""#,
638 r#"use foo::bar;"#, 656 r#"use foo::bar;"#,
639 expect![[r#" 657 expect![[r#"
640 insertions: 658 insertions:
641 659
642 660 Line 0: AsFirstChild(Node([email protected]))
661 -> use foo::bar;
643 662
644 replacements: 663 replacements:
645 664
646 Line 0: Node([email protected]) -> use foo::bar; 665
647 666
648 deletions: 667 deletions:
649 668
@@ -666,7 +685,7 @@ use baz;"#,
666 expect![[r#" 685 expect![[r#"
667 insertions: 686 insertions:
668 687
669 Line 2: Node([email protected]) 688 Line 2: After(Node([email protected]))
670 -> "\n" 689 -> "\n"
671 -> use baz; 690 -> use baz;
672 691
@@ -694,7 +713,7 @@ use baz;"#,
694 expect![[r#" 713 expect![[r#"
695 insertions: 714 insertions:
696 715
697 Line 2: Token([email protected] "\n") 716 Line 2: After(Token([email protected] "\n"))
698 -> use bar; 717 -> use bar;
699 -> "\n" 718 -> "\n"
700 719
@@ -722,7 +741,7 @@ use baz;"#,
722 expect![[r#" 741 expect![[r#"
723 insertions: 742 insertions:
724 743
725 Line 0: Token([email protected] "\n") 744 Line 0: After(Token([email protected] "\n"))
726 -> use foo; 745 -> use foo;
727 -> "\n" 746 -> "\n"
728 747
@@ -738,6 +757,36 @@ use baz;"#,
738 } 757 }
739 758
740 #[test] 759 #[test]
760 fn first_child_insertion() {
761 mark::check!(insert_first_child);
762 check_diff(
763 r#"fn main() {
764 stdi
765 }"#,
766 r#"use foo::bar;
767
768 fn main() {
769 stdi
770 }"#,
771 expect![[r#"
772 insertions:
773
774 Line 0: AsFirstChild(Node([email protected]))
775 -> use foo::bar;
776 -> "\n\n "
777
778 replacements:
779
780
781
782 deletions:
783
784
785 "#]],
786 );
787 }
788
789 #[test]
741 fn delete_last() { 790 fn delete_last() {
742 mark::check!(diff_delete); 791 mark::check!(diff_delete);
743 check_diff( 792 check_diff(
@@ -779,7 +828,7 @@ use crate::AstNode;
779 expect![[r#" 828 expect![[r#"
780 insertions: 829 insertions:
781 830
782 Line 1: Node([email protected]) 831 Line 1: After(Node([email protected]))
783 -> "\n\n" 832 -> "\n\n"
784 -> use crate::AstNode; 833 -> use crate::AstNode;
785 834
@@ -845,10 +894,10 @@ use std::ops::{self, RangeInclusive};
845 expect![[r#" 894 expect![[r#"
846 insertions: 895 insertions:
847 896
848 Line 2: Node([email protected]) 897 Line 2: After(Node([email protected]))
849 -> :: 898 -> ::
850 -> fmt 899 -> fmt
851 Line 6: Token([email protected] "\n") 900 Line 6: After(Token([email protected] "\n"))
852 -> use std::hash::BuildHasherDefault; 901 -> use std::hash::BuildHasherDefault;
853 -> "\n" 902 -> "\n"
854 -> use std::ops::{self, RangeInclusive}; 903 -> use std::ops::{self, RangeInclusive};
@@ -892,14 +941,14 @@ fn main() {
892 expect![[r#" 941 expect![[r#"
893 insertions: 942 insertions:
894 943
895 Line 3: Node([email protected]) 944 Line 3: After(Node([email protected]))
896 -> " " 945 -> " "
897 -> match Err(92) { 946 -> match Err(92) {
898 Ok(it) => it, 947 Ok(it) => it,
899 _ => return, 948 _ => return,
900 } 949 }
901 -> ; 950 -> ;
902 Line 3: Node([email protected]) 951 Line 3: After(Node([email protected]))
903 -> "\n " 952 -> "\n "
904 -> foo(x); 953 -> foo(x);
905 954
@@ -934,14 +983,18 @@ fn main() {
934 _ => format!("{}", syn), 983 _ => format!("{}", syn),
935 }; 984 };
936 985
937 let insertions = diff.insertions.iter().format_with("\n", |(k, v), f| { 986 let insertions =
938 f(&format!( 987 diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
939 "Line {}: {:?}\n-> {}", 988 f(&format!(
940 line_number(k), 989 "Line {}: {:?}\n-> {}",
941 k, 990 line_number(match k {
942 v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) 991 super::TreeDiffInsertPos::After(syn) => syn,
943 )) 992 super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
944 }); 993 }),
994 k,
995 v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
996 ))
997 });
945 998
946 let replacements = diff 999 let replacements = diff
947 .replacements 1000 .replacements