@@ -5,6 +5,17 @@ use itertools::Itertools;
55use crate :: * ;
66use DisplayTreeKind :: * ;
77
8+ /// How to compare two separated lists of different lengths.
9+ #[ derive( Clone , Copy , PartialEq , Eq ) ]
10+ pub enum CompareMode {
11+ /// We consider the whole subtree to differ.
12+ None ,
13+ /// The first elements are diffed together until exhaustion.
14+ Prefix ,
15+ /// The last elements are diffed together until exhaustion.
16+ Suffix ,
17+ }
18+
819/// A structured representation of a string to be displayed. Used to compute structured diffs.
920#[ derive( Clone , Copy ) ]
1021enum DisplayTreeKind < ' a > {
@@ -17,10 +28,8 @@ enum DisplayTreeKind<'a> {
1728 sep : & ' a str ,
1829 /// The children.
1930 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 ,
31+ /// How to compare elements if the lengths differ.
32+ compare_mode : CompareMode ,
2433 } ,
2534}
2635
@@ -119,11 +128,11 @@ impl<'a> DisplayTree<'a> {
119128 Self :: leaf_noalloc ( a. alloc_str ( s) )
120129 }
121130
122- fn mk_separated (
131+ pub fn sep_by_compare_mode (
123132 a : & ' a Arenas < ' a > ,
124133 sep : & str ,
125134 children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
126- compare_common_prefix : bool ,
135+ compare_mode : CompareMode ,
127136 ) -> Self {
128137 let children = children
129138 . into_iter ( )
@@ -132,7 +141,7 @@ impl<'a> DisplayTree<'a> {
132141 Self :: new_from_kind ( Separated {
133142 sep : a. alloc_str ( sep) ,
134143 children : a. bump . alloc_slice_copy ( & children) ,
135- compare_common_prefix ,
144+ compare_mode ,
136145 } )
137146 }
138147
@@ -141,15 +150,15 @@ impl<'a> DisplayTree<'a> {
141150 sep : & str ,
142151 children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
143152 ) -> Self {
144- Self :: mk_separated ( a, sep, children, false )
153+ Self :: sep_by_compare_mode ( a, sep, children, CompareMode :: None )
145154 }
146155
147156 pub fn sep_by_compare_prefix (
148157 a : & ' a Arenas < ' a > ,
149158 sep : & str ,
150159 children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
151160 ) -> Self {
152- Self :: mk_separated ( a, sep, children, true )
161+ Self :: sep_by_compare_mode ( a, sep, children, CompareMode :: Prefix )
153162 }
154163
155164 /// Concatenates `self` and `x`, separated by `sep`.
@@ -235,26 +244,44 @@ impl<'a> DisplayTree<'a> {
235244 Separated {
236245 sep,
237246 children : c1,
238- compare_common_prefix : ccp1,
247+ compare_mode : ccp1,
239248 } ,
240249 Separated {
241250 sep : sep2,
242251 children : c2,
243- compare_common_prefix : ccp2 ,
252+ compare_mode : _ , // we only look at one of tham
244253 } ,
245254 ) if strip_markup ( sep) == strip_markup ( sep2)
246- && ( c1. len ( ) == c2. len ( ) || ccp1 || ccp2 ) =>
255+ && ( c1. len ( ) == c2. len ( ) || ccp1 != CompareMode :: None ) =>
247256 {
257+ use std:: iter:: repeat_n;
258+ // Pad the two lists so they have the same length; pad at the start or end
259+ // depending on how we want to match the lists up.
260+ let len1 = c1. len ( ) ;
261+ let len2 = c2. len ( ) ;
262+ let len = std:: cmp:: max ( len1, len2) ;
263+ let ( prefix1, prefix2, suffix1, suffix2) = match ccp1 {
264+ CompareMode :: None => ( 0 , 0 , 0 , 0 ) ,
265+ CompareMode :: Prefix => ( 0 , 0 , len - len1, len - len2) ,
266+ CompareMode :: Suffix => ( len - len1, len - len2, 0 , 0 ) ,
267+ } ;
268+ let c1 = repeat_n ( None , prefix1)
269+ . chain ( c1. iter ( ) . copied ( ) . map ( Some ) )
270+ . chain ( repeat_n ( None , suffix1) ) ;
271+ let c2 = repeat_n ( None , prefix2)
272+ . chain ( c2. iter ( ) . copied ( ) . map ( Some ) )
273+ . chain ( repeat_n ( None , suffix2) ) ;
274+
248275 let mut is_first = true ;
249276 let mut any_diff = false ;
250- for either_or_both in c1. iter ( ) . copied ( ) . zip_longest ( c2 . iter ( ) . copied ( ) ) {
251- if !is_first && !either_or_both . is_right ( ) {
277+ for ( l , r ) in c1. zip ( c2 ) {
278+ if !is_first && !l . is_none ( ) {
252279 write ! ( left, "{sep}" ) ?;
253280 }
254- if !is_first && !either_or_both . is_left ( ) {
281+ if !is_first && !r . is_none ( ) {
255282 write ! ( right, "{sep}" ) ?;
256283 }
257- let ( c1, c2) = either_or_both . or_default ( ) ;
284+ let ( c1, c2) = ( l . unwrap_or_default ( ) , r . unwrap_or_default ( ) ) ;
258285 any_diff |= c1. diff_display_inner ( & c2, left, right) ?;
259286 is_first = false ;
260287 }
0 commit comments