aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 9dc7182bd..7ac6076a4 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)
@@ -629,18 +647,19 @@ mod tests {
629 647
630 #[test] 648 #[test]
631 fn replace_parent() { 649 fn replace_parent() {
632 mark::check!(diff_replace_parent); 650 mark::check!(diff_insert_as_first_child);
633 check_diff( 651 check_diff(
634 r#""#, 652 r#""#,
635 r#"use foo::bar;"#, 653 r#"use foo::bar;"#,
636 expect![[r#" 654 expect![[r#"
637 insertions: 655 insertions:
638 656
639 657 Line 0: AsFirstChild(Node([email protected]))
658 -> use foo::bar;
640 659
641 replacements: 660 replacements:
642 661
643 Line 0: Node([email protected]) -> use foo::bar; 662
644 663
645 deletions: 664 deletions:
646 665
@@ -663,7 +682,7 @@ use baz;"#,
663 expect![[r#" 682 expect![[r#"
664 insertions: 683 insertions:
665 684
666 Line 2: Node([email protected]) 685 Line 2: After(Node([email protected]))
667 -> "\n" 686 -> "\n"
668 -> use baz; 687 -> use baz;
669 688
@@ -691,7 +710,7 @@ use baz;"#,
691 expect![[r#" 710 expect![[r#"
692 insertions: 711 insertions:
693 712
694 Line 2: Token([email protected] "\n") 713 Line 2: After(Token([email protected] "\n"))
695 -> use bar; 714 -> use bar;
696 -> "\n" 715 -> "\n"
697 716
@@ -719,7 +738,7 @@ use baz;"#,
719 expect![[r#" 738 expect![[r#"
720 insertions: 739 insertions:
721 740
722 Line 0: Token([email protected] "\n") 741 Line 0: After(Token([email protected] "\n"))
723 -> use foo; 742 -> use foo;
724 -> "\n" 743 -> "\n"
725 744
@@ -735,6 +754,36 @@ use baz;"#,
735 } 754 }
736 755
737 #[test] 756 #[test]
757 fn first_child_insertion() {
758 mark::check!(insert_first_child);
759 check_diff(
760 r#"fn main() {
761 stdi
762 }"#,
763 r#"use foo::bar;
764
765 fn main() {
766 stdi
767 }"#,
768 expect![[r#"
769 insertions:
770
771 Line 0: AsFirstChild(Node([email protected]))
772 -> use foo::bar;
773 -> "\n\n "
774
775 replacements:
776
777
778
779 deletions:
780
781
782 "#]],
783 );
784 }
785
786 #[test]
738 fn delete_last() { 787 fn delete_last() {
739 mark::check!(diff_delete); 788 mark::check!(diff_delete);
740 check_diff( 789 check_diff(
@@ -776,7 +825,7 @@ use crate::AstNode;
776 expect![[r#" 825 expect![[r#"
777 insertions: 826 insertions:
778 827
779 Line 1: Node([email protected]) 828 Line 1: After(Node([email protected]))
780 -> "\n\n" 829 -> "\n\n"
781 -> use crate::AstNode; 830 -> use crate::AstNode;
782 831
@@ -842,10 +891,10 @@ use std::ops::{self, RangeInclusive};
842 expect![[r#" 891 expect![[r#"
843 insertions: 892 insertions:
844 893
845 Line 2: Node([email protected]) 894 Line 2: After(Node([email protected]))
846 -> :: 895 -> ::
847 -> fmt 896 -> fmt
848 Line 6: Token([email protected] "\n") 897 Line 6: After(Token([email protected] "\n"))
849 -> use std::hash::BuildHasherDefault; 898 -> use std::hash::BuildHasherDefault;
850 -> "\n" 899 -> "\n"
851 -> use std::ops::{self, RangeInclusive}; 900 -> use std::ops::{self, RangeInclusive};
@@ -889,14 +938,14 @@ fn main() {
889 expect![[r#" 938 expect![[r#"
890 insertions: 939 insertions:
891 940
892 Line 3: Node([email protected]) 941 Line 3: After(Node([email protected]))
893 -> " " 942 -> " "
894 -> match Err(92) { 943 -> match Err(92) {
895 Ok(it) => it, 944 Ok(it) => it,
896 _ => return, 945 _ => return,
897 } 946 }
898 -> ; 947 -> ;
899 Line 3: Node([email protected]) 948 Line 3: After(Node([email protected]))
900 -> "\n " 949 -> "\n "
901 -> foo(x); 950 -> foo(x);
902 951
@@ -931,14 +980,18 @@ fn main() {
931 _ => format!("{}", syn), 980 _ => format!("{}", syn),
932 }; 981 };
933 982
934 let insertions = diff.insertions.iter().format_with("\n", |(k, v), f| { 983 let insertions =
935 f(&format!( 984 diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
936 "Line {}: {:?}\n-> {}", 985 f(&format!(
937 line_number(k), 986 "Line {}: {:?}\n-> {}",
938 k, 987 line_number(match k {
939 v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) 988 super::TreeDiffInsertPos::After(syn) => syn,
940 )) 989 super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
941 }); 990 }),
991 k,
992 v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
993 ))
994 });
942 995
943 let replacements = diff 996 let replacements = diff
944 .replacements 997 .replacements