Tree

termflow.tui.widgets.Tree
object Tree

Generic tree-view widget. Renders a collapsible hierarchy as a flat list of rows, one per visible node.

The widget is structure-agnostic: apps describe their own tree by implementing Tree.Children (or supplying a function), label nodes via a render callback, and own the expanded / selected state. The widget walks the structure each frame and produces the visible row list — no internal state, no in-place mutation.

Conventions

  • Indentation. Each level adds two cells of left padding so ancestor relationships are visually obvious. Override with indentWidth.
  • Markers. Internal nodes (those with children) get a + (collapsed, "click to open") or - (expanded, "click to collapse") glyph, three columns wide ([+] / [-]). Leaves get four spaces of leading padding. The unicode flag is kept for backwards compatibility but no longer changes the glyph since + / - are already ASCII.
  • Selection. The row at selectedIndex (an index into the visible row list) is highlighted in the theme's primary slot, bolded.
  • Identity. Apps decide what an "expanded" node is via Tree.Children.id (a stable key) and a Set[Id] of expanded ids. Re-using the same id across frames is what keeps state stable as the tree changes shape.

Example

given Theme = Theme.dark

sealed trait Node:
 def name: String
case class Dir(name: String, kids: Vector[Node]) extends Node
case class File(name: String) extends Node

given Tree.Children[Node, String] with
 def id(n: Node): String = n.name
 def kids(n: Node): Vector[Node] = n match
   case Dir(_, k) => k
   case _: File   => Vector.empty

Tree(
 roots         = Vector(Dir("src", Vector(File("Main.scala")))),
 expanded      = Set("src"),
 selectedIndex = 0,
 render        = _.name
)

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type
Tree.type

Members list

Type members

Classlikes

trait Children[A, Id]

Type-class describing how to traverse a custom tree structure.

Type-class describing how to traverse a custom tree structure.

Attributes

Supertypes
class Object
trait Matchable
class Any
enum HitResult

Region of a tree row a click landed in. Apps map a HitResult.Chevron to "toggle expand" and a HitResult.Label to "select this row".

Region of a tree row a click landed in. Apps map a HitResult.Chevron to "toggle expand" and a HitResult.Label to "select this row".

Attributes

Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
final case class Row[A](node: A, id: String, depth: Int, hasChildren: Boolean, expanded: Boolean)

Row that the widget renders for each visible node.

Row that the widget renders for each visible node.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all

Value members

Concrete methods

def apply[A, Id](roots: Vector[A], expanded: Set[Id], selectedIndex: Int, render: A => String, at: Coord, indentWidth: Int, unicode: Boolean)(using c: Children[A, Id], theme: Theme): List[VNode]

Render the tree as a list of TextNodes.

Render the tree as a list of TextNodes.

Value parameters

at

Top-left cell of the first row.

expanded

Set of expanded node ids.

indentWidth

Cells added per depth level (default 2).

render

Label for a node.

roots

Root nodes drawn in document order.

selectedIndex

Visible-row index of the highlighted row, or -1 for no selection.

unicode

Whether to emit Unicode chevrons or ASCII v / > fallbacks.

Attributes

def collapsedFor(unicode: Boolean): String

Marker glyph for a collapsed internal node.

Marker glyph for a collapsed internal node.

Attributes

def expandedFor(unicode: Boolean): String

Marker glyph for an expanded internal node.

Marker glyph for an expanded internal node.

Attributes

def hitTest[A](rows: Vector[Row[A]], at: Coord, indentWidth: Int, col: Int, row: Int, labelLength: Int): Option[HitResult]

Map a click (col, row) to a HitResult over the rendered row list.

Map a click (col, row) to a HitResult over the rendered row list.

The chevron region is the column span occupied by the [+] / [-] glyph (skipped for leaves since they have no toggle). Apps pre-compute rows = Tree.visibleRows(...) once per frame and pass it in alongside the same at / indentWidth they used to render.

Returns None for clicks outside any rendered row.

Value parameters

at

Top-left of the first row (mirrors the rendering call).

col

Click column (1-based, absolute).

indentWidth

Cells per depth level (mirrors the rendering call).

labelLength

Maximum label width for the click target. Pass Int.MaxValue if rows can be any length.

row

Click row (1-based, absolute).

rows

Row list returned by visibleRows.

Attributes

def leafFor(unicode: Boolean): String

Padding used in place of a marker for leaf nodes.

Padding used in place of a marker for leaf nodes.

Attributes

def rowWidth(label: String, depth: Int, indentWidth: Int, unicode: Boolean): Int

Cell width of a tree row at depth carrying the given label.

Cell width of a tree row at depth carrying the given label.

Attributes

def visibleRows[A, Id](roots: Vector[A], expanded: Set[Id])(using c: Children[A, Id]): Vector[Row[A]]

Walk the tree honouring the expanded set; produce the flat row list the widget renders. Public so apps can pre-compute it (e.g. for click-to-row mapping outside the widget itself).

Walk the tree honouring the expanded set; produce the flat row list the widget renders. Public so apps can pre-compute it (e.g. for click-to-row mapping outside the widget itself).

Attributes