class

Phosphor::TreeMock

Inherits Phosphor::MockWidget < Reference < Object

A collapsible tree view for hierarchical data — file browsers, JSON explorers, directory pickers, network topology views.

Generic and app-agnostic: no knowledge of AppState, Msg, or the application theme. The Widget wrapper resolves theme → Style values and sets them in Props before each render.

props.nodes is the full tree, already structured with correct depth values by Widget#sync. TreeMock never traverses or flattens the raw tree to compute structure — but render_content does walk it on every call to derive which rows are currently visible (a node's children are visible only when that node is expanded). This is a read-only traversal for display, not a mutation, and mirrors how ListMock walks props.rows directly.

Because Props is a record and TreeNode is a struct, there is no way for handle_cmd to flip a node's expanded field in place — Cmd::Expand/Cmd::Collapse return CmdResult::Bubble instead of mutating props.nodes. The owning Widget translates the bubbled command into Msg::ExpandNode/Msg::CollapseNode, Screen#handle updates AppState, and the new expanded value flows back in through Widget#sync on the next render.

Constructors

new(props : Props, state : WidgetState = WidgetState.new)

Initialises the tree with props and an optional state.

Source

Instance methods

handle_cmd(cmd : Cmd) : CmdResult

Responds to navigation and expand/collapse commands.

  • Cmd::MoveDown — advances state.cursor by one within the visible flattened list, clamped at the last visible node.
  • Cmd::MoveUp — retreats state.cursor by one, clamped at 0.
  • Cmd::ExpandCmdResult::Bubble if the cursor node has children and is not expanded, so the owning Widget can emit Msg::ExpandNode; CmdResult::None otherwise (leaf node, already expanded, or no visible nodes).
  • Cmd::Collapse — same pattern as Cmd::Expand, but bubbles only when the cursor node has children and is currently expanded.
  • Any other command — returns CmdResult::None.
Source
preferred_height(width : Int32) : Int32 | Nil

The flattened visible node count — every node, plus a node's children wherever that node is expanded — regardless of width. Matches exactly what #render_content would draw given unlimited height, i.e. #flatten(props.nodes).size.

Source
props
Source
props=(props : Props)
Source
render_content(frame : Frame, buf : Buffer) : Void

Renders the visible window of props.nodes into buf within frame.

Flattens props.nodes depth-first into the visible list (a node's children appear only when that node is expanded), clamps state.scroll_offset so state.cursor stays on screen, then draws up to frame.height rows starting at state.scroll_offset. Each row is depth * 2 spaces of indent, an expand/collapse indicator ("▶ " collapsed-with-children, "▼ " expanded-with-children, " " leaf), then the label — truncated to frame.width. The cursor row uses node.selected_style; other expanded-with-children rows use node.expanded_style; everything else uses node.style.

Source
state

Narrows the inherited state getter to TreeMock::WidgetState. Safe: initialize only ever stores a WidgetState into the base @state ivar.

Source

Nested types