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.rs130
1 files changed, 93 insertions, 37 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 9dc7182bd..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)
@@ -331,7 +349,10 @@ pub struct SyntaxRewriter<'a> {
331 349
332impl fmt::Debug for SyntaxRewriter<'_> { 350impl fmt::Debug for SyntaxRewriter<'_> {
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 f.debug_struct("SyntaxRewriter").field("replacements", &self.replacements).finish() 352 f.debug_struct("SyntaxRewriter")
353 .field("replacements", &self.replacements)
354 .field("insertions", &self.insertions)
355 .finish()
335 } 356 }
336} 357}
337 358
@@ -629,18 +650,19 @@ mod tests {
629 650
630 #[test] 651 #[test]
631 fn replace_parent() { 652 fn replace_parent() {
632 mark::check!(diff_replace_parent); 653 mark::check!(diff_insert_as_first_child);
633 check_diff( 654 check_diff(
634 r#""#, 655 r#""#,
635 r#"use foo::bar;"#, 656 r#"use foo::bar;"#,
636 expect![[r#" 657 expect![[r#"
637 insertions: 658 insertions:
638 659
639 660 Line 0: AsFirstChild(Node([email protected]))
661 -> use foo::bar;
640 662
641 replacements: 663 replacements:
642 664
643 Line 0: Node([email protected]) -> use foo::bar; 665
644 666
645 deletions: 667 deletions:
646 668
@@ -663,7 +685,7 @@ use baz;"#,
663 expect![[r#" 685 expect![[r#"
664 insertions: 686 insertions:
665 687
666 Line 2: Node([email protected]) 688 Line 2: After(Node([email protected]))
667 -> "\n" 689 -> "\n"
668 -> use baz; 690 -> use baz;
669 691
@@ -691,7 +713,7 @@ use baz;"#,
691 expect![[r#" 713 expect![[r#"
692 insertions: 714 insertions:
693 715
694 Line 2: Token([email protected] "\n") 716 Line 2: After(Token([email protected] "\n"))
695 -> use bar; 717 -> use bar;
696 -> "\n" 718 -> "\n"
697 719
@@ -719,7 +741,7 @@ use baz;"#,
719 expect![[r#" 741 expect![[r#"
720 insertions: 742 insertions:
721 743
722 Line 0: Token([email protected] "\n") 744 Line 0: After(Token([email protected] "\n"))
723 -> use foo; 745 -> use foo;
724 -> "\n" 746 -> "\n"
725 747
@@ -735,6 +757,36 @@ use baz;"#,
735 } 757 }
736 758
737 #[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]
738 fn delete_last() { 790 fn delete_last() {
739 mark::check!(diff_delete); 791 mark::check!(diff_delete);
740 check_diff( 792 check_diff(
@@ -776,7 +828,7 @@ use crate::AstNode;
776 expect![[r#" 828 expect![[r#"
777 insertions: 829 insertions:
778 830
779 Line 1: Node([email protected]) 831 Line 1: After(Node([email protected]))
780 -> "\n\n" 832 -> "\n\n"
781 -> use crate::AstNode; 833 -> use crate::AstNode;
782 834
@@ -842,10 +894,10 @@ use std::ops::{self, RangeInclusive};
842 expect![[r#" 894 expect![[r#"
843 insertions: 895 insertions:
844 896
845 Line 2: Node([email protected]) 897 Line 2: After(Node([email protected]))
846 -> :: 898 -> ::
847 -> fmt 899 -> fmt
848 Line 6: Token([email protected] "\n") 900 Line 6: After(Token([email protected] "\n"))
849 -> use std::hash::BuildHasherDefault; 901 -> use std::hash::BuildHasherDefault;
850 -> "\n" 902 -> "\n"
851 -> use std::ops::{self, RangeInclusive}; 903 -> use std::ops::{self, RangeInclusive};
@@ -889,14 +941,14 @@ fn main() {
889 expect![[r#" 941 expect![[r#"
890 insertions: 942 insertions:
891 943
892 Line 3: Node([email protected]) 944 Line 3: After(Node([email protected]))
893 -> " " 945 -> " "
894 -> match Err(92) { 946 -> match Err(92) {
895 Ok(it) => it, 947 Ok(it) => it,
896 _ => return, 948 _ => return,
897 } 949 }
898 -> ; 950 -> ;
899 Line 3: Node([email protected]) 951 Line 3: After(Node([email protected]))
900 -> "\n " 952 -> "\n "
901 -> foo(x); 953 -> foo(x);
902 954
@@ -931,14 +983,18 @@ fn main() {
931 _ => format!("{}", syn), 983 _ => format!("{}", syn),
932 }; 984 };
933 985
934 let insertions = diff.insertions.iter().format_with("\n", |(k, v), f| { 986 let insertions =
935 f(&format!( 987 diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
936 "Line {}: {:?}\n-> {}", 988 f(&format!(
937 line_number(k), 989 "Line {}: {:?}\n-> {}",
938 k, 990 line_number(match k {
939 v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v))) 991 super::TreeDiffInsertPos::After(syn) => syn,
940 )) 992 super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
941 }); 993 }),
994 k,
995 v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
996 ))
997 });
942 998
943 let replacements = diff 999 let replacements = diff
944 .replacements 1000 .replacements