@@ -10,13 +10,17 @@ use DisplayTreeKind::*;
10
10
enum DisplayTreeKind < ' a > {
11
11
/// Leaf node.
12
12
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 .
15
15
Separated {
16
16
/// The separator, intercalated between the children.
17
17
sep : & ' a str ,
18
18
/// The children.
19
19
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 ,
20
24
} ,
21
25
}
22
26
@@ -25,7 +29,7 @@ pub struct DisplayTree<'a> {
25
29
kind : DisplayTreeKind < ' a > ,
26
30
/// Identifies the kind of node. Two nodes with different tags are always considered different.
27
31
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.
29
33
ignore_for_diff : bool ,
30
34
}
31
35
@@ -77,6 +81,14 @@ fn strip_markup(s: &str) -> String {
77
81
}
78
82
79
83
impl < ' 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
+
80
92
pub fn is_empty ( & self ) -> bool {
81
93
match self . kind {
82
94
Leaf ( s) => s. is_empty ( ) ,
@@ -87,7 +99,7 @@ impl<'a> DisplayTree<'a> {
87
99
pub fn len_ignoring_markup ( & self ) -> usize {
88
100
match self . kind {
89
101
Leaf ( s) => len_ignoring_markup ( s) ,
90
- Separated { sep, children } => {
102
+ Separated { sep, children, .. } => {
91
103
let sep_len = if children. len ( ) <= 1 {
92
104
0
93
105
} else {
@@ -100,45 +112,44 @@ impl<'a> DisplayTree<'a> {
100
112
}
101
113
102
114
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) )
108
116
}
109
117
110
118
pub fn leaf ( a : & ' a Arenas < ' a > , s : & str ) -> Self {
111
119
Self :: leaf_noalloc ( a. alloc_str ( s) )
112
120
}
113
121
114
- pub fn sep_by (
122
+ fn mk_separated (
115
123
a : & ' a Arenas < ' a > ,
116
124
sep : & str ,
117
- it : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
125
+ children : impl IntoIterator < Item : ToDisplayTree < ' a > > ,
126
+ compare_common_prefix : bool ,
118
127
) -> 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
+ } )
128
137
}
129
138
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 )
133
145
}
134
146
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 )
142
153
}
143
154
144
155
/// Concatenates `self` and `x`, separated by `sep`.
@@ -148,17 +159,26 @@ impl<'a> DisplayTree<'a> {
148
159
sep : & ' static str ,
149
160
x : impl ToDisplayTree < ' a > ,
150
161
) -> 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 ) ] )
152
163
}
153
164
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
+ )
162
182
}
163
183
164
184
pub fn ignore_for_diff ( mut self ) -> Self {
@@ -212,20 +232,30 @@ impl<'a> DisplayTree<'a> {
212
232
( Leaf ( l) , Leaf ( r) ) if strip_markup ( l) == strip_markup ( r) => all_same ( left, right) ,
213
233
// The non-trivial case: the trees differ partially.
214
234
(
215
- Separated { sep, children : c1 } ,
235
+ Separated {
236
+ sep,
237
+ children : c1,
238
+ compare_common_prefix : ccp1,
239
+ } ,
216
240
Separated {
217
241
sep : sep2,
218
242
children : c2,
243
+ compare_common_prefix : ccp2,
219
244
} ,
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
+ {
221
248
let mut is_first = true ;
222
249
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 ( ) {
225
252
write ! ( left, "{sep}" ) ?;
253
+ }
254
+ if !is_first && !either_or_both. is_left ( ) {
226
255
write ! ( right, "{sep}" ) ?;
227
256
}
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) ?;
229
259
is_first = false ;
230
260
}
231
261
Ok ( any_diff)
@@ -237,19 +267,15 @@ impl<'a> DisplayTree<'a> {
237
267
238
268
impl Default for DisplayTree < ' _ > {
239
269
fn default ( ) -> Self {
240
- Self {
241
- kind : Leaf ( "" ) ,
242
- tag : "" ,
243
- ignore_for_diff : false ,
244
- }
270
+ Self :: leaf_noalloc ( "" )
245
271
}
246
272
}
247
273
248
274
impl < ' a > Display for DisplayTree < ' a > {
249
275
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
250
276
match self . kind {
251
277
Leaf ( s) => write ! ( f, "{s}" ) ?,
252
- Separated { sep, children } => {
278
+ Separated { sep, children, .. } => {
253
279
let mut is_first = true ;
254
280
for child in children {
255
281
if !is_first {
0 commit comments