@@ -151,9 +151,9 @@ func buildNodes(beans []*bean.Bean, children map[string][]*bean.Bean, matchedSet
151151const (
152152 treeBranch = "├─ "
153153 treeLastBranch = "└─ "
154- treePipe = "" // no continuation lines
155- treeSpace = "" // no spacing for completed branches
156- treeIndent = 3 // width of connector (├─ or └─ )
154+ treePipe = "│ " // vertical line for ongoing branches
155+ treeSpace = " " // empty space for completed branches
156+ treeIndent = 3 // width of connector
157157)
158158
159159// calculateMaxDepth returns the maximum depth of the tree.
@@ -217,26 +217,35 @@ func RenderTree(nodes []*TreeNode, cfg *config.Config, maxIDWidth int, hasTags b
217217 sb .WriteString (Muted .Render (strings .Repeat ("─" , dividerWidth )))
218218 sb .WriteString ("\n " )
219219
220- // Render nodes (depth 0 = root level)
221- renderNodes (& sb , nodes , 0 , cfg , treeColWidth , hasTags )
220+ // Render nodes (depth 0 = root level, no ancestry yet )
221+ renderNodes (& sb , nodes , 0 , nil , cfg , treeColWidth , hasTags )
222222
223223 return sb .String ()
224224}
225225
226226// renderNodes recursively renders tree nodes with proper indentation.
227227// depth 0 = root level (no connector), depth 1+ = nested (has connector)
228- func renderNodes (sb * strings.Builder , nodes []* TreeNode , depth int , cfg * config.Config , treeColWidth int , hasTags bool ) {
228+ // ancestry tracks whether each parent level was a last child (true = last, no continuation line needed)
229+ func renderNodes (sb * strings.Builder , nodes []* TreeNode , depth int , ancestry []bool , cfg * config.Config , treeColWidth int , hasTags bool ) {
229230 for i , node := range nodes {
230231 isLast := i == len (nodes )- 1
231- renderNode (sb , node , depth , isLast , cfg , treeColWidth , hasTags )
232- renderNodes (sb , node .Children , depth + 1 , cfg , treeColWidth , hasTags )
232+ renderNode (sb , node , depth , isLast , ancestry , cfg , treeColWidth , hasTags )
233+ // Only add to ancestry when depth > 0 (roots have no connectors to continue)
234+ if len (node .Children ) > 0 {
235+ var newAncestry []bool
236+ if depth > 0 {
237+ newAncestry = append (ancestry , isLast )
238+ }
239+ renderNodes (sb , node .Children , depth + 1 , newAncestry , cfg , treeColWidth , hasTags )
240+ }
233241 }
234242}
235243
236244// renderNode renders a single tree node with tree connectors.
237245// treeColWidth is the fixed width of the ID column (includes space for tree connectors).
238246// depth 0 = root (no connector), depth 1+ = nested (has connector)
239- func renderNode (sb * strings.Builder , node * TreeNode , depth int , isLast bool , cfg * config.Config , treeColWidth int , hasTags bool ) {
247+ // ancestry tracks whether each parent level was a last child (true = last, no continuation line needed)
248+ func renderNode (sb * strings.Builder , node * TreeNode , depth int , isLast bool , ancestry []bool , cfg * config.Config , treeColWidth int , hasTags bool ) {
240249 b := node .Bean
241250
242251 // Get status color from config
@@ -275,9 +284,13 @@ func renderNode(sb *strings.Builder, node *TreeNode, depth int, isLast bool, cfg
275284 var indent string
276285 var connector string
277286 if depth > 0 {
278- // Add indentation for depth > 1 (3 spaces per level beyond first)
279- if depth > 1 {
280- indent = strings .Repeat (" " , depth - 1 )
287+ // Build indent from ancestry - each level adds either │ or space
288+ for _ , wasLast := range ancestry {
289+ if wasLast {
290+ indent += treeSpace // parent was last child, no continuation line
291+ } else {
292+ indent += treePipe // parent has more siblings, show continuation line
293+ }
281294 }
282295 if isLast {
283296 connector = treeLastBranch
@@ -399,22 +412,28 @@ type FlatItem struct {
399412// Each item includes the pre-computed tree prefix for rendering.
400413func FlattenTree (nodes []* TreeNode ) []FlatItem {
401414 var items []FlatItem
402- flattenNodes (nodes , 0 , & items )
415+ flattenNodes (nodes , 0 , nil , & items )
403416 return items
404417}
405418
406- func flattenNodes (nodes []* TreeNode , depth int , items * []FlatItem ) {
419+ // flattenNodes recursively flattens tree nodes.
420+ // ancestry tracks whether each parent level was a last child (true = last, no continuation line needed)
421+ func flattenNodes (nodes []* TreeNode , depth int , ancestry []bool , items * []FlatItem ) {
407422 for i , node := range nodes {
408423 isLast := i == len (nodes )- 1
409424
410425 // Compute tree prefix
411426 var prefix string
412427 if depth > 0 {
413- // Add indentation for depth > 1 (3 spaces per level beyond first)
414- if depth > 1 {
415- prefix = strings .Repeat (" " , depth - 1 )
428+ // Build prefix from ancestry - each level adds either │ or space
429+ for _ , wasLast := range ancestry {
430+ if wasLast {
431+ prefix += treeSpace // parent was last child, no continuation line
432+ } else {
433+ prefix += treePipe // parent has more siblings, show continuation line
434+ }
416435 }
417- // Add connector
436+ // Add connector for this node
418437 if isLast {
419438 prefix += treeLastBranch
420439 } else {
@@ -430,8 +449,15 @@ func flattenNodes(nodes []*TreeNode, depth int, items *[]FlatItem) {
430449 TreePrefix : prefix ,
431450 })
432451
433- // Recurse into children
434- flattenNodes (node .Children , depth + 1 , items )
452+ // Recurse into children, passing updated ancestry
453+ // Only add to ancestry when depth > 0 (roots have no connectors to continue)
454+ if len (node .Children ) > 0 {
455+ var newAncestry []bool
456+ if depth > 0 {
457+ newAncestry = append (ancestry , isLast )
458+ }
459+ flattenNodes (node .Children , depth + 1 , newAncestry , items )
460+ }
435461 }
436462}
437463
0 commit comments