inspector

package
v0.17.0 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package inspector provides a two-column label/value viewer for structured records — pod specs, REST responses, Prefect run details, any "show me the fields of this thing" surface. Each Field carries a Label and a Value; nested Children render below their parent with indent + ▸/▾ expand glyphs. Labels at the same parent auto-align so sibling key:value pairs read in a clean column.

The body is a pkg/pane.Pane (so pgup/pgdn/arrows/mouse-wheel and horizontal scroll work out of the box) plus an optional pkg/filter.Model for "/-to-search". A field whose Label or Value matches the query highlights inline with MatchStyle; backslash toggles filter mode, which hides non-matching subtrees while keeping ancestors visible so the path stays readable. Same nav verbs as pkg/tree: up/down/j/k per row, g/G top/bottom, ctrl+u/ctrl+d half-page, space to toggle the cursor row, E/C to expand/collapse all. Arrow keys and hjkl follow the library-wide scroll convention (rule 23) and are reserved for vertical/horizontal scroll — they do not expand/collapse.

Use FromAny / FromMap to convert json-unmarshal output (or any map[string]any / []any soup) into Fields without writing per-shape converters by hand.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Field

type Field struct {
	Label    string
	Value    string
	Children []Field
}

Field is one record entry. Value renders to the right of Label; pass an empty Value when the field is just a header for its Children. Children nest under the field with indent + an expand glyph; pass nil/empty for scalar fields. Field is value-typed so callers can build a tree by composition without worrying about pointer aliasing.

func FromAny

func FromAny(v any) []Field

FromAny converts an arbitrary JSON-shaped value (string, number, bool, nil, []any, map[string]any) into a slice of Fields. Maps render with keys (sorted alphabetically for determinism); slices render with "[N]" labels. Use this for REST responses or k8s manifests after a json.Unmarshal into any/map[string]any.

func FromMap

func FromMap(m map[string]any) []Field

FromMap converts a map[string]any into Fields, sorting keys for deterministic output. Nested maps and slices recurse.

type Keys

type Keys struct {
	Up, Down                       key.Binding
	Top, Bottom                    key.Binding
	HalfUp, HalfDown               key.Binding
	Toggle, ExpandAll, CollapseAll key.Binding
	NextSibling, PrevSibling       key.Binding
	NextLeaf, PrevLeaf             key.Binding
	Search, NextMatch, PrevMatch   key.Binding
	Filter                         key.Binding
	Pane                           pane.Keys
}

Keys is the inspector's keymap. Each binding carries both its dispatch keys (WithKeys) and its help label (WithHelp) — Update and Help() read from the same struct, so a custom binding propagates everywhere. The embedded pane.Keys covers horizontal scroll; mutate fields on Pane to override h-scroll without touching the rest.

func DefaultKeys

func DefaultKeys() Keys

DefaultKeys returns the inspector's stock keymap. Mutate the returned value to override individual actions.

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model is the inspector widget. Embed by value; mutate via the setters.

func New

func New(opts Options) Model

New constructs an inspector. Call Update/View from the parent model.

func (*Model) CollapseAll

func (m *Model) CollapseAll()

CollapseAll collapses every nested field.

func (Model) Cursor

func (m Model) Cursor() int

Cursor returns the current cursor index into the visible row set.

func (*Model) ExpandAll

func (m *Model) ExpandAll()

ExpandAll expands every nested field. Useful right after a refresh when the caller wants the whole record visible.

func (Model) FilterMode

func (m Model) FilterMode() bool

FilterMode reports whether non-matching subtrees are currently hidden.

func (Model) Help

func (m Model) Help() []key.Binding

Help returns the keys this inspector responds to. Each entry comes straight from m.keys (the same bindings Update dispatches against), so custom keymaps propagate to the hint strip automatically.

func (Model) Init

func (m Model) Init() tea.Cmd

Init satisfies tea.Model.

func (Model) Loading

func (m Model) Loading() bool

Loading reports whether the body pane is in its loading state.

func (Model) Query

func (m Model) Query() string

Query returns the current search query (empty when no search active).

func (Model) Searching

func (m Model) Searching() bool

Searching reports whether the embedded filter currently has focus.

func (Model) Selected

func (m Model) Selected() (Field, bool)

Selected returns the field under the cursor.

func (*Model) SetActiveColor

func (m *Model) SetActiveColor(c lipgloss.TerminalColor)

SetActiveColor / SetInactiveColor update the body pane's border colors.

func (*Model) SetCursor

func (m *Model) SetCursor(n int)

SetCursor moves the cursor (clamped) and scrolls to keep it on screen.

func (*Model) SetDimensions

func (m *Model) SetDimensions(w, h int)

SetDimensions resizes the inspector in place.

func (*Model) SetFields

func (m *Model) SetFields(fs []Field)

SetFields replaces the record. Expansion state is preserved by row path so refreshing a polled record doesn't collapse what the user had open; cursor falls back to the nearest valid row when its path disappears from the new fields. Options.InitialDepth is re-applied against the new field set so an inspector populated asynchronously (empty at construction, SetFields after a fetch) lands at the same pre-expansion the static-Fields path gets in New.

func (*Model) SetFilterMode

func (m *Model) SetFilterMode(b bool)

SetFilterMode turns filter-only rendering on or off.

func (*Model) SetFocused

func (m *Model) SetFocused(b bool)

SetFocused sets the body pane's focus state.

func (*Model) SetInactiveColor

func (m *Model) SetInactiveColor(c lipgloss.TerminalColor)

func (*Model) SetLoading

func (m *Model) SetLoading(b bool) tea.Cmd

SetLoading toggles the loading state and returns the spinner's first tick.

func (*Model) SetLoadingLabel

func (m *Model) SetLoadingLabel(s string)

SetLoadingLabel updates the spinner's accompanying text.

func (*Model) SetQuery

func (m *Model) SetQuery(s string)

SetQuery seeds the search programmatically. Used to carry state across SetTheme rebuilds (read Query(), rebuild, SetQuery back).

func (*Model) SetSpinnerStyle

func (m *Model) SetSpinnerStyle(s lipgloss.Style)

SetSpinnerStyle updates the lipgloss style applied to the spinner glyph.

func (*Model) SetTitle

func (m *Model) SetTitle(s string)

SetTitle updates the title rendered on the body pane's top border.

func (Model) Update

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

Update handles cursor movement, expand/collapse, search, and forwards non-key messages to the body pane (so spinner ticks reach the loading-state animation).

func (Model) View

func (m Model) View() string

View stacks the filter (when filterable) above the body pane.

type Options

type Options struct {
	Width, Height int
	// Title sits on the pane's top-left border slot. Defaults to "details".
	Title string
	// Fields is the top-level record. Each field's Children render as a
	// nested expandable block.
	Fields []Field
	// Filterable embeds a filter.Model above the body pane (three rows).
	Filterable bool
	// InitialDepth pre-expands every node whose depth is < InitialDepth.
	// 0 (default) shows only top-level rows collapsed; pass a large number
	// to expand everything.
	InitialDepth int

	// LabelStyle is applied to label text (typically a subtle color or
	// bold). Padding to the per-group label-column width is applied
	// before the style runs.
	LabelStyle lipgloss.Style
	// ValueStyle is applied to value text after label rendering.
	ValueStyle lipgloss.Style
	// MatchStyle highlights matched substrings while a query is active.
	MatchStyle lipgloss.Style
	// CurrentLineStyle is applied to the entire row holding the cursor,
	// padded out to the pane's inner width.
	CurrentLineStyle lipgloss.Style

	// Pane pass-throughs.
	ActiveColor    lipgloss.TerminalColor
	InactiveColor  lipgloss.TerminalColor
	ActiveBorder   lipgloss.Border
	InactiveBorder lipgloss.Border
	SlotBrackets   pane.SlotBracketStyle
	HScrollbar     bool

	// SpinnerStyle is applied to the spinner glyph rendered while the
	// inspector is in its loading state (see SetLoading).
	SpinnerStyle lipgloss.Style
	// LoadingLabel is rendered next to the spinner while loading.
	LoadingLabel string

	// Filter configures the embedded filter. Ignored when Filterable=false.
	Filter filter.Options

	// Keys overrides the default keymap. Any field left as the zero
	// key.Binding falls back to the corresponding DefaultKeys() value, so
	// callers can override a single action without restating the rest.
	// theme.Inspector() pre-populates this with DefaultKeys().
	Keys Keys
}

Options configures a new inspector. Theme.Inspector() returns this pre-styled — set Title/Fields/Filterable/Filter on the returned value.

Jump to

Keyboard shortcuts

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