treeview

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package treeview is a hierarchical expandable tree — InkUI's "TreeView" (file-browser-style navigation).

Example

Nodes start collapsed; Right expands the one under the cursor.

package main

import (
	"fmt"

	"github.com/ows4444/tui"
	"github.com/ows4444/tui/treeview"
)

func main() {
	m := treeview.New(treeview.Node{Label: "src", Children: []treeview.Node{{Label: "main.go"}, {Label: "util.go"}}})
	fmt.Println(len(m.VisibleRows()))
	m, _ = m.Update(tui.Key{Type: tui.KeyRight})
	for _, r := range m.VisibleRows() {
		fmt.Println(r.Depth, r.Label)
	}
}
Output:
1
0 src
1 main.go
1 util.go

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Sidebar(title string, tv Model, activeKey string, icons, badges map[string]string, t theme.Theme, width int) string

Sidebar renders tv's visible rows (as Model.View does: an indent-and-marker tree, delegating all flatten/expand-state/cursor logic to tv itself via Model.VisibleRows) inside a widgets.Panel, with optional per-row icon and badge decoration and a highlight driven by activeKey rather than tv's own keyboard cursor — activeKey identifies which row's content is currently shown elsewhere (e.g. the open file in a file-tree-plus-editor layout), which can differ from where the keyboard cursor happens to be.

icons and badges are looked up by a row's Path (see VisibleRow and Model's doc comment on path stability); a path with no entry in icons renders with no icon glyph, and likewise for badges. width behaves exactly as it does for Panel.

Types

type KeyMap

type KeyMap struct {
	Up, Down keymap.Binding
	// Select toggles a branch or confirms a leaf (SelectedMsg).
	Select keymap.Binding
	// Expand opens the branch under the cursor; Collapse closes it.
	Expand, Collapse keymap.Binding
}

KeyMap names the keys Update reacts to.

func DefaultKeyMap

func DefaultKeyMap() KeyMap

DefaultKeyMap returns the default keys: Up/Down, Enter or Space to select, Right to expand and Left to collapse.

type Model

type Model struct {
	Roots []Node
	Theme theme.Theme

	// Raw, when true, draws node labels unchanged. By default each label is
	// sanitised (ansi.Sanitize) so untrusted text, such as file names, cannot
	// carry terminal escape sequences.
	Raw bool

	// KeyMap holds the keys Update reacts to; New fills it with
	// DefaultKeyMap. A Model built as a struct literal with no KeyMap set
	// uses DefaultKeyMap.
	KeyMap KeyMap

	// Mouse, when true, makes Update handle tui.MouseEvent inside Bounds:
	// the wheel moves the cursor by WheelStep rows and a left click puts the
	// cursor on the row under the pointer. The zero value ignores the mouse.
	Mouse bool
	// Bounds is the screen rectangle where the app draws the tree (its
	// top-left cell is the first row). The app sets it.
	Bounds hittest.Rect
	// WheelStep is the rows moved per wheel notch; zero means 3.
	WheelStep int
	// contains filtered or unexported fields
}

Model is a keyboard-navigable tree. Expand state is tracked by a path (child indices joined with '.', e.g. "0.2.1"), which stays stable across renders as long as the tree's shape itself doesn't change out from under it — building a new Roots slice with different structure invalidates any previously-set expand state.

Model also serves as TreeSelect, a single-selection hierarchical picker: no separate type or package was created for it, since Model's flatten, expand-state and cursor-navigation logic (plus Enter/Space's toggle-if-branch/confirm-if-leaf behavior and the SelectedMsg it emits) already implements what TreeSelect needs.

func FromJSON

func FromJSON(data []byte) (Model, error)

New parses data as JSON and returns a Model rooted at its top-level value. Numbers are shown exactly as written, so an integer beyond 2^53 (an ID, say) is not rounded through a float64.

func New

func New(roots ...Node) Model

New builds a Model from roots, all initially collapsed.

func (Model) Bindings

func (m Model) Bindings() []keymap.Binding

Bindings returns the active bindings, for help widgets.

func (Model) Cursor

func (m Model) Cursor() int

Cursor returns the index of the visible row currently under the cursor.

func (Model) IsExpanded

func (m Model) IsExpanded(path string) bool

IsExpanded reports whether the node at path is expanded.

func (Model) LayoutNode

func (m Model) LayoutNode() layout.Node

LayoutNode adapts the tree to a layout.Node. Measure reports its natural size (the widest visible row by one row per visible node). Render fits the allotted Size: rows are cut to the width, and when there are more visible rows than fit it shows a window of rows containing the cursor row. The Model is not changed.

func (Model) Linearize

func (m Model) Linearize() string

Linearize renders the visible rows as plain text for accessible output (see tui.Linearizer): one line per node with its label, level, expanded or collapsed state (branches only), position among its siblings, and ", selected" on the cursor row, e.g. "src, level 1, expanded, item 2 of 3". No indentation, markers or styling.

func (*Model) SetCursor

func (m *Model) SetCursor(i int)

SetCursor moves the cursor to i among the currently visible rows, clamped to a valid index (or 0 with none visible).

func (Model) SetTheme

func (m Model) SetTheme(t theme.Theme) Model

SetTheme returns m with t applied. It makes Model a tui.ThemeSetter, so a root model can forward the Program's theme (see tui.WithTheme).

func (Model) Tokens

func (m Model) Tokens() theme.Tokens

Tokens returns the colour tokens the widget renders with: its theme's roles, overridden by any theme.WithTokens(theme.ComponentTreeView, ...) and then by WithTokens.

func (Model) Update

func (m Model) Update(msg tui.Msg) (Model, tui.Cmd)

Update moves the cursor on Up/Down and, on Enter or Space, either toggles the row under it (if it has children) or confirms it as a leaf, returning a Cmd that delivers SelectedMsg. Right expands the row under the cursor if it has children and is collapsed; Left collapses it if it has children and is expanded. Left on an already-collapsed node, or Left/Right on a leaf, is a no-op. A Msg that isn't a Key is a no-op.

func (Model) View

func (m Model) View() string

View renders the currently visible rows (expanded subtrees included), indented by depth, with the row under the cursor highlighted.

func (Model) VisibleRows

func (m Model) VisibleRows() []VisibleRow

VisibleRows returns the same flattened, currently-visible rows View renders, in the same order, without rendering them.

func (Model) WithTokens

func (m Model) WithTokens(tok theme.Tokens) Model

WithTokens returns m with tok as its per-instance colour override. Nil fields inherit from the theme, so only the roles tok names change; the theme and every other widget are untouched. A second call replaces the first.

type Node

type Node struct {
	Label    string
	Children []Node
}

Node is one tree node. A Node with no Children is a leaf.

func DirectoryTree

func DirectoryTree(root string) Node

DirectoryTree walks the filesystem starting at root and returns a Node tree for New/Model, one root Node labeled with root's base name. Only directories are recursed into eagerly (their Children are populated up front, unlike Model's own lazy expand state, which is purely a rendering concern); files are included as leaves. An entry that can't be listed (permission error, or a symlink loop) is skipped rather than failing the whole walk.

type SelectedMsg

type SelectedMsg struct {
	Node *Node
	Path string
}

SelectedMsg is delivered (via the Cmd Update returns) when a leaf node is confirmed with Enter or Space. Confirming a non-leaf node instead toggles its expand state and doesn't emit this.

type VisibleRow

type VisibleRow struct {
	Label       string
	Path        string
	Depth       int
	HasChildren bool
}

VisibleRow is one currently-visible row, exported for callers (e.g. Sidebar) that need to render a Model's rows themselves rather than through View — the path uniquely and stably identifies a row (see Model's doc comment) so a caller can key its own per-row decoration (icons, badges, an externally-driven active selection) off it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL