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
Initialises the tree with props and an optional state.
Instance methods
Responds to navigation and expand/collapse commands.
Cmd::MoveDown— advancesstate.cursorby one within the visible flattened list, clamped at the last visible node.Cmd::MoveUp— retreatsstate.cursorby one, clamped at 0.Cmd::Expand—CmdResult::Bubbleif the cursor node has children and is not expanded, so the owningWidgetcan emitMsg::ExpandNode;CmdResult::Noneotherwise (leaf node, already expanded, or no visible nodes).Cmd::Collapse— same pattern asCmd::Expand, but bubbles only when the cursor node has children and is currently expanded.- Any other command — returns
CmdResult::None.
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.
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.
Narrows the inherited state getter to TreeMock::WidgetState. Safe:
initialize only ever stores a WidgetState into the base @state
ivar.