Documentation
¶
Overview ¶
Package tui is a small terminal UI: raw-mode input, differential line renderer, multi-line editor, and chat view. No external TUI framework; just ANSI escape codes.
Index ¶
- Constants
- Variables
- func AppearanceQuery() string
- func Bold(s string) string
- func CellAspectRatio() float64
- func ContextUsageText(used, max int) string
- func CursorColor(color TerminalColor) string
- func CursorColor256(index int) string
- func CursorShapeBlock() string
- func DetectTrueColor(termEnv, colorTerm string) bool
- func Dim(s string) string
- func DimLines(lines []string) []string
- func ExtractLastNewText(raw string) (value string, ok, done bool, editIdx int)
- func ExtractPartialStringField(raw, field string) (value string, ok, done bool)
- func HighlightCode(src, lang string) []string
- func ImageDimensions(data []byte) (int, int)
- func InlineImageFootprint(data []byte, cellsWide, maxRows int) (int, int)
- func InputBlock(th Theme, lines []string, width int) []string
- func InputLines(th Theme, lines []string, width int) []string
- func Italic(s string) string
- func JoinRightBar(th Theme, main, rightBar string, mainWidth, rightBarWidth int) string
- func LanguageFromPath(p string) string
- func MoveTo(row, col int) string
- func NormalizeInputStyle(v string) string
- func NormalizeStatusPosition(v string) string
- func NormalizeSubagentPosition(v string) string
- func NormalizeWorkingPosition(v string) string
- func ParseAppearanceCSI(raw []byte) (scheme *SchemeEvent, mode *ModeReportEvent)
- func ReadClipboardImagePNG() (string, []byte, bool, error)
- func ReadClipboardText() (string, bool, error)
- func RenderInlineImage(proto ImageProtocol, data []byte, mime string, maxCellsWide int) string
- func RenderInlineImageScaled(proto ImageProtocol, data []byte, mime string, maxCellsWide, maxCellsHigh int) string
- func RenderMarkdown(src string, th Theme, width int) string
- func RenderRightBar(th Theme, widgets []RightBarWidget, width, height int) []string
- func ReportCWD(dir string) string
- func ResetCursorColor() string
- func ResetCursorShape() string
- func RightBarColumns(cols int) (mainWidth, rightBarWidth int, ok bool)
- func RowsForInlineImage(data []byte, cellsWide, maxRows int) int
- func SetScrollRegion(top, bottom int) string
- func SetTitle(title string) string
- func ShortArgs(tool string, raw json.RawMessage) string
- func StatusBar(p StatusBarParams) []string
- func ThemeExists(zutHome, preferred string) bool
- func UsageStatsParts(p UsageStatsParams) []string
- func WrapANSILine(s string, limit int) []string
- func WriteBell(w io.Writer) error
- type AppearanceParser
- type AppearanceSource
- type ClipboardImage
- type ColorDepth
- type ColorEvent
- type Editor
- func (e *Editor) Clear()
- func (e *Editor) HandleKey(k Key) (submit bool)
- func (e *Editor) Insert(s string)
- func (e *Editor) IsEmpty() bool
- func (e *Editor) MoveVertical(dir int) bool
- func (e *Editor) Render(width int) (lines []string, visualRow, visualCol int)
- func (e *Editor) SetValue(s string)
- func (e *Editor) SubmitValue() string
- func (e *Editor) Value() string
- type FloatingPane
- type FloatingPaneFrame
- type FloatingPaneRect
- type ImageProtocol
- type InputEvent
- type Key
- type KeyKind
- type MessageAnchor
- type ModeReportEvent
- type ProcTerm
- func (p *ProcTerm) EnterRaw() (func() error, error)
- func (p *ProcTerm) OnResize(fn func())
- func (p *ProcTerm) PeekByteTimeout(d time.Duration) (byte, bool, error)
- func (p *ProcTerm) ReadByte() (byte, error)
- func (p *ProcTerm) SetNonblock(enable bool) error
- func (p *ProcTerm) Size() (int, int)
- func (p *ProcTerm) Write(b []byte) (int, error)
- type Reader
- type Renderer
- func (r *Renderer) Clear()
- func (r *Renderer) Draw(lines []string, cursorRow, cursorCol int)
- func (r *Renderer) DrawFloating(pane FloatingPaneFrame, cursorRow, cursorCol int)
- func (r *Renderer) DrawLog(chat, bottom []string, cursorBottomRow, cursorCol int)
- func (r *Renderer) DrawRightBar(chat, bottom, rightBar []string, cursorBottomRow, cursorCol int)
- func (r *Renderer) DrawRightBarDimmed(chat, bottom, rightBar []string, cursorBottomRow, cursorCol int)
- func (r *Renderer) Invalidate()
- func (r *Renderer) KeepsScrollback() bool
- func (r *Renderer) ResetScrollRegion()
- func (r *Renderer) Resize(cols, rows int)
- func (r *Renderer) SetTheme(th Theme)
- type RightBarWidget
- type SchemeEvent
- type StatusBarParams
- type StringSpinner
- type SyntaxTheme
- type SyntaxThemeOverrides
- type Terminal
- type TerminalColor
- type TerminalColorValue
- type TerminalProfile
- type Theme
- func (t Theme) AccentBar(c TerminalColor) string
- func (t Theme) BG(c TerminalColor, s string) string
- func (t Theme) BG256(c TerminalColor, s string) stringdeprecated
- func (t Theme) BackgroundStyle() string
- func (t Theme) DimColor(color TerminalColor, percent int) TerminalColor
- func (t Theme) FG256(c TerminalColor, s string) stringdeprecated
- func (t Theme) FGColor(c TerminalColor, s string) string
- func (t Theme) Highlight(s string) string
- func (th Theme) HighlightCode(src, lang string) []string
- func (t Theme) PadHighlight(s string, width int) string
- func (t Theme) SelectionStyle() string
- func (t Theme) SelectionStyleFG(fg TerminalColor) string
- func (t Theme) UserBubble(s string, width int) string
- func (t Theme) UserBubbleRow(content string, width int) string
- type ThemeFile
- type ThemeFileColorModes
- type ThemeOption
- type ThemeOverrides
- type ThemePreference
- type ThemeResolution
- type ThemeSource
- type ToolCallView
- type UsageStatsParams
- type View
- func (v *View) AdoptRenderCacheFrom(snapshot *View)
- func (v *View) Build(width int) []string
- func (v *View) BuildLive(width int) []string
- func (v *View) BuildWithAnchors(width int) ([]string, []MessageAnchor)
- func (v *View) CloneForRender() *View
- func (v *View) InvalidateRenderCache()
- func (v *View) RenderToolCall(tc ToolCallView, width int) []string
Constants ¶
const ( SeqQueryColorScheme = "\x1b[?996n" SeqQueryMode2031 = "\x1b[?2031$p" SeqEnableMode2031 = "\x1b[?2031h" SeqDisableMode2031 = "\x1b[?2031l" )
Appearance query and DEC mode 2031 control sequences.
const ( InputStylePlain = "plain" InputStyleLines = "lines" InputStyleBlock = "block" StatusPositionAboveInput = "above_input" StatusPositionBelowInput = "below_input" WorkingPositionAboveInput = "above_input" WorkingPositionBelowInput = "below_input" SubagentPositionAboveInput = "above_input" SubagentPositionBelowInput = "below_input" )
const ( // RightBarSeparatorWidth is the one-cell divider between the main pane // and the host-owned right bar. RightBarSeparatorWidth = 1 // RightBarMinWidth keeps widget titles and checklist markers readable. RightBarMinWidth = 24 // RightBarMaxWidth prevents a long extension line from taking most of // the transcript on wide terminals. RightBarMaxWidth = 36 // RightBarMinMainWidth preserves enough room for the editor and chat. RightBarMinMainWidth = 48 )
const ( SeqHideCursor = "\x1b[?25l" SeqShowCursor = "\x1b[?25h" SeqClearScreen = "\x1b[2J\x1b[H" // SeqClearScreenNoHome is SeqClearScreen without the trailing // cursor-home (\x1b[H). Use it whenever a MoveTo(...) follows // immediately. VS Code's integrated terminal interprets a bare // CUP-no-args during a clear as "snap the viewport scrollbar to // row 0", which makes the user's scroll position jump on every // repaint. The explicit MoveTo we emit afterwards positions the // cursor identically without triggering that snap. SeqClearScreenNoHome = "\x1b[2J" SeqClearScrollback = "\x1b[3J" // SeqCursorHome moves to the top-left of the visible viewport. // SeqClearToEnd erases from the cursor to the end of the screen // without scrolling content into scrollback (unlike \x1b[2J on // xterm.js). Together they clear the visible frame in place, which // the VS Code terminal needs for duplicate-free full repaints. SeqCursorHome = "\x1b[H" SeqClearToEnd = "\x1b[0J" SeqClearLine = "\x1b[2K" SeqResetScrollRegion = "\x1b[r" SeqDeleteKittyImages = "\x1b_Ga=d\x1b\\" SeqBracketedPasteOn = "\x1b[?2004h" SeqBracketedPasteOff = "\x1b[?2004l" // Request enhanced keyboard reporting where supported. Kitty-style // keyboard protocol covers Ghostty, Kitty, VS Code's integrated // terminal, and recent xterm.js builds. Xterm modifyOtherKeys is a // useful fallback for terminals/tmux configurations that expose // modified Enter as CSI 27;<mod>;<code>~. SeqEnhancedKeyboardOn = "\x1b[>1u\x1b[>4;2m" SeqEnhancedKeyboardOff = "\x1b[<u\x1b[>4m" // Basic mouse tracking + SGR extended coordinates. Used only // when explicitly enabled by the interactive mode (currently VS // Code terminal) so terminals with good native scrolling, like // Ghostty, are left alone. SeqMouseOn = "\x1b[?1000h\x1b[?1006h" SeqMouseOff = "\x1b[?1000l\x1b[?1006l" SeqAltScreenOn = "\x1b[?1049h" SeqAltScreenOff = "\x1b[?1049l" SeqSynchronizedOn = "\x1b[?2026h" SeqSynchronizedOff = "\x1b[?2026l" // SeqSaveCursor / SeqRestoreCursor use DECSC/DECRC. All terminals // we target adjust the saved row when natural scrolling occurs, so // these survive scroll-on-write inside the bottom band. SeqSaveCursor = "\x1b7" SeqRestoreCursor = "\x1b8" // SeqEraseToEnd erases from the cursor to the end of the screen. SeqEraseToEnd = "\x1b[J" )
HideCursor, ShowCursor, ClearScreen, BracketedPasteOn/Off, etc.
const ( ToolCollapsePreview = 10 ToolCollapseLines = 12 )
ToolCollapsePreview is the number of lines shown before a long tool result is replaced with a "... ctrl+o to expand" footer. Tool results shorter than ToolCollapseLines always render in full.
const FlushLeftSentinel = '\x1c'
FlushLeftSentinel was used previously to opt fenced code blocks out of the prose indent. The current rendering keeps fences aligned with surrounding prose, so the sentinel is no longer emitted; the constant is kept (and exported) so any older caller that still strips it remains a harmless no-op.
Variables ¶
var Dark = Theme{ FG: Color256(253), Muted: Color256(244), Accent: Color256(111), User: Color256(180), UserBubbleBG: ColorRGB(66, 69, 75), UserBubbleFG: Color256(248), Assistant: Color256(117), Tool: Color256(114), ToolOut: Color256(245), Error: Color256(203), Warning: Color256(214), Spinner: Color256(183), ThinkingMax: Color256(207), SelectionBG: Color256(24), SelectionFG: Color256(231), SpinnerFrames: defaultSpinnerFrames, SpinnerIntervalMS: 80, SyntaxBaseStyle: "monokai", Syntax: nordSyntax, }
var Light = Theme{ FG: Color256(236), Muted: Color256(244), Accent: Color256(33), User: Color256(94), UserBubbleBG: Color256(254), UserBubbleFG: Color256(240), Assistant: Color256(31), Tool: Color256(28), ToolOut: Color256(240), Error: Color256(160), Warning: Color256(166), Spinner: Color256(91), ThinkingMax: Color256(127), SelectionBG: Color256(153), SelectionFG: Color256(232), SpinnerFrames: defaultSpinnerFrames, SpinnerIntervalMS: 80, SyntaxBaseStyle: "monokai", Syntax: nordSyntax, }
Functions ¶
func AppearanceQuery ¶ added in v0.24.0
func AppearanceQuery() string
AppearanceQuery returns the complete profile query used at startup and on a replacement generation. The ANSI palette is requested in one OSC 4 batch.
func CellAspectRatio ¶
func CellAspectRatio() float64
CellAspectRatio returns the pixel-height / pixel-width ratio for one terminal cell. ZUT_CELL_ASPECT lets users tune inline-image row reservation for terminals/fonts where the default causes overlap or excessive blank space. Values outside a sane range are ignored.
func ContextUsageText ¶ added in v0.19.0
ContextUsageText returns the latest request's context utilization without styling so callers can safely measure, truncate, and color the whole line.
func CursorColor ¶ added in v0.2.0
func CursorColor(color TerminalColor) string
CursorColor returns OSC 12 to set the terminal cursor color. Unlike SGR styling, the cursor is terminal-owned, so modal backdrops must set this separately from their dimmed text rows.
func CursorColor256 ¶
func CursorShapeBlock ¶
func CursorShapeBlock() string
func DetectTrueColor ¶
DetectTrueColor reports whether TERM or COLORTERM advertises direct color support. This follows the same conservative signals used by ../vev.
func Dim ¶
Dim wraps s in dim SGR. Re-apply dim after sequences that clear faint so independently styled segments remain dimmed too. Like Bold and Italic, it restores only its own attribute so callers can safely compose styles.
func DimLines ¶ added in v0.2.0
DimLines returns a dimmed copy of lines. It is suitable for content behind a modal layer: the foreground layer can retain its normal styling while every styled segment in the background stays dimmed.
func ExtractLastNewText ¶
ExtractLastNewText finds the most recent `"newText"` field inside an array of edit objects, scanning from the end of raw backwards so we get the one currently being streamed rather than an earlier completed edit. Returns the partial string value the same way ExtractPartialStringField does, plus the 1-indexed edit number in the array (so the UI can show "edit 2 of N" or similar).
This is aimed at the `edit` tool's streaming shape:
{"path":"...","edits":[{"oldText":"x","newText":"y"},
{"oldText":"a","newText":"b<streaming>
We want to show `b<streaming>` while it grows.
func ExtractPartialStringField ¶
ExtractPartialStringField scans raw (a partial JSON object's bytes) for the given top-level string field and returns the unescaped value seen so far. If the value is still being written, it returns what's available with ok=true but done=false. If the closing unescaped quote has been reached, done=true.
This is deliberately small and best-effort: zut uses it to show the live body of a `write` tool call while the model is still typing it, before the full JSON object has been received. It assumes the field is a top-level key (no nested lookup), matches the first occurrence, and tolerates unfinished `\uXXXX` escapes by dropping a trailing incomplete escape sequence.
A production-grade JSON parser would be overkill for this use case; we only care about extracting one field incrementally.
func HighlightCode ¶
HighlightCode syntax-colors src and returns the result split into lines, ready for a line-based diff renderer. If no language is given or chroma has no lexer for it, src is returned as-is (one entry per line). Safe to call from multiple goroutines.
Results are memoised by (lang, src) so repeated calls from the view builder (which runs on every redraw) don't re-tokenise. Cache is bounded and evicts oldest entries past its cap.
func ImageDimensions ¶
ImageDimensions returns width and height in pixels, or zeros on error. Used for the text fallback so the user sees something useful.
func InlineImageFootprint ¶
InlineImageFootprint returns the rendered (rows, cells) footprint of an image at the requested cellsWide / maxRows budget, preserving aspect ratio. When the image's natural height exceeds maxRows, the rendered width shrinks below cellsWide so the aspect ratio is preserved within the row clamp; callers wrapping the image in a frame need that actual width to place a closing border at the right column.
func JoinRightBar ¶
JoinRightBar combines one main-pane row and one right-bar row without allowing either side to soft-wrap. The returned row occupies exactly mainWidth + RightBarSeparatorWidth + rightBarWidth display cells.
func LanguageFromPath ¶
LanguageFromPath maps file extensions to chroma lexer names.
func NormalizeInputStyle ¶
func NormalizeStatusPosition ¶
func NormalizeSubagentPosition ¶ added in v0.4.0
NormalizeSubagentPosition returns the placement for live subagent activity. A missing value keeps activity immediately below the input by default.
func ParseAppearanceCSI ¶ added in v0.24.0
func ParseAppearanceCSI(raw []byte) (scheme *SchemeEvent, mode *ModeReportEvent)
ParseAppearanceCSI parses the two runtime CSI response families used by terminal-owned themes: current scheme (997) and mode ownership (DECRQM).
func ReadClipboardImagePNG ¶
ReadClipboardImagePNG preserves the legacy Linux behavior. Linux image reads retain their clipboard MIME type through ReadClipboardImage instead.
func ReadClipboardText ¶
ReadClipboardText reads plain text from a Wayland or X11 clipboard. The small command-line clients are used to preserve zut's CGO-free build.
func RenderInlineImage ¶
func RenderInlineImage(proto ImageProtocol, data []byte, mime string, maxCellsWide int) string
RenderInlineImage returns a terminal escape sequence that draws data inline. If the protocol is None, returns "" so the caller can fall back to a text placeholder.
maxCellsWide caps the rendered width in terminal cells (columns) for protocols that honor it. 0 means "let the terminal decide".
func RenderInlineImageScaled ¶
func RenderInlineImageScaled(proto ImageProtocol, data []byte, mime string, maxCellsWide, maxCellsHigh int) string
RenderInlineImageScaled renders an image with both width and height clamps (in terminal cells). Values <= 0 mean "let the terminal decide".
func RenderMarkdown ¶
RenderMarkdown renders a small subset of Markdown to styled terminal text using theme colors. Supported: headings, bold, italic, inline code, fenced code blocks, bullet lists, numbered lists, blockquotes, simple GitHub-style tables. Not supported: links with complex formatting, HTML.
width is used to draw horizontal rules (e.g. around code fences). Pass 0 to use a reasonable fallback.
func RenderRightBar ¶
func RenderRightBar(th Theme, widgets []RightBarWidget, width, height int) []string
RenderRightBar renders a bounded, full-height side rail without adding a second frame around the host-owned separator. Widgets are sorted by extension name and ID so output stays deterministic even when extension frames arrive concurrently. Long lines are clipped with a three-dot ellipsis while reserving one cell of right padding.
func ReportCWD ¶
ReportCWD returns the OSC 7 sequence that tells the terminal the current working directory, formatted as a file URL. Terminals such as kitty, WezTerm, iTerm2, and GNOME Terminal use this to open new tabs / splits in the same directory. Returns "" for an empty path so callers can write it unconditionally. The path is percent-encoded per RFC 3986 (only unreserved characters and the path separator are left bare) and prefixed with the local hostname.
func ResetCursorColor ¶
func ResetCursorColor() string
func ResetCursorShape ¶
func ResetCursorShape() string
func RightBarColumns ¶
RightBarColumns returns the main-pane and side-rail widths for a terminal. It returns ok=false when keeping both panes usable would leave too little room for the rail; callers should then render right-bar widgets using their normal fallback placement.
func RowsForInlineImage ¶
RowsForInlineImage returns the number of terminal rows an image rendered at cellsWide columns will occupy, preserving aspect ratio. Clamped to maxRows. Returns 0 if the image cannot be decoded.
func SetScrollRegion ¶
SetScrollRegion returns the DECSTBM sequence to set the terminal's scroll region (1-indexed, inclusive). Lines that scroll out of this region still flow into the terminal's scrollback, but content above or below the region is not affected by scroll-induced movement.
func SetTitle ¶
SetTitle returns an OSC 0 sequence that sets the terminal's tab/window title. Control characters are removed from the payload so user- or model-provided text cannot inject another terminal control sequence.
func ShortArgs ¶
func ShortArgs(tool string, raw json.RawMessage) string
ShortArgs renders a tool call's arguments into a one-line suffix for the "tool name <args>" header. tool is the tool name so we can add shape-specific decorations: for read we append the requested line range (e.g. "path:1-200") pulled from the offset/limit args, which is useful context at a glance without expanding the result body. Other tools keep the legacy "path or command, truncated" shape.
The truncation width defaults to 60 cells but can be tuned via the ZUT_TOOL_ARG_WIDTH environment variable (see toolArgWidth).
Exported because the interactive mode pre-populates the ToolCallView.Args field with this value as soon as the tool call is announced, so the live overlay's header matches what the finalised transcript will later render.
func StatusBar ¶
func StatusBar(p StatusBarParams) []string
StatusBar builds the status shown above the editor. Always returns two lines when a cwd is provided: the stats on the first line, the cwd on its own line below, indented to match the stats column. This keeps the status bar stable across terminal resizes (the cwd never jumps from right-aligned-on-line-1 to flush-left-on-line-2) and makes a long cwd safe at any width.
Layout:
<busyPrefix> (provider) model stats <- line 1 cwd <- line 2 (2-space indent)
The old "ctrl+c exit - /help" / "esc cancel" hint is gone entirely. The slash-command popup and the queued/sliding-in chips already cover the discoverability of those keybindings.
func ThemeExists ¶
func UsageStatsParts ¶ added in v0.19.0
func UsageStatsParts(p UsageStatsParams) []string
UsageStatsParts returns compact, provider-neutral token and cost labels.
func WrapANSILine ¶
WrapANSILine is the exported form of wrapANSILine so other modes / dialogs can reuse the same visible-width-aware wrap behavior.
Types ¶
type AppearanceParser ¶ added in v0.24.0
type AppearanceParser struct {
// contains filtered or unexported fields
}
AppearanceParser controls which terminal replies may be consumed. Keeping the gate here prevents OSC-looking editor input from disappearing unless zut actively issued a matching query, while 997 notifications are accepted only after notification support is known.
func (*AppearanceParser) SetNotifications ¶ added in v0.24.0
func (p *AppearanceParser) SetNotifications(enabled bool)
func (*AppearanceParser) SetPendingColors ¶ added in v0.24.0
func (p *AppearanceParser) SetPendingColors(pending bool)
func (*AppearanceParser) SetPendingScheme ¶ added in v0.24.0
func (p *AppearanceParser) SetPendingScheme(pending bool)
SetPendingScheme permits one solicited 997 response and marks it so the event loop does not mistake it for a new terminal notification.
type AppearanceSource ¶ added in v0.24.0
type AppearanceSource struct {
// contains filtered or unexported fields
}
AppearanceSource filters accepted terminal appearance replies before they reach Reader. It deliberately leaves bracketed-paste payload opaque.
func NewAppearanceSource ¶ added in v0.24.0
func NewAppearanceSource(read func() (byte, error), peek func(time.Duration) (byte, bool, error), parser *AppearanceParser, emit func(InputEvent)) *AppearanceSource
func (*AppearanceSource) ReadByte ¶ added in v0.24.0
func (s *AppearanceSource) ReadByte() (byte, error)
type ClipboardImage ¶
ClipboardImage is an image read from the system clipboard.
func ReadClipboardImage ¶
func ReadClipboardImage(ctx context.Context) (ClipboardImage, bool, error)
ReadClipboardImage reads an image from the Wayland or X11 system clipboard. Clipboard helper failures are intentionally treated as an empty clipboard so that optional desktop integrations do not affect paste handling.
type ColorDepth ¶ added in v0.24.0
type ColorDepth uint8
ColorDepth is the terminal output capability used when resolving a color.
const ( // Indexed256 is the zero value to preserve the legacy behavior for // profiles assembled by callers that predate ColorDepth. ColorDepthIndexed256 ColorDepth = iota ColorDepthANSI16 ColorDepthTrueColor )
func DetectColorDepth ¶ added in v0.24.0
func DetectColorDepth(termEnv, colorTerm string) ColorDepth
DetectColorDepth conservatively chooses the highest color mode advertised by the environment. Terminals without a 256-color signal stay ANSI16.
type ColorEvent ¶ added in v0.24.0
type ColorEvent struct {
Kind int // 10 foreground, 11 background, 4 palette
Slot int
Color TerminalColor
}
ColorEvent is one default foreground/background or ANSI-palette reply.
func ParseAppearanceOSC ¶ added in v0.24.0
func ParseAppearanceOSC(raw []byte) []ColorEvent
ParseAppearanceOSC parses one complete BEL/ST-terminated OSC sequence. Combined OSC 4 responses produce one ColorEvent for every valid pair.
type Editor ¶
type Editor struct {
// Lines is the current buffer, one entry per line.
Lines []string
CursorR int // row index into Lines
CursorC int // rune index into Lines[CursorR]
Prompt string
MaxWidth int
// Mask replaces rendered input runes with asterisks while preserving the
// real buffer for submission. It is intended for secrets such as API keys.
Mask bool
// contains filtered or unexported fields
}
Editor is a simple multi-line text editor for the input area.
Users can type, paste, move the cursor, and submit. The editor exposes its rendered height and the current cursor row/col for the outer renderer. It does NOT draw itself directly; instead, Render() returns the visible lines.
func (*Editor) HandleKey ¶
HandleKey applies k to the editor. It returns submit=true when the user pressed enter and there is content to send; the caller should read SubmitValue() and then Clear().
func (*Editor) Insert ¶
Insert places s into the editor at the cursor, splitting on newlines so multi-line pastes preserve their structure.
func (*Editor) MoveVertical ¶
moveCursorVisual moves the cursor one visual row in direction dir (-1 = up, +1 = down) through the wrapped layout the user sees on screen. Handles both multi-line logical inputs and the case where a single long line wraps across several visual rows.
Algorithm: rebuild the same wrapped layout Render produces, tagging each visual row with (logicalRow, runeOffsetStart, runeOffsetEnd, leadingWidth). Find the row the cursor sits on, then pick (row+dir) and map the cursor's current visual column (minus the target row's leading indent) to a rune index inside that row's slice of its logical line. No-op at the top/bottom edges of the whole buffer. MoveVertical moves the cursor one visual row up/down through the rendered editor layout. It returns true when the cursor moved, false at the top/bottom edge. Callers can use false to fall back to outer UI scrolling.
func (*Editor) Render ¶
Render returns the editor's visible lines (wrapped to width). visualRow/visualCol describe where the cursor lands within the returned lines.
func (*Editor) SetValue ¶
SetValue replaces the buffer and places the cursor at the end. Also drops any stored pastes because the placeholders they back are now gone from the visible text.
func (*Editor) SubmitValue ¶
SubmitValue returns the buffer with every paste placeholder expanded to its stored body. Call once at submit time; the expansion is lossless (placeholders are only injected in HandleKey for KeyPaste with multi-line content).
Expansion is non-destructive: the internal paste map isn't touched. Clear() is what resets both the placeholder text and the map, and the caller already calls Clear() right after reading SubmitValue() as part of the submit flow.
func (*Editor) Value ¶
Value returns the buffer as a single string, WITHOUT expanding paste placeholders. Used for anything that should reflect what's visible on screen (history, slash-command detection, editor state). For the string that actually goes to the agent, use SubmitValue(), which expands each [paste #N +L lines] token back into the full pasted body.
type FloatingPane ¶ added in v0.18.0
type FloatingPane struct {
// contains filtered or unexported fields
}
FloatingPane is a stateful viewport for an independent TUI view. It keeps its scroll position while the same view is active, follows a focused row into view, and composes that view over a live background frame.
A FloatingPane is deliberately frontend-neutral: callers own their view's data and key handling, while the pane owns geometry, clipping, and visual composition.
func (*FloatingPane) Compose ¶ added in v0.18.0
func (p *FloatingPane) Compose(theme Theme, id, title string, background, content []string, cols, rows, contentCursorRow, contentCursorCol int) (pane FloatingPaneFrame, cursorRow, cursorCol int)
Compose returns a complete floating-pane frame. title is centered in the pane border. contentCursorRow is relative to content and is used both to retain the pane's own viewport and to return an absolute terminal cursor row. Pass -1 when the foreground has no text cursor.
func (*FloatingPane) Reset ¶ added in v0.18.0
func (p *FloatingPane) Reset()
Reset discards the viewport position. Callers normally do not need this: Compose resets it automatically when the view identity changes.
type FloatingPaneFrame ¶ added in v0.18.0
type FloatingPaneFrame struct {
Background []string
Lines []string
Rect FloatingPaneRect
}
FloatingPaneFrame contains the dimmed background and foreground rows to paint at absolute terminal positions. Renderer.DrawFloating consumes it.
type FloatingPaneRect ¶ added in v0.18.0
FloatingPaneRect describes a pane's outer border in zero-based terminal coordinates. Content occupies the rectangle inside that border.
func FloatingPaneMaxRect ¶ added in v0.18.0
func FloatingPaneMaxRect(cols, rows int) FloatingPaneRect
FloatingPaneMaxRect returns the largest pane for the current terminal. The final pane is shortened to its content by Compose. Below 80 columns it becomes a full-width bottom drawer so dialogs remain readable and usable.
func (FloatingPaneRect) ContentHeight ¶ added in v0.18.0
func (r FloatingPaneRect) ContentHeight() int
func (FloatingPaneRect) ContentWidth ¶ added in v0.18.0
func (r FloatingPaneRect) ContentWidth() int
type ImageProtocol ¶
type ImageProtocol int
ImageProtocol describes which inline-image escape the current terminal understands.
const ( ImageProtocolNone ImageProtocol = iota // no inline images, use text fallback ImageProtocolITerm2 // iTerm2 proprietary OSC 1337 File= (also: WezTerm) ImageProtocolKitty // Kitty graphics protocol )
func DetectImageProtocol ¶
func DetectImageProtocol() ImageProtocol
DetectImageProtocol returns the best inline-image protocol supported by the current terminal, or ImageProtocolNone.
The default is to auto-detect: if the terminal advertises iTerm2 or Kitty-graphics support, we use it. The ZUT_INLINE_IMAGES env var overrides the default:
ZUT_INLINE_IMAGES=off -> force text fallback ZUT_INLINE_IMAGES=placeholder -> force text fallback (alias for off) ZUT_INLINE_IMAGES=iterm -> force iTerm2 protocol ZUT_INLINE_IMAGES=kitty -> force Kitty protocol ZUT_INLINE_IMAGES=auto -> explicit auto-detect (same as default)
type InputEvent ¶ added in v0.24.0
type InputEvent struct {
Key *Key
Scheme *SchemeEvent
Color *ColorEvent
Mode *ModeReportEvent
}
InputEvent is emitted by the appearance-aware input path. Exactly one field is set. Key bytes that do not form an accepted protocol reply remain keys.
type Key ¶
type Key struct {
Kind KeyKind
Rune rune // for KeyRune
Paste string // for KeyPaste
Ctrl bool
Alt bool
Shift bool
Super bool
}
Key is a parsed keypress.
type KeyKind ¶
type KeyKind int
const ( KeyRune KeyKind = iota KeyEnter KeyBackspace KeyTab KeyShiftTab KeyEsc KeyUp KeyDown KeyLeft KeyRight KeyHome KeyEnd KeyPageUp KeyPageDown KeyDelete KeyCtrlC KeyCtrlD KeyCtrlL KeyCtrlU KeyCtrlK KeyCtrlA KeyCtrlB KeyCtrlE KeyCtrlW KeyCtrlO KeyPaste KeyPasteClipboard KeyMouseWheelUp KeyMouseWheelDown KeyUnknown )
type MessageAnchor ¶
type MessageAnchor struct {
MessageIdx int // index into v.Messages
Row int // first row of that message in the Build() output
}
MessageAnchor records where a rendered message starts in the chat line slice. Used by /jump so the dialog can scroll the viewport to the row where a turn's user prompt begins.
type ModeReportEvent ¶ added in v0.24.0
ModeReportEvent is a DECRQM response. Status follows the terminal protocol: 1/3 set, 2 reset, 0/4 unsupported or permanently reset.
type ProcTerm ¶
type ProcTerm struct {
// contains filtered or unexported fields
}
ProcTerm is a Terminal bound to the current process's tty.
func NewProcTerm ¶
func NewProcTerm() *ProcTerm
NewProcTerm returns a Terminal bound to stdin/stdout.
func (*ProcTerm) PeekByteTimeout ¶
PeekByteTimeout uses a platform-specific non-blocking read to decide whether another byte is available within d. If not, returns (0, false, nil).
func (*ProcTerm) SetNonblock ¶
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader parses a byte stream into Key events. It understands basic xterm escape sequences and bracketed paste.
type Renderer ¶
type Renderer struct {
// contains filtered or unexported fields
}
Renderer maintains a previous frame and writes only the lines that changed on each Draw(). Callers pass a full target frame (slice of styled lines, already wrapped to width).
func NewRenderer ¶
NewRenderer returns a renderer that writes to out.
Detects VS Code's integrated terminal via $TERM_PROGRAM and, when detected, disables emission of \x1b[3J for the reasons documented on Renderer.keepScrollback. The env var is set by VS Code itself (and by Cursor, which forks VS Code's terminal — same xterm.js, same bug), so no user configuration is required.
func (*Renderer) Clear ¶
func (r *Renderer) Clear()
Clear forces a full repaint on the next Draw and clears the screen plus scrollback. In main-screen flow mode this is required whenever already-emitted transcript layout changes (for example ctrl+o expand/collapse), because terminal scrollback cannot be edited reliably once printed.
func (*Renderer) DrawFloating ¶ added in v0.18.0
func (r *Renderer) DrawFloating(pane FloatingPaneFrame, cursorRow, cursorCol int)
DrawFloating paints a complete, dimmed live background and then an opaque floating pane at absolute coordinates. The background is deliberately invalidated on every call: the pane is not represented in Draw's frame cache, so repainting it first prevents stale foreground cells when either layer changes or the terminal is resized.
func (*Renderer) DrawLog ¶
DrawLog renders zut in the terminal's main screen as normal terminal flow rather than a fixed full-screen frame. Chat lines are emitted once into the host terminal scrollback; the current bottom block (dialogs, slash popup, status, editor) is erased and redrawn in place at the end.
cursorBottomRow/cursorCol are offsets into bottom, not the full frame.
func (*Renderer) DrawRightBar ¶
DrawRightBar renders the complete transcript through DrawLog, then composites the persistent rail over the visible viewport. The flow cache remains authoritative so appended chat still enters native scrollback.
func (*Renderer) DrawRightBarDimmed ¶ added in v0.2.0
func (r *Renderer) DrawRightBarDimmed(chat, bottom, rightBar []string, cursorBottomRow, cursorCol int)
DrawRightBarDimmed renders a right-bar frame whose separator is part of a dimmed backdrop. Callers must pass already-dimmed main and right-bar rows.
func (*Renderer) Invalidate ¶
func (r *Renderer) Invalidate()
Invalidate forces a full repaint on the next Draw without clearing the whole terminal first. Useful when the cached diff is unreliable but a visible full-screen flash would be too distracting.
func (*Renderer) KeepsScrollback ¶
KeepsScrollback reports whether this renderer suppresses the scrollback-clear escape (true under VS Code's terminal). Callers use it to pick a viewport-safe full repaint (Invalidate) over a scrollback-clearing one (Clear) when redrawing overlays.
func (*Renderer) ResetScrollRegion ¶
func (r *Renderer) ResetScrollRegion()
Resize tells the renderer the current terminal size.
On a real size change we also issue a clear-screen so the next Draw starts from a blank slate. Without the clear, characters from the old (wider) layout linger past the new right edge and rows from before the new bottom hang around as garbage.
type RightBarWidget ¶
RightBarWidget is declarative content for one persistent extension widget. The host owns ordering and layout; widgets are display-only in the first version and should use OpenPanel for interaction.
type SchemeEvent ¶ added in v0.24.0
SchemeEvent is a reported terminal color-scheme preference. Solicited is true only for the reply to a query initiated by zut.
type StatusBarParams ¶
type StatusBarParams struct {
Theme Theme
Provider string
Model string
Reasoning string // "" means thinking off
FastMode bool // show the provider's opt-in fast tier when enabled
Busy bool
BusyPrefix string // spinner + funny line when busy
CWD string
Locked bool // sandbox on?
NoYolo bool // confirmation mode enabled?
GoalStatus string // autonomous goal lifecycle, empty when none
// Cumulative session usage and cost.
Usage provider.Usage
// Subscription is true when the credential is an OAuth token (claude
// pro/max, chatgpt plus/pro) rather than a paid api key. We still
// compute a cost for visibility and append "(sub)" so the user
// knows no real money moved.
Subscription bool
// Last turn's input+cache tokens (approximates current live context).
ContextUsed int
ContextMax int // model's context window; 0 disables the percentage
// AutoCompacting is true when the agent is currently running a
// model-triggered condense pass. Surfaces as "(auto)" after the
// context percentage so it's clear where the spinner is coming from.
AutoCompacting bool
// Telegram true when the telegram bridge is connected. Adds a
// small "- tg -" tag to the cwd line so the user can tell at a
// glance that dms are being mirrored into this session.
Telegram bool
Cols int // terminal width; drives right-alignment of cwd
}
StatusBarParams groups the many bits of state the status bar needs. Grew from a flat argument list once we settled on the layout.
type StringSpinner ¶ added in v0.16.0
type StringSpinner struct {
// contains filtered or unexported fields
}
StringSpinner selects one text frame for each configured interval. It owns no ticker or goroutine; callers render it from their existing UI clock.
func NewStringSpinner ¶ added in v0.16.0
func NewStringSpinner(frames []string, interval time.Duration) StringSpinner
NewStringSpinner creates a reusable text animation. Empty frames render an empty string, and a non-positive interval keeps the first frame stable.
type SyntaxTheme ¶
type SyntaxTheme struct {
Keyword string
KeywordConstant string
KeywordDeclaration string
KeywordNamespace string
KeywordReserved string
KeywordType string
NameBuiltin string
NameFunction string
NameClass string
NameDecorator string
LiteralString string
LiteralStringEscape string
LiteralNumber string
Comment string
CommentPreproc string
Operator string
Punctuation string
Text string
}
SyntaxTheme contains the chroma token colors used by code fences, file previews, and diffs. Values are chroma style entries, so they may include attributes after the color (for example "#81a1c1 bold").
type SyntaxThemeOverrides ¶
type SyntaxThemeOverrides struct {
Keyword *string `json:"keyword,omitempty"`
KeywordConstant *string `json:"keyword_constant,omitempty"`
KeywordDeclaration *string `json:"keyword_declaration,omitempty"`
KeywordNamespace *string `json:"keyword_namespace,omitempty"`
KeywordReserved *string `json:"keyword_reserved,omitempty"`
KeywordType *string `json:"keyword_type,omitempty"`
NameBuiltin *string `json:"name_builtin,omitempty"`
NameFunction *string `json:"name_function,omitempty"`
NameClass *string `json:"name_class,omitempty"`
NameDecorator *string `json:"name_decorator,omitempty"`
LiteralString *string `json:"literal_string,omitempty"`
LiteralStringEscape *string `json:"literal_string_escape,omitempty"`
LiteralNumber *string `json:"literal_number,omitempty"`
Comment *string `json:"comment,omitempty"`
CommentPreproc *string `json:"comment_preproc,omitempty"`
Operator *string `json:"operator,omitempty"`
Punctuation *string `json:"punctuation,omitempty"`
Text *string `json:"text,omitempty"`
}
type Terminal ¶
type Terminal interface {
io.Writer
// Size returns (cols, rows).
Size() (int, int)
// OnResize registers a callback invoked on SIGWINCH (best effort).
OnResize(func())
// EnterRaw puts the tty into raw mode. Returns a restore func.
EnterRaw() (restore func() error, err error)
// ReadByte reads one byte of input. Blocks.
ReadByte() (byte, error)
// PeekByteTimeout reads one byte of input but returns (0, false, nil)
// if no byte arrives within the timeout. Used to disambiguate bare
// Esc from the start of an escape sequence.
PeekByteTimeout(time.Duration) (byte, bool, error)
// SetNonblock sets stdin to non-blocking mode (used by paste handling).
// May be a no-op on some platforms.
SetNonblock(bool) error
}
Terminal abstracts the real terminal for tests.
type TerminalColor ¶
TerminalColor describes both explicit colors and terminal-owned colors. TerminalDefault and TerminalPaletteSlot intentionally differ from literal xterm-256 values: an adaptive theme follows the terminal palette while a custom numeric value retains its xterm meaning.
func Color256 ¶
func Color256(index int) TerminalColor
func ColorANSI ¶
func ColorANSI(sgr int) TerminalColor
func ColorRGB ¶
func ColorRGB(r, g, b int) TerminalColor
func TerminalDefault ¶ added in v0.24.0
func TerminalDefault() TerminalColor
func TerminalPaletteSlot ¶ added in v0.24.0
func TerminalPaletteSlot(index int) TerminalColor
type TerminalColorValue ¶
type TerminalColorValue struct {
TerminalColor
}
TerminalColorValue accepts any of these JSON forms:
24 // xterm-256 color index
"#42454b" // RGB hex
{"mode":"ansi","index":100}
{"mode":"rgb","r":66,"g":69,"b":75}
{"mode":"256","index":254}
func (*TerminalColorValue) UnmarshalJSON ¶
func (c *TerminalColorValue) UnmarshalJSON(data []byte) error
type TerminalProfile ¶
type TerminalProfile struct {
Foreground TerminalColor
Background TerminalColor
HasForeground bool
HasBackground bool
Palette [16]TerminalColor
PaletteKnown uint16
Depth ColorDepth
// TrueColor is retained for callers compiled against the older profile.
// Depth is authoritative when it is ColorDepthTrueColor.
TrueColor bool
Light bool
SchemeKnown bool
}
TerminalProfile is the best-effort color snapshot reported by the controlling terminal. Palette entries are optional; an unknown slot is emitted as its direct ANSI SGR rather than substituted with a fixed zut RGB.
func (TerminalProfile) ColorDepth ¶ added in v0.24.0
func (p TerminalProfile) ColorDepth() ColorDepth
func (TerminalProfile) PaletteColor ¶
func (p TerminalProfile) PaletteColor(index int) (TerminalColor, bool)
PaletteColor returns a reported ANSI palette entry when available.
type Theme ¶
type Theme struct {
FG TerminalColor
Muted TerminalColor
Accent TerminalColor
Background *TerminalColor // optional full-row TUI background; nil keeps terminal default
User TerminalColor // label color for the user role
UserBubbleBG TerminalColor // background tint behind user message rows
UserBubbleFG TerminalColor // foreground colour for user message rows
Assistant TerminalColor // label color for the zut role
Tool TerminalColor
ToolOut TerminalColor
Error TerminalColor
Warning TerminalColor
Spinner TerminalColor // spinner frame and activity label
ThinkingMax TerminalColor // status color for the opt-in max reasoning level
SelectionBG TerminalColor // background for highlighted rows
SelectionFG TerminalColor // foreground for highlighted rows
// UseTerminalPalette resolves TerminalPaletteSlot roles against the
// reported palette on truecolor terminals. It has no effect on explicit
// Color256 values from a custom theme.
UseTerminalPalette bool
Terminal TerminalProfile
SpinnerFrames []string
SpinnerIntervalMS int
SyntaxBaseStyle string
Syntax SyntaxTheme
}
Semantic palette used by zut. Each role is a TerminalColor so themes can use indexed, ANSI, or RGB values without changing render code.
func DetectThemeFromBackground ¶
DetectThemeFromBackground queries the controlling tty for its current foreground, background, and ANSI palette using OSC 10/11/4. Auto is always terminal-owned; the snapshot is retained for subsequent runtime resolution.
The query / parse runs synchronously before the TUI is initialised so the returned snapshot can drive the entire session. We briefly put stdin into raw mode and disable echo so OSC replies do not leak onto the user's screen.
func DetectThemeWithCustom ¶
DetectThemeWithCustom performs the initial bounded profile query then uses the same loader and pure resolver as runtime selection.
func LoadThemeFromHome ¶
LoadThemeFromHome is retained as the startup convenience wrapper. New runtime code should keep the ThemeSource and call ResolveTheme directly.
func TerminalTheme ¶ added in v0.24.0
func TerminalTheme(profile TerminalProfile) Theme
TerminalTheme constructs zut's adaptive default from terminal-owned defaults and ANSI slots. It never chooses a fixed built-in palette merely because a terminal reports a light background.
func (Theme) AccentBar ¶
func (t Theme) AccentBar(c TerminalColor) string
AccentBar returns a 2-cell-wide leader: a coloured half-block glyph followed by a plain space gutter. Used as the speaker-label prefix in the chat ("▌ you", "▌ zut") and as the editor prompt so the bar reads consistently across the UI.
func (Theme) BG ¶
func (t Theme) BG(c TerminalColor, s string) string
BG wraps s in a terminal background color. RGB values are quantized when the active terminal does not advertise truecolor support.
func (Theme) BG256
deprecated
func (t Theme) BG256(c TerminalColor, s string) string
BG256 retains the historical helper name while accepting the full TerminalColor model.
Deprecated: use BG.
func (Theme) BackgroundStyle ¶
BackgroundStyle returns the SGR prefix for the optional full-row TUI background. Empty means zut should leave the terminal's configured background untouched.
func (Theme) DimColor ¶
func (t Theme) DimColor(color TerminalColor, percent int) TerminalColor
DimColor fades a theme color toward the terminal background. It is used while resolving adaptive terminal surfaces and by overlay callers.
func (Theme) FG256
deprecated
func (t Theme) FG256(c TerminalColor, s string) string
FG256 retains the historical helper name while accepting the full TerminalColor model.
Deprecated: use FGColor.
func (Theme) FGColor ¶
func (t Theme) FGColor(c TerminalColor, s string) string
FGColor wraps s in a foreground color. The name is intentionally explicit because the color may be xterm-256, ANSI, or RGB.
func (Theme) Highlight ¶
Highlight paints s with the theme's selection colors (foreground + background). The caller is responsible for padding s to the desired width; styling alone does not extend the background past content.
func (Theme) HighlightCode ¶
HighlightCode syntax-colors src using this theme's syntax palette.
func (Theme) PadHighlight ¶
PadHighlight styles s and extends the selection background to the full terminal width so the highlight is a full row, not just a rectangle around the text.
func (Theme) SelectionStyle ¶
SelectionStyle returns the SGR prefix for the theme's selected row.
func (Theme) SelectionStyleFG ¶
func (t Theme) SelectionStyleFG(fg TerminalColor) string
SelectionStyleFG returns the SGR prefix for selected-row text with a custom foreground. Useful for preserving semantic marks inside a highlighted row without hardcoding escape sequences outside theme.go.
func (Theme) UserBubble ¶
UserBubble paints a single user message row with the bubble background colour, padding to width so the tint extends to the full terminal width. Foreground stays in UserBubbleFG so text remains legible against the tint.
func (Theme) UserBubbleRow ¶
UserBubbleRow renders one user-bubble row prefixed with a coloured half-block accent bar ("▌ ") so every line of the bubble has the zut-blue gutter at the very left. The bar lives outside the bubble tint (chat bg) so the bubble itself sits inside it. Width is the outer width including the bar; the bubble content is padded to width-2 (the bar + its trailing space).
type ThemeFile ¶
type ThemeFile struct {
Name string `json:"name"`
Description string `json:"description"`
Colors ThemeFileColorModes `json:"colors"`
Overrides ThemeOverrides `json:"-"`
}
ThemeFile is the user-editable JSON shape loaded from $ZUT_HOME/themes/*.json. It carries metadata plus separate overrides for dark and light terminals.
func (*ThemeFile) UnmarshalJSON ¶
type ThemeFileColorModes ¶
type ThemeFileColorModes struct {
Base ThemeOverrides `json:"-"`
Dark ThemeOverrides `json:"dark"`
Light ThemeOverrides `json:"light"`
HasDark bool `json:"-"`
HasLight bool `json:"-"`
}
func (*ThemeFileColorModes) UnmarshalJSON ¶
func (m *ThemeFileColorModes) UnmarshalJSON(data []byte) error
type ThemeOption ¶
ThemeOption is one selectable theme discovered under $ZUT_HOME/themes. Value is stored in config.json.
func AvailableThemes ¶
func AvailableThemes(zutHome string) []ThemeOption
AvailableThemes returns built-in and user-installed themes suitable for a settings picker. Invalid JSON files are skipped.
func ThemeOptionFromFile ¶
func ThemeOptionFromFile(path, value, source string) (ThemeOption, bool)
ThemeOptionFromFile parses one theme JSON file for picker display. value is what will be stored in config; pass an absolute path for extension-owned themes so they can be loaded without copying into $ZUT_HOME/themes.
type ThemeOverrides ¶
type ThemeOverrides struct {
FG *TerminalColorValue `json:"fg,omitempty"`
Muted *TerminalColorValue `json:"muted,omitempty"`
Accent *TerminalColorValue `json:"accent,omitempty"`
Background *TerminalColorValue `json:"background,omitempty"`
User *TerminalColorValue `json:"user,omitempty"`
UserBubbleBG *TerminalColorValue `json:"user_bubble_bg,omitempty"`
UserBubbleFG *TerminalColorValue `json:"user_bubble_fg,omitempty"`
Assistant *TerminalColorValue `json:"assistant,omitempty"`
Tool *TerminalColorValue `json:"tool,omitempty"`
ToolOut *TerminalColorValue `json:"tool_out,omitempty"`
Error *TerminalColorValue `json:"error,omitempty"`
Warning *TerminalColorValue `json:"warning,omitempty"`
Spinner *TerminalColorValue `json:"spinner,omitempty"`
ThinkingMax *TerminalColorValue `json:"thinking_max,omitempty"`
ThinkingMaxCamel *TerminalColorValue `json:"thinkingMax,omitempty"`
SelectionBG *TerminalColorValue `json:"selection_bg,omitempty"`
SelectionFG *TerminalColorValue `json:"selection_fg,omitempty"`
SpinnerFrames []string `json:"spinner_frames,omitempty"`
SpinnerIntervalMS *int `json:"spinner_interval_ms,omitempty"`
SyntaxBaseStyle *string `json:"syntax_base_style,omitempty"`
Syntax SyntaxThemeOverrides `json:"syntax,omitempty"`
}
ThemeOverrides is intentionally pointer-based so a theme file can override only the colors it cares about and inherit the built-in dark/light defaults for everything else.
type ThemePreference ¶ added in v0.24.0
ThemePreference separates the persisted setting from the process-only ZUT_THEME override. Only dark/light force a running session.
func ResolveThemePreference ¶ added in v0.24.0
func ResolveThemePreference(persisted, env string) ThemePreference
type ThemeResolution ¶ added in v0.24.0
ThemeResolution is the pure result of resolving a preference against one terminal snapshot and, for custom preferences, one accepted source file.
func ResolveTheme ¶ added in v0.24.0
func ResolveTheme(preference string, source *ThemeSource, profile TerminalProfile) ThemeResolution
ResolveTheme performs no I/O. Custom themes always overlay TerminalTheme, so omitted roles continue to follow the controlling terminal.
type ThemeSource ¶ added in v0.24.0
ThemeSource is an immutable, fully validated custom theme revision. Runtime profile changes resolve this value without touching the filesystem again.
func LoadThemeSource ¶ added in v0.24.0
func LoadThemeSource(zutHome, preference string) (*ThemeSource, error)
LoadThemeSource resolves and validates a custom source. Built-in selections have no source and return nil, nil. The file limit prevents a polling reload from allocating an unbounded partial write.
type ToolCallView ¶
type ToolCallView struct {
ID string
Name string
// Revision is advanced by the owning interactive state whenever a
// visible field changes. A non-zero revision lets the live render cache
// avoid rescanning a large result string on every redraw.
Revision uint64
Args string // rendered argument summary
Preview string // side-effect-free result shown before confirmation
Result string // rendered result preview (truncated)
Error bool
Done bool
// Streaming is true while the model is still typing the tool
// call's JSON arguments. The TUI renders a live preview of any
// interesting string fields (for `write`, the `content`; for
// `bash`, the `command`) so the user can watch the file being
// composed. Set to false as soon as EvToolUseEnd arrives.
Streaming bool
// RawJSONBuf is the accumulator of every EvToolUseArgs delta
// the stream has delivered for this tool call. Used by the
// partial-JSON extractor to peel off the live string value
// of one named field on each render.
RawJSONBuf string
// LivePath is the `path` arg extracted as soon as it parses
// out of RawJSONBuf. Shown next to the tool name in the header
// so the user can see which file is being written to.
LivePath string
}
ToolCallView is a pending tool invocation plus optional result.
type UsageStatsParams ¶ added in v0.19.0
UsageStatsParams describes cumulative usage shown by compact status surfaces.
type View ¶
type View struct {
Theme Theme
ImageProto ImageProtocol // how to render inline images in this terminal
Messages []provider.Message
// MessagesRevision is supplied by the owning transcript when available.
// Append-only revisions let Build reuse prior message rows without
// hashing every existing payload. Zero keeps the standalone hash cache
// behaviour for callers that do not have a revision source.
MessagesRevision uint64
// RenderCacheRevision changes whenever a visual rendering dependency
// changes. Interactive mode includes it in its stable transcript key so
// the outer cache cannot bypass View's own theme/layout cache checks.
RenderCacheRevision uint64
Streaming string // current assistant text delta
StreamingActive bool
ToolCalls []ToolCallView // tool calls in flight or completed
// Startup resource fields list host-loaded inputs before the transcript
// without creating provider messages or persisted entries.
StartupAgentName string
StartupContextPaths []string
StartupExtensionNames []string
StartupSkillNames []string
StatusLine string
Err string
// FlatTools renders tool calls without the bordered panel: a quiet
// header line per call plus indented, frameless output. The
// truncation/expand behaviour and theme colors are unchanged.
// False (the default) keeps the bordered box.
FlatTools bool
// CompactUser renders sent user messages as a single quiet gutter
// line per wrapped row instead of a tinted bubble with a blank
// padding row above and below. False (the default) keeps the
// padded, background-tinted bubble.
CompactUser bool
// CompactMode reduces visual chrome in the transcript. Tool calls
// render with a flat header and no bordered panel, and sent user
// messages render without padded background bubbles. False keeps
// the current spacious rendering.
CompactMode bool
// ExpandAll forces every long tool result to render in full.
// Toggled from the tui by ctrl+o. When false, results longer than
// ToolCollapseLines collapse to ToolCollapsePreview lines plus a
// "... (N more lines, M total, ctrl+o to expand)" footer.
ExpandAll bool
// TailLimit caps how many messages from the END of Messages are
// rendered. Messages older than the limit emit a zero-row slice
// so first paint after a session resume doesn't pay the markdown
// / chroma cost for the entire transcript at once. 0 means no
// limit (render everything, the historical behaviour). Interactive
// raises the cap when the user scrolls past the top of the
// already-rendered tail.
TailLimit int
// contains filtered or unexported fields
}
View turns a transcript + live state into a slice of styled lines, already wrapped to width.
func (*View) AdoptRenderCacheFrom ¶ added in v0.11.1
AdoptRenderCacheFrom transfers caches produced from a render snapshot back to the owning view. Callers must ensure the transcript revision is still current before adopting them.
func (*View) BuildLive ¶
BuildLive renders only in-flight assistant/tool/error state. Main-screen scrollback renderers can keep these rows outside the immutable transcript so native scrolling stays stable while a turn streams.
func (*View) BuildWithAnchors ¶
func (v *View) BuildWithAnchors(width int) ([]string, []MessageAnchor)
BuildWithAnchors is like Build but additionally reports the first row occupied by each message in v.Messages. Callers that need to scroll to a specific turn (the /jump dialog) use the anchor slice to map a message index back to a row offset.
func (*View) CloneForRender ¶ added in v0.11.1
CloneForRender returns an immutable render snapshot. Its mutable cache maps are copied so a renderer owner can build outside the interactive state mutex without racing the next snapshot.
func (*View) InvalidateRenderCache ¶
func (v *View) InvalidateRenderCache()
InvalidateRenderCache drops all cached message renders. The tui calls this when the transcript is replaced wholesale (/compact, /clear, session swap) since messages can be replaced in place and a content-hash miss alone doesn't reclaim the old entries.
func (*View) RenderToolCall ¶
func (v *View) RenderToolCall(tc ToolCallView, width int) []string
RenderToolCall renders one live or completed tool call using the same presentation as tool calls in the main transcript. Dialogs with isolated agent loops use this to avoid maintaining a second tool renderer.