components

package
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var SlashCommands = []SlashCmd{
	{"/clear", "start a new conversation"},
	{"/compact", "compact the current conversation"},
	{"/exit", "exit Looprig"},
}

SlashCommands is the canonical list (exported so package tui can map Name→action).

Functions

This section is empty.

Types

type FileComplete

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

FileComplete is a filtered file list with a wrapping cursor — the @path completion panel, the disk-backed sibling of SlashComplete. It is display-only: package tui computes the candidate list (the filesystem read) and feeds it here.

func NewFileComplete

func NewFileComplete(items []FileItem) *FileComplete

NewFileComplete returns a completer over items, or nil when empty (nil = hidden).

func (*FileComplete) Cursor

func (f *FileComplete) Cursor() int

Cursor returns the absolute selected index in the filtered list.

func (*FileComplete) Down

func (f *FileComplete) Down()

Down moves the cursor down, wrapping to the top.

func (*FileComplete) SelectWindowRow

func (f *FileComplete) SelectWindowRow(row, maxRows int) bool

SelectWindowRow moves the cursor to a row in the currently rendered maxRows window. It returns whether the selection changed; rows outside the visible window are ignored.

func (*FileComplete) Selected

func (f *FileComplete) Selected() FileItem

Selected returns the item under the cursor.

func (*FileComplete) Up

func (f *FileComplete) Up()

Up moves the cursor up, wrapping to the bottom.

func (*FileComplete) View

func (f *FileComplete) View() string

View renders the filtered list at its natural content width, which is the width the engine was built with: the rows never change, so neither does it.

func (*FileComplete) ViewWidth

func (f *FileComplete) ViewWidth(width int) string

ViewWidth renders the filtered list as a tray whose rows are padded or clamped ANSI-safely to width display columns.

func (*FileComplete) ViewWindow

func (f *FileComplete) ViewWindow(width, maxRows int) string

ViewWindow renders a full-width tray capped to maxRows and keeps the selected path in the visible window. View and ViewWidth remain the unbounded variants.

type FileItem

type FileItem struct {
	Path  string
	IsDir bool
}

FileItem is one @path completion candidate. Path is the value to complete to (e.g. "src" or "src/main.go"); IsDir drives the trailing "/" affordance and whether selecting it keeps the panel open to drill in.

type InputBox

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

InputBox wraps a bubbles textarea: an auto-growing editor with the shared "▌" accent bar as its prompt (matching user-message rows), rendered inside a bordered box. No char limit, no line numbers, no "> " prompt. The box height tracks the content between minLines and maxInputLines.

minLines, bg, and padV are per-INSTANCE so a single composer implementation serves both shells: the scrollback Screen keeps the historical 1-line, background-free, unpadded editor (the NewInputBox defaults), and the modern viewport opts into a taller, gray-filled, padded panel via SetMinLines/SetBackground/SetVerticalPadding. Nothing else changes, so the scrollback composer stays byte-identical.

func NewInputBox

func NewInputBox() InputBox

NewInputBox returns a configured, focused prompt editor.

Enter is left unbound on the textarea so screen.go can use it as submit; newline insertion is bound to TWO keys so it works regardless of terminal capability:

  • Shift+Enter (PRIMARY, preferred) — only distinguishable from plain Enter on terminals that implement the Kitty keyboard protocol AND only when the program requests "report all keys as escape codes" (flag 8). screen.go's View() sets KeyboardEnhancements.ReportAllKeysAsEscapeCodes for exactly this reason; without it the Kitty spec keeps Enter as a legacy byte and Shift+Enter arrives as plain Enter (→ submit). Supported on kitty, Ghostty, WezTerm, foot, Alacritty, and recent iTerm2 (with the protocol option enabled).
  • Ctrl+J (UNIVERSAL FALLBACK) — the LF byte (0x0A), delivered by EVERY terminal with no protocol required; v2 decodes it as Code 'j' + ModCtrl (String()=="ctrl+j"). This is the only way to type a literal newline on terminals that cannot deliver a distinct Shift+Enter (Apple Terminal, many VS Code setups). It is purely additive — Shift+Enter stays primary. Ctrl+J does not collide with any global binding in screen.go (which handles only ctrl+c, ctrl+t, and esc).

func (*InputBox) DisplayValue added in v0.21.0

func (b *InputBox) DisplayValue() string

DisplayValue returns the compact text held by the editor. Invisible marker boundaries distinguish retained paste segments from marker-looking text typed by the user.

func (*InputBox) Focus

func (b *InputBox) Focus() tea.Cmd

Focus focuses the editor and returns its Blink command.

func (InputBox) Height

func (b InputBox) Height() int

Height is the editor's visible content height in rows: the textarea's current row count clamped to [minInputLines, maxInputLines]. It excludes the border frame.

It reads ta.Height() rather than ta.LineCount() so it tracks VISUAL rows (a single long logical line that soft-wraps occupies several rows), matching what View() actually renders. DynamicHeight keeps ta.Height() equal to the total visual line count (capped at contentHeightSecurityLimit, far above maxInputLines), so once capHeight has applied the visible cap this returns that capped value, and before capping it returns the true content height — both already within [min, max] after clamp.

func (*InputBox) Reset

func (b *InputBox) Reset()

Reset clears the text.

func (*InputBox) ResetPlaceholder added in v0.17.0

func (b *InputBox) ResetPlaceholder()

ResetPlaceholder restores the ordinary compose hint after a temporary picker closes.

func (*InputBox) Resize

func (b *InputBox) Resize(width int)

Resize sets the box width; the inner textarea is the box width minus the border's horizontal frame. The height auto-grows with content, so it is not set here.

func (*InputBox) SetBackground

func (b *InputBox) SetBackground(bg color.Color)

SetBackground enables the MODERN gray panel fill of color bg behind every composer row. It derives bg's SGR open/reset pair ONCE (styles.DeriveBackgroundSGR) and View then paints each rendered line to the box width with it — a per-row fill that re-opens the background after the textarea's internal SGR resets, so it never leaves the holes a plain Background() wrap does (and the empty end-of-buffer rows fill too). It does NOT tint the textarea's own Base style: the focused cursor line therefore keeps the empty style NewInputBox already set (no default "black box"), and the uniform post-fill supplies the gray instead. The scrollback Screen never calls this, so its composer stays background-free (styles.BoxStyle). MODERN-safe: the viewport re-renders the whole frame per tick, so the fill never strands into scrollback the way it could in the print-once surface.

func (*InputBox) SetMinLines

func (b *InputBox) SetMinLines(n int)

SetMinLines sets the composer's minimum visible height (default minInputLines). The MODERN viewport uses 2 for a roomier panel; the scrollback Screen never calls this, so it keeps the historical single line. Below-1 values are ignored (fail-safe). It moves BOTH the textarea's own MinHeight and the visible cap in lockstep, then re-caps so the change takes effect immediately.

func (*InputBox) SetPlaceholder added in v0.17.0

func (b *InputBox) SetPlaceholder(s string)

SetPlaceholder changes the empty-editor hint without changing its value. Pickers reuse the existing bottom input box as their search field, so the hint has to describe that temporary context rather than suggest a chat submission.

func (*InputBox) SetValue

func (b *InputBox) SetValue(s string)

SetValue replaces the text.

func (*InputBox) SetVerticalPadding

func (b *InputBox) SetVerticalPadding(n int)

SetVerticalPadding sets the number of padding rows View draws ABOVE and BELOW the text region, so the modern composer reads as a padded box ([pad][text…][pad]) rather than a bare line. It defaults to 0 (the scrollback Screen never calls this, so its composer stays byte-identical); the modern viewport sets 1. Negative values are ignored (fail-safe). Each padding row carries the box's ▌ accent edge (the rail runs unbroken through the padding), gray-filled by the modern panel (SetBackground) so it reads as part of the box. Padding does NOT change the editor's auto-grow — the text region still grows to maxInputLines — it only frames it, so the box's rendered height is the text height plus 2*padV.

func (*InputBox) Update

func (b *InputBox) Update(msg tea.Msg) tea.Cmd

Update forwards the message to the textarea and grows the editor to fit the current content (capped at maxInputLines, past which it scrolls internally).

func (*InputBox) Value

func (b *InputBox) Value() string

Value returns the current text with collapsed paste markers expanded to the exact original payloads.

func (*InputBox) View

func (b *InputBox) View() string

View renders the editor inside the bordered box. The box grows with the content because the inner textarea height tracks Height(). In MODERN mode (SetBackground called) every rendered row — the ▌ edge, its one-column left pad, the text, and any empty end-of-buffer rows — is filled to the box width with the gray panel color, so the composer reads as one continuous panel; the default (scrollback) box paints nothing.

With vertical padding (SetVerticalPadding, modern sets 1) padV rail rows are added ABOVE and BELOW the text rows so the composer reads as a padded box ([pad][text…][pad]) rather than a bare line. A padding row is the box's ▌ edge alone (so the accent rail runs unbroken through it), gray-filled to the box width when a background is set. The scrollback composer sets neither background nor padding, so it returns the bare box unchanged (byte-identical).

type SessionComplete

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

SessionComplete is the /resume session picker, backed by the shared tray engine in its stacked layout. It used to render itself through a bespoke renderSessionLine that duplicated the rail, the background fill and the truncation; that renderer is gone, and with it the panel's private selection fill. The selected record is now banded with styles.SelectedRow like every other tray, which is a deliberate and visible change.

It keeps the SessionItem slice alongside the tray because the tray's rows are DISPLAY strings only. Selected must hand back the record's ID for the caller to parse as a UUID, and an ID never appears on screen, so it cannot be recovered from a rendered row.

func NewSessionComplete

func NewSessionComplete(items []SessionItem) *SessionComplete

NewSessionComplete builds the picker, or returns nil when there is nothing to pick. Nil means "panel hidden" to the caller, so an empty tray must never be a non-nil object that renders to the empty string: the surface tests for nil, not for "".

func (*SessionComplete) Cursor

func (s *SessionComplete) Cursor() int

Cursor is the selected RECORD's index, not its row. A record spans two rows plus a spacer, so the two numbers diverge as soon as the cursor leaves the first record.

func (*SessionComplete) Down

func (s *SessionComplete) Down()

Down moves to the next record, wrapping to the first.

func (*SessionComplete) Filter added in v0.17.0

func (s *SessionComplete) Filter(query string)

Filter applies the inline search text. A blank query restores the unfiltered projection rather than asking Bubbles to filter on "", whose cursor mapping is unsuitable for payload selection (see trayList.ResetFilter).

func (*SessionComplete) Len added in v0.17.0

func (s *SessionComplete) Len() int

Len is the number of sessions that can currently be selected.

func (*SessionComplete) SelectWindowRow

func (s *SessionComplete) SelectWindowRow(row, maxRows int) bool

SelectWindowRow moves the cursor to the record occupying a clicked VISUAL row of the current maxRows window, reporting whether the selection changed.

Either of a record's two content rows selects it: the metadata row is part of the record the user pointed at rather than a target of its own, so clicking the date picks the session whose date it is. The spacer between records is inert, because it belongs to neither neighbour and picking one would move the cursor somewhere the user did not point.

func (*SessionComplete) Selected

func (s *SessionComplete) Selected() SessionItem

Selected resolves through the tray's original-item cursor so filtering may reorder or hide records without changing the opaque session ID that resume receives.

func (*SessionComplete) Up

func (s *SessionComplete) Up()

Up moves to the previous record, wrapping to the last.

func (*SessionComplete) ViewWindow added in v0.17.0

func (s *SessionComplete) ViewWindow(width, maxRows int) string

ViewWindow renders the picker into at most maxRows SCREEN rows, not maxRows records: two screen rows buy one record, and each further record costs three more, because only the rows BETWEEN records carry a spacer. A maxRows too small for one record's two content rows renders nothing rather than a title with its metadata cut off.

type SessionItem

type SessionItem struct {
	ID    string
	Title string
	// Current marks the session backing the active Agent. It remains independent from the
	// cursor after the user navigates to a different resume target.
	Current bool
	// Description is filter-only session context. It stays out of the compact two-row
	// picker so the visible row remains a quick scan of title, activity, date, and short ID.
	Description string
	State       string
	Activity    string
	LastUsed    string
	ShortID     string
}

SessionItem is the already-formatted, secret-free view data for one session record.

type SlashCmd

type SlashCmd struct {
	Name string // e.g. "/clear"
	Desc string // e.g. "clear the conversation"
}

SlashCmd is one slash command's display metadata. The action is dispatched by package tui keyed on Name; this widget only filters and displays.

type SlashComplete

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

SlashComplete is a filtered command list with a wrapping cursor.

The items, the cursor, the filter and the sliding window all live in the shared trayList engine, so this type is a translation layer: SlashCmd in, trayItem out, and back again.

func NewSlashComplete

func NewSlashComplete(prefix string) *SlashComplete

NewSlashComplete returns a fuzzy, case-insensitive completer for prefix over the canonical catalog. Returns nil when nothing matches (nil = panel hidden).

func NewSlashCompleteWithCommands

func NewSlashCompleteWithCommands(prefix string, commands []SlashCmd) *SlashComplete

NewSlashCompleteWithCommands builds a completer from an immutable caller-owned catalog. The commands are copied into the list engine, so a live tray cannot change underneath keyboard input.

Matching is the engine's fuzzy filter over command NAMES: the query's runes need only appear in order, so "sbx" finds /sandbox and "ear" still finds /clear. Descriptions are deliberately NOT searched -- see trayItem.FilterValue -- so a word that reads well in a description can no longer drag an unrelated command into the tray. Case is folded by the filter itself, so the query goes through as typed.

Returns nil when nothing matches, INCLUDING for an empty catalog: nil means "panel hidden", and a panel with no rows would be a tray that reserves height to draw nothing.

func (*SlashComplete) Cursor

func (s *SlashComplete) Cursor() int

Cursor returns the absolute selected index in the filtered list.

func (*SlashComplete) Down

func (s *SlashComplete) Down()

Down moves the cursor down, wrapping to the top.

func (*SlashComplete) SelectWindowRow

func (s *SlashComplete) SelectWindowRow(row, maxRows int) bool

SelectWindowRow moves the cursor to a row in the currently rendered maxRows window. It returns whether the selection changed; rows outside the visible window are ignored.

func (*SlashComplete) Selected

func (s *SlashComplete) Selected() SlashCmd

Selected returns the item under the cursor.

func (*SlashComplete) Up

func (s *SlashComplete) Up()

Up moves the cursor up, wrapping to the bottom.

func (*SlashComplete) View

func (s *SlashComplete) View() string

View renders the filtered list at its natural content width.

func (*SlashComplete) ViewWidth

func (s *SlashComplete) ViewWidth(width int) string

ViewWidth renders the filtered list as a tray whose rows are padded or clamped ANSI-safely to width display columns.

func (*SlashComplete) ViewWindow

func (s *SlashComplete) ViewWindow(width, maxRows int) string

ViewWindow renders a full-width tray capped to maxRows and keeps the selected command in the visible window. View and ViewWidth remain the unbounded variants.

type ValueComplete

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

ValueComplete is the runtime-choice tray -- in practice the model picker -- over the shared list engine.

items is EVERY choice in catalog order, not just the matching ones: the engine owns filtering and hands back the UNFILTERED index of the selection, so the payload lookup stays a direct index rather than a second, parallel slice that could drift out of step with the rows the engine is actually showing.

func NewModelComplete added in v0.17.0

func NewModelComplete(items []ValueItem) *ValueComplete

NewModelComplete builds the grouped model picker. Provider headings are rows in the same panel so they stay aligned with the selection, but the shared tray marks them inert: a cursor or pointer may only select a model payload.

func NewValueComplete

func NewValueComplete(items []ValueItem, query string) *ValueComplete

NewValueComplete builds the tray for items, narrowed to query. It returns nil when nothing matches: nil means "no panel at all", and the caller commits a notice rather than showing an empty tray that the arrow keys cannot move within.

func (*ValueComplete) Cursor

func (v *ValueComplete) Cursor() int

Cursor is the selected index among the MATCHING choices, not among all of them.

func (*ValueComplete) Down

func (v *ValueComplete) Down()

func (*ValueComplete) Filter added in v0.17.0

func (v *ValueComplete) Filter(query string)

Filter updates a live model search without recreating the picker. Plain runtime pickers use the same method when a caller wants it, while their existing constructor query remains valid.

func (*ValueComplete) Len

func (v *ValueComplete) Len() int

Len is how many choices matched, which is what the tray draws.

func (*ValueComplete) SelectWindowRow

func (v *ValueComplete) SelectWindowRow(row, maxRows int) bool

SelectWindowRow moves the cursor to a visual row of the rendered window and reports whether the selection changed.

func (*ValueComplete) Selected

func (v *ValueComplete) Selected() ValueItem

Selected is the choice under the cursor. It resolves through the engine's UNFILTERED index, so the opaque ID survives filtering however the matcher reordered the rows.

func (*ValueComplete) Up

func (v *ValueComplete) Up()

Up and Down move the cursor, wrapping at both ends.

func (*ValueComplete) ViewWindow

func (v *ValueComplete) ViewWindow(width, maxRows int) string

ViewWindow renders at most maxRows rows at width columns, keeping the selection on screen.

type ValueItem

type ValueItem struct {
	ID          string
	Provider    string
	Label       string
	Description string
	Aliases     []string
	Current     bool
}

ValueItem is one typed runtime choice. ID is the opaque payload returned on selection.

Jump to

Keyboard shortcuts

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