@@ -15,6 +15,10 @@ Print a text representation of `tree` to the given `io` object.
1515* `io::IO` - IO stream to write to.
1616* `tree` - tree to print.
1717* `maxdepth::Integer = 5` - truncate printing of subtrees at this depth.
18+ * `maxsibling::Union{Nothing,Integer} = nothing` - if set, print at most this many
19+ consecutive similar siblings and then elide the rest of that run.
20+ * `sibling_similarity_threshold::Real = 0` - threshold for considering sibling node values
21+ similar. Non-numeric node values currently only support exact matching.
1822* `indicate_truncation::Bool = true` - print a vertical ellipsis character beneath
1923 truncated nodes.
2024* `charset::TreeCharSet` - [`TreeCharSet`](@ref) to use to print branches.
@@ -191,15 +195,46 @@ print_child_key(io::IO, key::CartesianIndex) = show(io, Tuple(key))
191195
192196branchwidth (cs:: TreeCharSet ) = sum (textwidth .((cs. mid, cs. dash)))
193197
198+
199+ """
200+ nodevalue_distance(v1, v2; kw...)::Real
201+
202+ Compute the distance between the values of two child nodes. By default, equivalent to isequal.
203+ It must return a Real
204+
205+ **OPTIONAL**: This can be extended for custom types and controls how nodes are shown
206+ in [`print_tree`](@ref).
207+ """
208+ nodevalue_distance (v1, v2) = ifelse (isequal (v1, v2), zero (Float64), Inf )
209+
210+ function print_and_child_prefix (io:: IO , prefix:: AbstractString , is_last:: Bool , charset:: TreeCharSet )
211+ print (io, prefix)
212+
213+ if is_last
214+ print (io, charset. terminator)
215+ child_prefix = prefix * " " ^ (textwidth (charset. skip) + textwidth (charset. dash) + 1 )
216+ else
217+ print (io, charset. mid)
218+ child_prefix = prefix * charset. skip * " " ^ (textwidth (charset. dash) + 1 )
219+ end
220+
221+ print (io, charset. dash, ' ' )
222+
223+ return child_prefix
224+ end
225+
194226function print_tree (printnode:: Function , print_child_key:: Function , io:: IO , node;
195227 maxdepth:: Integer = 5 ,
228+ maxsibling:: Union{Nothing,Integer} = nothing ,
229+ sibling_similarity_threshold:: Real = 0 ,
196230 indicate_truncation:: Bool = true ,
197231 charset:: TreeCharSet = TreeCharSet (),
198232 printkeys:: Union{Bool,Nothing} = nothing ,
199233 depth:: Integer = 0 ,
200234 prefix:: AbstractString = " " ,
201235 printnode_kw= (;),
202236 )
237+
203238 # Get node representation as string
204239 buf = IOBuffer ()
205240 printnode (IOContext (buf, io), node; printnode_kw... )
@@ -233,28 +268,43 @@ function print_tree(printnode::Function, print_child_key::Function, io::IO, node
233268 # Print children
234269 s = Iterators. Stateful (this_printkeys ? pairs (c) : c)
235270
236- while ! isempty (s)
237- child_prefix = prefix
271+ use_sibling_elision = ! isnothing (maxsibling)
272+ prev_child_value = nothing
273+ seen_child = false
274+ similar_run_length = 0
275+ elided_count = 0
238276
277+ while ! isempty (s)
239278 if this_printkeys
240279 child_key, child = popfirst! (s)
241280 else
242281 child = popfirst! (s)
243282 child_key = nothing
244283 end
245284
246- print (io, prefix)
285+ child_value = nodevalue (child)
286+ if use_sibling_elision
287+ if seen_child && nodevalue_distance (prev_child_value, child_value) <= sibling_similarity_threshold
288+ similar_run_length += 1
289+ else
290+ if elided_count > 0
291+ print_and_child_prefix (io, prefix, false , charset)
292+ println (io, charset. trunc, " (" , elided_count, " siblings elided)" )
293+ elided_count = 0
294+ end
295+ similar_run_length = 1
296+ end
297+ end
247298
248- # Last child?
249- if isempty (s)
250- print (io, charset. terminator)
251- child_prefix *= " " ^ (textwidth (charset. skip) + textwidth (charset. dash) + 1 )
252- else
253- print (io, charset. mid)
254- child_prefix *= charset. skip * " " ^ (textwidth (charset. dash) + 1 )
299+ prev_child_value = child_value
300+ seen_child = true
301+
302+ if use_sibling_elision && similar_run_length > maxsibling
303+ elided_count += 1
304+ continue
255305 end
256306
257- print (io, charset . dash, ' ' )
307+ child_prefix = print_and_child_prefix (io, prefix, isempty (s) && elided_count == 0 , charset )
258308
259309 # Print key
260310 if this_printkeys
@@ -267,10 +317,17 @@ function print_tree(printnode::Function, print_child_key::Function, io::IO, node
267317 end
268318
269319 print_tree (printnode, print_child_key, io, child;
270- maxdepth= maxdepth, indicate_truncation= indicate_truncation, charset= charset,
271- printkeys= printkeys, depth= depth+ 1 , prefix= child_prefix, printnode_kw= printnode_kw,
320+ maxdepth= maxdepth, maxsibling= maxsibling,
321+ sibling_similarity_threshold= sibling_similarity_threshold,
322+ indicate_truncation= indicate_truncation, charset= charset, printkeys= printkeys,
323+ depth= depth+ 1 , prefix= child_prefix, printnode_kw= printnode_kw,
272324 )
273325 end
326+
327+ if elided_count > 0
328+ print_and_child_prefix (io, prefix, true , charset)
329+ println (io, charset. trunc, " (" , elided_count, " siblings elided)" )
330+ end
274331end
275332
276333print_tree (printnode:: Function , io:: IO , node; kw... ) = print_tree (printnode, print_child_key, io, node; kw... )
0 commit comments