@@ -137,7 +137,7 @@ impl TreeDiff {
137137 }
138138}
139139
140- /// Finds minimal the diff, which, applied to `from`, will result in `to`.
140+ /// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
141141///
142142/// Specifically, returns a structure that consists of a replacements, insertions and deletions
143143/// such that applying this map on `from` will result in `to`.
@@ -151,7 +151,6 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
151151 } ;
152152 let ( from, to) = ( from. clone ( ) . into ( ) , to. clone ( ) . into ( ) ) ;
153153
154- // FIXME: this is horrible inefficient. I bet there's a cool algorithm to diff trees properly.
155154 if !syntax_element_eq ( & from, & to) {
156155 go ( & mut diff, from, to) ;
157156 }
@@ -169,6 +168,7 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
169168 }
170169 }
171170
171+ // FIXME: this is horrible inefficient. I bet there's a cool algorithm to diff trees properly.
172172 fn go ( diff : & mut TreeDiff , lhs : SyntaxElement , rhs : SyntaxElement ) {
173173 let ( lhs, rhs) = match lhs. as_node ( ) . zip ( rhs. as_node ( ) ) {
174174 Some ( ( lhs, rhs) ) => ( lhs, rhs) ,
@@ -179,6 +179,8 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
179179 }
180180 } ;
181181
182+ let mut look_ahead_scratch = Vec :: default ( ) ;
183+
182184 let mut rhs_children = rhs. children_with_tokens ( ) ;
183185 let mut lhs_children = lhs. children_with_tokens ( ) ;
184186 let mut last_lhs = None ;
@@ -204,7 +206,31 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
204206 diff. deletions . push ( element) ;
205207 }
206208 ( Some ( ref lhs_ele) , Some ( ref rhs_ele) ) if syntax_element_eq ( lhs_ele, rhs_ele) => { }
207- ( Some ( lhs_ele) , Some ( rhs_ele) ) => go ( diff, lhs_ele, rhs_ele) ,
209+ ( Some ( lhs_ele) , Some ( rhs_ele) ) => {
210+ // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
211+ // until that element as insertions. This is important to keep the diff minimal
212+ // in regards to insertions that have been actually done, this is important for
213+ // use insertions as we do not want to replace the entire module node.
214+ look_ahead_scratch. push ( rhs_ele. clone ( ) ) ;
215+ let mut rhs_children_clone = rhs_children. clone ( ) ;
216+ let mut insert = false ;
217+ while let Some ( rhs_child) = rhs_children_clone. next ( ) {
218+ if syntax_element_eq ( & lhs_ele, & rhs_child) {
219+ mark:: hit!( diff_insertions) ;
220+ insert = true ;
221+ break ;
222+ } else {
223+ look_ahead_scratch. push ( rhs_child) ;
224+ }
225+ }
226+ let drain = look_ahead_scratch. drain ( ..) ;
227+ if let Some ( prev) = last_lhs. clone ( ) . filter ( |_| insert) {
228+ diff. insertions . entry ( prev) . or_insert_with ( Vec :: new) . extend ( drain) ;
229+ rhs_children = rhs_children_clone;
230+ } else {
231+ go ( diff, lhs_ele, rhs_ele)
232+ }
233+ }
208234 }
209235 last_lhs = lhs_child. or ( last_lhs) ;
210236 }
@@ -292,7 +318,6 @@ fn _replace_children(
292318#[ derive( Debug , PartialEq , Eq , Hash ) ]
293319enum InsertPos {
294320 FirstChildOf ( SyntaxNode ) ,
295- // Before(SyntaxElement),
296321 After ( SyntaxElement ) ,
297322}
298323
@@ -603,18 +628,44 @@ mod tests {
603628 }
604629
605630 #[ test]
606- fn insert ( ) {
631+ fn replace_parent ( ) {
632+ mark:: check!( diff_replace_parent) ;
633+ check_diff (
634+ r#""# ,
635+ r#"use foo::bar;"# ,
636+ expect ! [ [ r#"
637+ insertions:
638+
639+
640+
641+ replacements:
642+
643+ Line 0: Node([email protected] ) -> use foo::bar; 644+
645+ deletions:
646+
647+
648+ "# ] ] ,
649+ ) ;
650+ }
651+
652+ #[ test]
653+ fn insert_last ( ) {
607654 mark:: check!( diff_insert) ;
608655 check_diff (
609- r#"use foo;"# ,
610- r#" use foo;
656+ r#"
657+ use foo;
611658use bar;"# ,
659+ r#"
660+ use foo;
661+ use bar;
662+ use baz;"# ,
612663 expect ! [ [ r#"
613664 insertions:
614665
615- Line 0 : Node(USE@0..8 )
666+ Line 2 : Node(USE@10..18 )
616667 -> "\n"
617- -> use bar ;
668+ -> use baz ;
618669
619670 replacements:
620671
@@ -628,29 +679,63 @@ use bar;"#,
628679 }
629680
630681 #[ test]
631- fn replace_parent ( ) {
632- mark:: check!( diff_replace_parent) ;
682+ fn insert_middle ( ) {
633683 check_diff (
634- r#""# ,
635- r#"use foo::bar;"# ,
684+ r#"
685+ use foo;
686+ use baz;"# ,
687+ r#"
688+ use foo;
689+ use bar;
690+ use baz;"# ,
636691 expect ! [ [ r#"
637692 insertions:
638693
694+ Line 2: Token([email protected] "\n") 695+ -> use bar;
696+ -> "\n"
697+
698+ replacements:
699+
700+
701+
702+ deletions:
703+
704+
705+ "# ] ] ,
706+ )
707+ }
708+
709+ #[ test]
710+ fn insert_first ( ) {
711+ check_diff (
712+ r#"
713+ use bar;
714+ use baz;"# ,
715+ r#"
716+ use foo;
717+ use bar;
718+ use baz;"# ,
719+ expect ! [ [ r#"
720+ insertions:
639721
722+ Line 0: Token([email protected] "\n") 723+ -> use foo;
724+ -> "\n"
640725
641726 replacements:
642727
643- Line 0: Node([email protected] ) -> use foo::bar; 728+
644729
645730 deletions:
646731
647732
648733 "# ] ] ,
649- ) ;
734+ )
650735 }
651736
652737 #[ test]
653- fn delete ( ) {
738+ fn delete_last ( ) {
654739 mark:: check!( diff_delete) ;
655740 check_diff (
656741 r#"use foo;
@@ -674,52 +759,50 @@ use bar;"#,
674759 }
675760
676761 #[ test]
677- fn insert_use ( ) {
762+ fn delete_middle ( ) {
763+ mark:: check!( diff_insertions) ;
678764 check_diff (
679765 r#"
680766use expect_test::{expect, Expect};
767+ use text_edit::TextEdit;
681768
682769use crate::AstNode;
683770"# ,
684771 r#"
685772use expect_test::{expect, Expect};
686- use text_edit::TextEdit;
687773
688774use crate::AstNode;
689775"# ,
690776 expect ! [ [ r#"
691777 insertions:
692778
693- Line 4: Token([email protected] "\n") 779+ 780+ -> "\n\n"
694781 -> use crate::AstNode;
695- -> "\n"
696782
697783 replacements:
698784
699- Line 2: Token([email protected] "\n\n") -> "\n" 700- Line 4: Token([email protected] "crate") -> text_edit 701- Line 4: Token([email protected] "AstNode") -> TextEdit 702- Line 4: Token([email protected] "\n") -> "\n\n" 703785
704- deletions:
705786
787+ deletions:
706788
789+ Line 2: use text_edit::TextEdit;
790+ Line 3: "\n\n"
791+ Line 4: use crate::AstNode;
792+ Line 5: "\n"
707793 "# ] ] ,
708794 )
709795 }
710796
711797 #[ test]
712- fn remove_use ( ) {
798+ fn delete_first ( ) {
713799 check_diff (
714800 r#"
715- use expect_test::{expect, Expect};
716801use text_edit::TextEdit;
717802
718803use crate::AstNode;
719804"# ,
720805 r#"
721- use expect_test::{expect, Expect};
722-
723806use crate::AstNode;
724807"# ,
725808 expect ! [ [ r#"
@@ -729,15 +812,14 @@ use crate::AstNode;
729812
730813 replacements:
731814
732- Line 2: Token([email protected] "\n") -> "\n\n" 733- Line 3: Node([email protected] ) -> crate 734- Line 3: Token([email protected] "TextEdit") -> AstNode 735- Line 3: Token([email protected] "\n\n") -> "\n" 815+ Line 2: Node([email protected] ) -> crate 816+ Line 2: Token([email protected] "TextEdit") -> AstNode 817+ Line 2: Token([email protected] "\n\n") -> "\n" 736818
737819 deletions:
738820
739- Line 4 : use crate::AstNode;
740- Line 5 : "\n"
821+ Line 3 : use crate::AstNode;
822+ Line 4 : "\n"
741823 "# ] ] ,
742824 )
743825 }
@@ -814,17 +896,15 @@ fn main() {
814896 _ => return,
815897 }
816898 -> ;
817- Line 5: Token([email protected] "}" ) 818- -> "\n"
819- -> }
899+ 900+ -> "\n "
901+ -> foo(x);
820902
821903 replacements:
822904
823905 Line 3: Token([email protected] "if") -> let 824906 Line 3: Token([email protected] "let") -> x 825907 Line 3: Node([email protected] ) -> = 826- Line 5: Token([email protected] "\n") -> "\n " 827- Line 5: Token([email protected] "}") -> foo(x); 828908
829909 deletions:
830910
0 commit comments