@@ -10,13 +10,17 @@ use DisplayTreeKind::*;
1010enum DisplayTreeKind < ' a > {
1111 /// Leaf node.
1212 Leaf ( & ' a str ) ,
13- /// Separated node. Considered different if the separator is different or the lengths are
14- /// different.
13+ /// Separated node. Considered different if the separator is different. If the lengths are
14+ /// different, different options are possible .
1515 Separated {
1616 /// The separator, intercalated between the children.
1717 sep : & ' a str ,
1818 /// The children.
1919 children : & ' a [ DisplayTree < ' a > ] ,
20+ /// If the lengths differ and this is `true`, the first elements are diffed together until
21+ /// exhaustion. If the lengths differ and this is `false`, we consider the whole subtree to
22+ /// differ.
23+ compare_common_prefix : bool ,
2024 } ,
2125}
2226
@@ -25,7 +29,7 @@ pub struct DisplayTree<'a> {
2529 kind : DisplayTreeKind < ' a > ,
2630 /// Identifies the kind of node. Two nodes with different tags are always considered different.
2731 tag : & ' static str ,
28- /// Whether to this sub-tree unchanged for the purposes of diffing.
32+ /// Whether to consider this sub-tree unchanged for the purposes of diffing.
2933 ignore_for_diff : bool ,
3034}
3135
@@ -77,6 +81,14 @@ fn strip_markup(s: &str) -> String {
7781}
7882
7983impl < ' a > DisplayTree < ' a > {
84+ fn new_from_kind ( kind : DisplayTreeKind < ' a > ) -> Self {
85+ Self {
86+ kind,
87+ tag : "" ,
88+ ignore_for_diff : false ,
89+ }
90+ }
91+
8092 pub fn is_empty ( & self ) -> bool {
8193 match self . kind {
8294 Leaf ( s) => s. is_empty ( ) ,
@@ -87,7 +99,7 @@ impl<'a> DisplayTree<'a> {
8799 pub fn len_ignoring_markup ( & self ) -> usize {
88100 match self . kind {
89101 Leaf ( s) => len_ignoring_markup ( s) ,
90- Separated { sep, children } => {
102+ Separated { sep, children, .. } => {
91103 let sep_len = if children. len ( ) <= 1 {
92104 0
93105 } else {
@@ -100,45 +112,44 @@ impl<'a> DisplayTree<'a> {
100112 }
101113
102114 pub fn leaf_noalloc ( s : & ' a str ) -> Self {
103- Self {
104- kind : Leaf ( s) ,
105- tag : "" ,
106- ignore_for_diff : false ,
107- }
115+ Self :: new_from_kind ( Leaf ( s) )
108116 }
109117
110118 pub fn leaf ( a : & ' a Arenas < ' a > , s : & str ) -> Self {
111119 Self :: leaf_noalloc ( a. alloc_str ( s) )
112120 }
113121
114- pub fn sep_by (
122+ fn mk_separated (
115123 a : & ' a Arenas < ' a > ,
116124 sep : & str ,
117- it : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
125+ children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
126+ compare_common_prefix : bool ,
118127 ) -> Self {
119- let children = it . into_iter ( ) . map ( |x| x . to_display_tree ( a ) ) . collect_vec ( ) ;
120- Self {
121- kind : Separated {
122- sep : a . alloc_str ( sep ) ,
123- children : a . bump . alloc_slice_copy ( & children ) ,
124- } ,
125- tag : "" ,
126- ignore_for_diff : false ,
127- }
128+ let children = children
129+ . into_iter ( )
130+ . map ( |x| x . to_display_tree ( a ) )
131+ . collect_vec ( ) ;
132+ Self :: new_from_kind ( Separated {
133+ sep : a . alloc_str ( sep ) ,
134+ children : a . bump . alloc_slice_copy ( & children ) ,
135+ compare_common_prefix ,
136+ } )
128137 }
129138
130- /// Constructs `self` followed by `after`.
131- pub fn then ( & self , a : & ' a Arenas < ' a > , x : impl ToDisplayTree < ' a > ) -> Self {
132- self . sep_then ( a, "" , x)
139+ pub fn sep_by (
140+ a : & ' a Arenas < ' a > ,
141+ sep : & str ,
142+ children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
143+ ) -> Self {
144+ Self :: mk_separated ( a, sep, children, false )
133145 }
134146
135- /// Constructs `self` surrounded by `before` and `after`.
136- pub fn surrounded ( & self , a : & ' a Arenas < ' a > , before : & ' static str , after : & ' static str ) -> Self {
137- Self :: sep_by (
138- a,
139- "" ,
140- [ Self :: leaf_noalloc ( before) , * self , Self :: leaf_noalloc ( after) ] ,
141- )
147+ pub fn sep_by_compare_prefix (
148+ a : & ' a Arenas < ' a > ,
149+ sep : & str ,
150+ children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
151+ ) -> Self {
152+ Self :: mk_separated ( a, sep, children, true )
142153 }
143154
144155 /// Concatenates `self` and `x`, separated by `sep`.
@@ -148,17 +159,26 @@ impl<'a> DisplayTree<'a> {
148159 sep : & ' static str ,
149160 x : impl ToDisplayTree < ' a > ,
150161 ) -> Self {
151- Self :: sep2_by ( a, self , sep , x)
162+ Self :: sep_by ( a, sep , [ self . to_display_tree ( a ) , x. to_display_tree ( a ) ] )
152163 }
153164
154- /// Concatenates `x` and `y`, separated by `sep`.
155- pub fn sep2_by (
156- a : & ' a Arenas < ' a > ,
157- x : impl ToDisplayTree < ' a > ,
158- sep : & str ,
159- y : impl ToDisplayTree < ' a > ,
160- ) -> Self {
161- Self :: sep_by ( a, sep, [ x. to_display_tree ( a) , y. to_display_tree ( a) ] )
165+ /// Constructs `self` followed by `after`.
166+ pub fn then ( & self , a : & ' a Arenas < ' a > , x : impl ToDisplayTree < ' a > ) -> Self {
167+ self . sep_then ( a, "" , x)
168+ }
169+
170+ /// Constructs `self` surrounded by `before` and `after`.
171+ pub fn preceded ( & self , a : & ' a Arenas < ' a > , before : & ' static str ) -> Self {
172+ Self :: sep_by ( a, "" , [ Self :: leaf_noalloc ( before) , * self ] )
173+ }
174+
175+ /// Constructs `self` surrounded by `before` and `after`.
176+ pub fn surrounded ( & self , a : & ' a Arenas < ' a > , before : & ' static str , after : & ' static str ) -> Self {
177+ Self :: sep_by (
178+ a,
179+ "" ,
180+ [ Self :: leaf_noalloc ( before) , * self , Self :: leaf_noalloc ( after) ] ,
181+ )
162182 }
163183
164184 pub fn ignore_for_diff ( mut self ) -> Self {
@@ -212,20 +232,30 @@ impl<'a> DisplayTree<'a> {
212232 ( Leaf ( l) , Leaf ( r) ) if strip_markup ( l) == strip_markup ( r) => all_same ( left, right) ,
213233 // The non-trivial case: the trees differ partially.
214234 (
215- Separated { sep, children : c1 } ,
235+ Separated {
236+ sep,
237+ children : c1,
238+ compare_common_prefix : ccp1,
239+ } ,
216240 Separated {
217241 sep : sep2,
218242 children : c2,
243+ compare_common_prefix : ccp2,
219244 } ,
220- ) if strip_markup ( sep) == strip_markup ( sep2) && c1. len ( ) == c2. len ( ) => {
245+ ) if strip_markup ( sep) == strip_markup ( sep2)
246+ && ( c1. len ( ) == c2. len ( ) || ccp1 || ccp2) =>
247+ {
221248 let mut is_first = true ;
222249 let mut any_diff = false ;
223- for ( c1 , c2 ) in c1. iter ( ) . zip ( c2 ) {
224- if !is_first {
250+ for either_or_both in c1. iter ( ) . copied ( ) . zip_longest ( c2 . iter ( ) . copied ( ) ) {
251+ if !is_first && !either_or_both . is_right ( ) {
225252 write ! ( left, "{sep}" ) ?;
253+ }
254+ if !is_first && !either_or_both. is_left ( ) {
226255 write ! ( right, "{sep}" ) ?;
227256 }
228- any_diff |= c1. diff_display_inner ( c2, left, right) ?;
257+ let ( c1, c2) = either_or_both. or_default ( ) ;
258+ any_diff |= c1. diff_display_inner ( & c2, left, right) ?;
229259 is_first = false ;
230260 }
231261 Ok ( any_diff)
@@ -237,19 +267,15 @@ impl<'a> DisplayTree<'a> {
237267
238268impl Default for DisplayTree < ' _ > {
239269 fn default ( ) -> Self {
240- Self {
241- kind : Leaf ( "" ) ,
242- tag : "" ,
243- ignore_for_diff : false ,
244- }
270+ Self :: leaf_noalloc ( "" )
245271 }
246272}
247273
248274impl < ' a > Display for DisplayTree < ' a > {
249275 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
250276 match self . kind {
251277 Leaf ( s) => write ! ( f, "{s}" ) ?,
252- Separated { sep, children } => {
278+ Separated { sep, children, .. } => {
253279 let mut is_first = true ;
254280 for child in children {
255281 if !is_first {
0 commit comments