components

package
v0.17.5 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package components contains the bubbletea sub-views that compose the App.

Each file in this package exports one component as a simple struct with a View(...) method. The components are intentionally NOT tea.Model implementations: the App owns the state machine; components are pure presentation layers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ColorForSubagentType

func ColorForSubagentType(typeName string) color.Color

ColorForSubagentType returns a deterministic color derived from a subagent type name. Uses a curated palette of distinct ANSI-256 colors that are visible on both dark and light backgrounds.

func HighlightMentions

func HighlightMentions(s string, style lipgloss.Style) string

HighlightMentions applies style to @ mention tokens in already-rendered text.

func HighlightPastedInputMarkers

func HighlightPastedInputMarkers(s string, style lipgloss.Style) string

HighlightPastedInputMarkers applies style to collapsed multi-line paste markers.

func HighlightURL added in v0.12.1

func HighlightURL(s, hoveredURL string, style lipgloss.Style) string

HighlightURL styles the visible text for the given URL in s. It is intended for hover feedback after hit testing has identified the URL under the mouse.

func LinkifyURLs added in v0.12.1

func LinkifyURLs(s string) string

LinkifyURLs wraps every plain http(s):// URL found in s with an OSC 8 terminal hyperlink sequence so that supporting terminals render the URL as a clickable link while keeping the visible text unchanged.

The function operates on the raw string including any ANSI CSI styling already applied; it will not match URLs that appear inside an ANSI escape sequence because those sequences contain \x1b which cannot be part of a valid URL match.

func ModalContentWidth added in v0.11.0

func ModalContentWidth(containerWidth int) int

ModalContentWidth returns the inner content width for modal boxes, clamped to a readable range shared by modal components.

func RandomWorkingVerb

func RandomWorkingVerb() string

RandomWorkingVerb selects one busy footer label. Callers should store the returned value and rotate it deliberately so spinner ticks do not change the label every frame.

func SessionLabel

func SessionLabel(slug, firstMsgPreview, id string) string

SessionLabel returns the display label for a session, preferring slug over first-message preview over short id. Used by the App to build Breadcrumb segments.

func ThemeGlamourStyle added in v0.10.0

func ThemeGlamourStyle(t *styles.Styles) glamouransi.StyleConfig

ThemeGlamourStyle builds a glamour ansi.StyleConfig from the active Hygge theme. It starts from the standard dark config (deterministic, no OSC 11 query) and overrides only the key color fields that map cleanly to theme atoms:

  • Heading color ← AtomPrimary
  • H1 background ← AtomAccent
  • Link color ← AtomAccent
  • LinkText color ← AtomPrimary
  • Inline code fg ← AtomCodeFg
  • Inline code bg ← AtomCodeBg

When t is nil the unmodified DarkStyleConfig is returned.

Types

type APIKeyKey

type APIKeyKey struct {
	Name  string
	Runes []rune
}

APIKeyKey is the dialog-local key event shape used by tests and the UI app.

type APIKeyModal

type APIKeyModal struct {
	Width, Height int
	Theme         *styles.Styles
	Provider      string
	HasExisting   bool
	Value         string
}

APIKeyModal renders and updates the provider API-key dialog.

func (APIKeyModal) HandleKey

func (m APIKeyModal) HandleKey(k APIKeyKey) (APIKeyModal, APIKeyModalMsg)

HandleKey updates dialog state for one key and may emit an action message.

func (APIKeyModal) View

func (m APIKeyModal) View() string

View renders the dialog into a centered terminal string.

type APIKeyModalMsg

type APIKeyModalMsg interface {
	// contains filtered or unexported methods
}

APIKeyModalMsg is emitted when the dialog wants the App to perform an action.

type Breadcrumb struct {
	// Segments is the ordered list of navigation labels, root first.
	Segments []string

	// Width is the maximum column width of the rendered line.  0 means 80.
	Width int

	// Theme is the active theme; nil is accepted (plain style used).
	Theme *styles.Styles
}

Breadcrumb renders a navigation path of the form "root › child › grandchild".

It is shown above the message list whenever the foreground-stack depth is greater than 1 (i.e. the user has followed into a sub-session via Ctrl+G). When depth is 1 (root only), the breadcrumb is empty — View returns "".

Width is the maximum character width of the rendered line. If the natural rendering would exceed Width, middle segments are elided:

"root › … › 2 more › leaf"

Segments are user-visible labels for each stack entry:

  • The session's slug if non-empty.
  • Otherwise the first 24 characters of the first user message preview.
  • Otherwise "sess_" + the first 8 characters of the session id.
func (b Breadcrumb) View() string

View renders the breadcrumb, or "" when there is nothing to show. A single-segment stack (just the root) returns "". Downstream callers do NOT need to special-case the empty string — a zero-height string does not occupy layout space.

type CloseAPIKeyModal

type CloseAPIKeyModal struct{}

CloseAPIKeyModal requests closing the API-key dialog without saving.

type CloseMemoryModal added in v0.5.0

type CloseMemoryModal struct{}

CloseMemoryModal requests closing the memory dialog.

type CloseMessageActionModal added in v0.13.1

type CloseMessageActionModal struct{}

CloseMessageActionModal is emitted when the user dismisses the modal.

type CloseModelModal

type CloseModelModal struct{}

CloseModelModal requests closing the model dialog without changing model.

type CloseRememberScopeModal added in v0.5.0

type CloseRememberScopeModal struct{}

CloseRememberScopeModal requests closing the remember scope picker.

type CloseSessionsModal

type CloseSessionsModal struct{}

CloseSessionsModal asks the App to close the modal.

type CloseThemeModal

type CloseThemeModal struct{}

CloseThemeModal requests closing the theme dialog without changing theme.

type CommandPalette

type CommandPalette struct {
	// Width is the rendered width in cells (matches the input width).
	Width int

	// Theme is the active theme.  Nil falls back to default lipgloss
	// styles — the palette stays usable but loses muted/accent
	// distinction.
	Theme *styles.Styles

	// Matches is the prefix-filtered command list, sorted by Name.
	Matches []command.Command

	// Highlight is the index into Matches that is currently selected.
	// Clamped into [0, len(Matches)) at render time so the App does
	// not need to.  An out-of-range value (e.g. -1) renders as "no
	// row highlighted" — useful when the buffer has not yet picked a
	// row.
	Highlight int

	// QueryAfterSlash is the user's typed buffer minus the leading
	// slash.  Used only for the optional hint row at the bottom; the
	// actual filtering happens upstream.
	QueryAfterSlash string
}

CommandPalette is the inline autocomplete popover shown above the input whenever the user's buffer starts with `/`. It is a pure view-model: the App owns lookup state (matches, highlight index) and feeds it in; the palette has no event-handling logic of its own.

Filtering is done by the App via command.Registry.LookupPrefix so this component is also reusable for non-slash menus in the future.

Anchor: the App draws the palette as a floating layer above the editor. The palette draws its own rounded border so it visually floats above the input border.

func (CommandPalette) Empty

func (p CommandPalette) Empty() bool

Empty reports whether the palette has no matches to render. The App uses this to skip the popover entirely (no border, no blank padding) when the user has typed `/` plus characters that don't match anything.

func (CommandPalette) View

func (p CommandPalette) View() string

View renders the palette. Returns an empty string when there are no matches AND no query: this lets the App unconditionally concatenate the palette into the layout without worrying about reserving vertical space.

When there are no matches BUT the user has typed a query (e.g. `/foo`) we render a single "no commands match" row so the user has feedback rather than a silently disappearing popover.

type CompactionBanner

type CompactionBanner struct {
	Width   int
	Theme   *styles.Styles
	Visible bool
	Pct     float64 // context usage percentage (0–100)
}

CompactionBanner is the thin advisory banner shown above the input when context usage crosses the configured threshold. It is non-blocking: the user can dismiss it with Ctrl+X without triggering compaction.

Dismiss semantics (managed by the App, not here):

Ctrl+X          — dismiss for this crossing (hidden until re-crossing
                  after hysteresis or compaction).
CompactionCompleted event — auto-cleared by the App.

func (CompactionBanner) View

func (b CompactionBanner) View() string

View renders the banner as a single line, or "" when not visible.

type CompactionModal

type CompactionModal struct {
	Width  int
	Height int
	Theme  *styles.Styles
	Toast  string // optional transient line (e.g. warning text)

	// SessionID is the foreground session being compacted.
	SessionID string

	// MessageCount is the number of messages since the last compaction marker.
	// When < 4 the modal disables the [y] key and shows a "nothing to compact"
	// notice.
	MessageCount int

	// ContextPct is the current context-window usage as a percentage (0–100).
	ContextPct float64

	// ContextWindow is the model's maximum context size in tokens.  Shown in
	// the modal body.
	ContextWindow int64
}

CompactionModal renders the confirmation dialog shown when the user runs /compact. It displays the message count, context usage, and a brief explanation before asking the user to confirm or cancel.

Keybinds (handled by the App, not here):

y / Y  — confirm compaction
n / N  — cancel
esc    — cancel

func (CompactionModal) NothingToCompact

func (m CompactionModal) NothingToCompact() bool

NothingToCompact reports whether there are fewer than 4 messages since the last marker. When true the [y] key is disabled.

func (CompactionModal) View

func (m CompactionModal) View() string

View renders the modal centred in a Width×Height box.

type CopyMessageAction added in v0.13.1

type CopyMessageAction struct {
	Text string // raw message text to copy
}

CopyMessageAction is emitted when the user selects "Copy message".

type DeleteSessionAction

type DeleteSessionAction struct{ ID string }

DeleteSessionAction asks the App to soft-delete a session.

type DiffView

type DiffView struct {
	Raw      string
	Width    int
	Theme    *styles.Styles
	MaxLines int
}

DiffView renders unified-diff-like text with line-level add/delete styling.

func (DiffView) IsTruncated added in v0.6.0

func (d DiffView) IsTruncated() bool

IsTruncated reports whether the diff exceeds its configured preview line limit. For wide views (side-by-side), pair-preservation may extend the rendered range to the end of the diff, in which case truncation is false even if the raw line count exceeds MaxLines.

func (DiffView) View

func (d DiffView) View() string

View returns the styled diff text, collapsed when MaxLines is exceeded.

type Footer struct {
	Width          int
	Theme          *styles.Styles
	Styles         *styles.Styles
	AgentType      string
	ModelName      string
	Provider       string
	ReasoningLevel string
	// ModeIndicator is the pre-rendered mode selector string (e.g. "smart · rush · deep")
	// with the active mode highlighted. Empty when only one mode exists.
	ModeIndicator string
	// Busy shows a spinner indicator on the left side of the footer.
	Busy bool
	// SpinnerView is the pre-rendered spinner frame (e.g. "⣾").
	SpinnerView string
	// WorkingVerb is the busy label selected by the owner. It should be stable
	// between periodic rotations rather than changing on every spinner frame.
	WorkingVerb string
}

Footer renders the bottom-of-screen identity line.

Layout (segments separated by ` · `):

{AgentType Capitalized} · {ModelName} · {Provider Capitalized} · {ReasoningLevel}

func (Footer) View

func (f Footer) View() string

View renders the footer.

type ForgetMemoryAction added in v0.5.0

type ForgetMemoryAction struct {
	Scope session.MemoryScope
	ID    string
}

ForgetMemoryAction requests deleting a memory by scope and id.

type ForkMessageAction added in v0.13.1

type ForkMessageAction struct {
	SessionID string // session to fork from
	MessageID string // message ID to fork at
}

ForkMessageAction is emitted when the user selects "Fork from here".

type ForkSessionAction

type ForkSessionAction struct {
	ID        string
	MessageID string
}

ForkSessionAction asks the App to fork a session. MessageID == "" means fork at the latest user message.

type Input

type Input struct {
	Textarea         textarea.Model
	Styles           *styles.Styles
	PasteMarkerStyle lipgloss.Style
	BorderColor      color.Color
	VerticalPadding  int
	Focused          bool
	// contains filtered or unexported fields
}

Input wraps a bubbles textarea with dynamic height, custom prompts, and theme-aware styling.

Keybind contract:

  • Enter submits (handled by the App, not the textarea).
  • Shift+Enter and Alt+Enter insert a newline.
  • Ctrl+C, Ctrl+L handled by the App.

func NewInput

func NewInput(t *styles.Styles) *Input

NewInput builds a configured textarea with dynamic height and custom prompts.

func (*Input) HeightChanged

func (i *Input) HeightChanged() bool

HeightChanged reports whether the textarea height changed since the last check. Call this after Update to know if layout needs recalculation.

func (*Input) Reset

func (i *Input) Reset()

Reset clears the input.

func (*Input) SetBusy

func (i *Input) SetBusy(busy bool, suffix string)

SetBusy switches the placeholder based on agent state.

func (*Input) SetStyles

func (i *Input) SetStyles(s *styles.Styles)

SetStyles applies the theme style system.

func (*Input) SetWidth

func (i *Input) SetWidth(w int)

SetWidth resizes the underlying textarea, accounting for border and padding.

func (*Input) Value

func (i *Input) Value() string

Value returns the current input text.

func (*Input) View

func (i *Input) View() string

View renders the input area with a themed border.

type MemoryKey added in v0.5.0

type MemoryKey struct {
	Name  string
	Runes []rune
}

MemoryKey is the dialog-local key event shape used by tests and the UI app.

type MemoryModal added in v0.5.0

type MemoryModal struct {
	Width, Height int
	Theme         *styles.Styles
	Memories      []*session.Memory
	Query         string
	Cursor        int
	ForgetOnly    bool
}

MemoryModal renders active memories grouped by scope.

func (MemoryModal) Filtered added in v0.5.0

func (m MemoryModal) Filtered() []*session.Memory

Filtered returns active memories after applying the current search query.

func (MemoryModal) HandleKey added in v0.5.0

func (m MemoryModal) HandleKey(k MemoryKey) (MemoryModal, MemoryModalMsg)

HandleKey updates dialog state for one key and may emit an action message.

func (MemoryModal) View added in v0.5.0

func (m MemoryModal) View() string

View renders the dialog into a centered terminal string.

type MemoryModalMsg added in v0.5.0

type MemoryModalMsg interface {
	// contains filtered or unexported methods
}

MemoryModalMsg is emitted when the memory dialog wants the App to act.

type MentionItem

type MentionItem struct {
	Kind        string
	Label       string
	Description string
}

MentionItem is one selectable @ mention candidate.

type MentionPalette

type MentionPalette struct {
	Width     int
	Theme     *styles.Styles
	Matches   []MentionItem
	Highlight int
	Query     string
}

MentionPalette is the inline autocomplete popover shown above the input while the user is typing an @ mention.

func (MentionPalette) View

func (p MentionPalette) View() string

View renders the mention autocomplete popover.

type MessageActionKey added in v0.13.1

type MessageActionKey struct {
	Name  string
	Runes []rune
}

MessageActionKey is a key event routed to MessageActionModal.HandleKey.

type MessageActionModal added in v0.13.1

type MessageActionModal struct {
	Width       int
	Height      int
	Theme       *styles.Styles
	SessionID   string // current foreground session id
	MessageID   string // message id clicked
	MessageText string // raw text of the clicked message
	Cursor      int    // selected row (0=copy, 1=fork)
}

MessageActionModal is a lightweight two-action modal shown when the user clicks on a user message bubble. It offers copy and fork actions.

Following the components convention the modal is a pure value type: HandleKey returns an updated copy plus an optional action message. The App owns the mutable state.

func (MessageActionModal) HandleKey added in v0.13.1

HandleKey processes a key press and returns the updated modal plus an optional action. Returns nil msg when no action was triggered.

func (MessageActionModal) View added in v0.13.1

func (m MessageActionModal) View() string

View renders the modal centered in Width×Height.

type MessageActionModalMsg added in v0.13.1

type MessageActionModalMsg interface {
	// contains filtered or unexported methods
}

MessageActionModalMsg is the sealed interface for messages emitted by MessageActionModal.HandleKey.

type MessageList

type MessageList struct {
	Width         int
	CollapseLines int // 0 → 8 (tool result collapse threshold)
	Theme         *styles.Styles
	Styles        *styles.Styles
	Messages      []UIMessage
	Subagents     map[string]*SubagentState
	// AnimFor, when non-nil, maps SubSessionID to the running Anim for
	// that sub-agent.  Passed through to SubagentBlock so the running
	// state can display the animated spinner.
	AnimFor map[string]*anim.Anim
	// Now is the wall-clock to use for elapsed-time math inside
	// nested SubagentBlocks.  Zero means time.Now (production
	// path); tests override it for deterministic output.
	Now time.Time

	// HoverSubagentID is the subagent currently under the mouse cursor.
	// When set, that subagent's bubble renders with highlight styling.
	HoverSubagentID string

	// HoverURL is the URL currently under the mouse cursor. When set, matching
	// visible URL text in user/assistant bubbles renders with hover styling.
	HoverURL string
	// HoverUserMsgID is the user message currently under the mouse cursor.
	// When set, that user bubble renders with clickable hover styling.
	HoverUserMsgID string

	// ExpandedTools is the set of ToolUseIDs whose output is fully expanded
	// (not truncated). Nil means all tools are collapsed.
	ExpandedTools map[string]bool

	// ExpandedThinking is the set of message indices whose thinking block is
	// fully expanded (not truncated). Nil means all thinking is collapsed.
	ExpandedThinking map[int]bool

	// MessageIndexOffset is added to rendered message indices before looking up
	// ExpandedThinking. It keeps expansion state stable when scrollback is capped
	// and a synthetic notice is prepended to the rendered slice.
	MessageIndexOffset int

	// Compact enables compact layout mode: tighter message spacing, no separate
	// assistant header row with model metadata (mode name goes inside the bubble),
	// tool output hidden until explicitly expanded, subagent blocks two lines.
	Compact bool
	// contains filtered or unexported fields
}

MessageList renders the conversation history.

Width is the terminal width; the gutter (`▌user`, etc.) is prepended to the first line of each message. Tool result blocks are collapsed to the first CollapseLines lines, with a hint when the rest is hidden.

Subagents, when populated, is a map from sub-session id to the rendering state of an in-flight or completed sub-agent. Messages whose SubagentID is a key in this map get a nested SubagentBlock rendered under them.

func (MessageList) View

func (m MessageList) View() string

View renders all messages joined with a blank line between them. The pre-pass groups consecutive compact RoleTool entries into a single tool-calls bubble. Bash, edit, and write tools render as standalone tool blocks so expandable output and large file diffs have their own hit zone.

func (MessageList) ViewWithHitZones

ViewWithHitZones renders all messages and returns both the rendered content and the line ranges of clickable subagent bubbles.

type MessageRole

type MessageRole string

MessageRole is the participant role for a rendered message.

const (
	RoleUser      MessageRole = "user"
	RoleAssistant MessageRole = "assistant"
	RoleTool      MessageRole = "tool"
	RoleSystem    MessageRole = "system"
	// RoleMarker renders a prominent banner-style section break produced
	// by a compaction event.  It shows the summary and tokens-saved count.
	RoleMarker MessageRole = "marker"
)

Recognised roles for rendering purposes. Mirrors session.Role but kept separate so the components package does not import session.

type ModelKey

type ModelKey struct {
	Name  string
	Runes []rune
}

ModelKey is the dialog-local key event shape used by tests and the UI app.

type ModelModal

type ModelModal struct {
	Width, Height int
	Theme         *styles.Styles
	Current       string
	Query         string
	Cursor        int
	Models        []ModelOption
	// Favorites is the ordered list of "provider/model" refs the user has
	// starred.  Loaded from global state when the modal opens; toggled via
	// ctrl+f.  Favorites are shown first under a "Favorites" heading.
	Favorites []string
}

ModelModal renders and updates the model-selection dialog.

func (ModelModal) Filtered

func (m ModelModal) Filtered() []ModelOption

Filtered returns the model list after applying the current search query. Favorite models appear first (sorted within their group), followed by the remaining models sorted by provider then model id.

func (ModelModal) HandleKey

func (m ModelModal) HandleKey(k ModelKey) (ModelModal, ModelModalMsg)

HandleKey updates dialog state for one key and may emit an action message.

func (ModelModal) View

func (m ModelModal) View() string

View renders the dialog into a centered terminal string.

type ModelModalMsg

type ModelModalMsg interface {
	// contains filtered or unexported methods
}

ModelModalMsg is emitted when the dialog wants the App to perform an action.

type ModelOption

type ModelOption struct {
	Provider string
	Entry    catalog.Entry
}

ModelOption is one selectable catalog model in the model picker.

func ConfiguredModelOption added in v0.6.0

func ConfiguredModelOption(provider, model string) ModelOption

ConfiguredModelOption builds a selectable entry for a configured model that is missing from the catalog snapshot.

type NewSessionAction

type NewSessionAction struct{}

NewSessionAction asks the App to start a fresh session. Emitted when the user presses 'n' in the empty-list picker.

type OnboardingClose added in v0.7.0

type OnboardingClose struct{}

OnboardingClose is emitted when the user presses Esc on the welcome step.

type OnboardingGeneratePrompt added in v0.7.0

type OnboardingGeneratePrompt struct {
	ProviderName string
	ModelName    string
	APIKey       string
	Idea         string
	ForSubagent  bool
}

OnboardingGeneratePrompt asks the App to call GeneratePrompt asynchronously (provider/model are ready in wizard state).

type OnboardingGeneratedPromptReady added in v0.7.0

type OnboardingGeneratedPromptReady struct {
	Prompt      string
	Err         error
	ForSubagent bool
}

OnboardingGeneratedPromptReady is sent back to the wizard by the App after generation completes. Err is non-nil on failure.

type OnboardingKey added in v0.7.0

type OnboardingKey struct {
	Name  string
	Runes []rune
}

OnboardingKey is the wizard-local key event.

type OnboardingMsg added in v0.7.0

type OnboardingMsg interface {
	// contains filtered or unexported methods
}

OnboardingMsg is emitted when the wizard needs the App to act.

type OnboardingSaveResult added in v0.7.0

type OnboardingSaveResult struct {
	ProviderName   string
	ProviderAPIKey string
	Mode           config.ModeConfig
	Subagents      []OnboardingSubagentDraft
}

OnboardingSaveResult asks the App to persist the final wizard output.

type OnboardingSaved added in v0.7.0

type OnboardingSaved struct{ Err error }

OnboardingSaved is sent back to the wizard when the App has finished persisting the result (Err non-nil on failure).

type OnboardingStep added in v0.7.0

type OnboardingStep int

OnboardingStep enumerates the wizard steps.

const (
	OnboardStepWelcome OnboardingStep = iota
	OnboardStepAPIKey
	OnboardStepProviderMore
	OnboardStepPickModel
	OnboardStepModeName
	OnboardStepModeIdea
	OnboardStepPromptReview
	OnboardStepSubagentOffer
	OnboardStepSubagentName
	OnboardStepSubagentIdea
	OnboardStepSubagentPromptReview
	OnboardStepDone
)

Wizard step constants.

type OnboardingSubagentDraft added in v0.7.0

type OnboardingSubagentDraft struct {
	Name   string
	Idea   string
	Prompt string
}

OnboardingSubagentDraft holds wizard state for a single subagent being built.

type OnboardingWizard added in v0.7.0

type OnboardingWizard struct {
	Width, Height int
	Theme         *styles.Styles
	Providers     []string // known provider names

	Step OnboardingStep

	// step 0/1: provider + API key
	ProviderCursor      int
	ProviderName        string
	APIKey              string
	ProviderKeys        map[string]string
	ConfiguredProviders map[string]bool

	// step 2: model pick
	Models       []string // filled after provider is confirmed
	ModelCursor  int
	ModelQuery   string
	ModelName    string
	ModelNameRaw string // typed entry

	// step 3: mode name
	ModeName string

	// step 4: mode behavior idea
	ModeIdea string

	// step 5: generated prompt for mode
	ModePrompt    string
	PromptLoading bool
	PromptLoadErr string
	PromptEditing bool
	PromptEditBuf string

	// subagent wizard
	SubagentDrafts  []OnboardingSubagentDraft
	CurrentSubagent OnboardingSubagentDraft
	SubagentLoading bool
	SubagentLoadErr string
	SubagentEditing bool
	SubagentEditBuf string

	// saving tracks whether the final save is in progress
	Saving    bool
	SaveError string
	// contains filtered or unexported fields
}

OnboardingWizard is the onboarding wizard component. It is a pure state machine: HandleKey advances state and emits messages; View renders the current step.

func (OnboardingWizard) ApplyGeneratedPrompt added in v0.7.0

ApplyGeneratedPrompt feeds a completed prompt-generation result back.

func (OnboardingWizard) HandleKey added in v0.7.0

HandleKey advances wizard state, returns updated wizard and optional message.

func (OnboardingWizard) View added in v0.7.0

func (w OnboardingWizard) View() string

View renders the wizard overlay.

type PermissionModal

type PermissionModal struct {
	Width   int
	Height  int
	Theme   *styles.Styles
	Request PermissionRequest
}

PermissionModal renders the centered modal that gates tool execution.

func (PermissionModal) View

func (m PermissionModal) View() string

View renders the modal centered in a Width×Height box. Caller is responsible for not calling View when no request is active.

type PermissionRequest

type PermissionRequest struct {
	RequestID string
	ToolName  string
	Category  string
	Target    string
	Why       string // optional rationale
}

PermissionRequest is the data the modal needs to render. Mirrors bus.PermissionAsked so components does not import bus.

type QuestionModal added in v0.4.0

type QuestionModal struct {
	Width         int
	Height        int
	Theme         *styles.Styles
	Request       QuestionRequest
	SelectedIndex int
}

QuestionModal renders a centered multiple-choice prompt for model questions.

func (QuestionModal) View added in v0.4.0

func (m QuestionModal) View() string

View renders the modal centered in a Width×Height box.

type QuestionOption added in v0.4.0

type QuestionOption struct {
	ID    string
	Label string
}

QuestionOption is one selectable answer in a question modal.

type QuestionRequest added in v0.4.0

type QuestionRequest struct {
	RequestID string
	ToolName  string
	Question  string
	Options   []QuestionOption
}

QuestionRequest is the data the modal needs to render. Mirrors bus.QuestionAsked so components does not import bus.

type RememberScopeAction added in v0.5.0

type RememberScopeAction struct {
	Scope   session.MemoryScope
	Content string
}

RememberScopeAction requests saving the draft content at a chosen scope.

type RememberScopeKey added in v0.5.0

type RememberScopeKey struct {
	Name string
}

RememberScopeKey is the dialog-local key event shape used by tests and the UI app.

type RememberScopeModal added in v0.5.0

type RememberScopeModal struct {
	Width, Height int
	Theme         *styles.Styles
	Content       string
	Cursor        int
}

RememberScopeModal lets the user choose where a no-scope /remember should save.

func (RememberScopeModal) HandleKey added in v0.5.0

HandleKey updates dialog state for one key and may emit an action message.

func (RememberScopeModal) View added in v0.5.0

func (m RememberScopeModal) View() string

View renders the dialog into a centered terminal string.

type RememberScopeModalMsg added in v0.5.0

type RememberScopeModalMsg interface {
	// contains filtered or unexported methods
}

RememberScopeModalMsg is emitted when the scope picker wants the App to act.

type RenameSessionAction

type RenameSessionAction struct {
	ID   string
	Slug string
}

RenameSessionAction asks the App to rename a session.

type SaveAPIKeyAction

type SaveAPIKeyAction struct{ Provider, APIKey string }

SaveAPIKeyAction requests saving APIKey for Provider.

type SelectModelAction

type SelectModelAction struct{ Provider, Model string }

SelectModelAction requests switching to Provider/Model for the current session.

type SelectThemeAction

type SelectThemeAction struct{ Name string }

SelectThemeAction requests switching to Name for the current session.

type SessionsKey

type SessionsKey struct {
	Name  string
	Runes []rune
}

SessionsKey is the subset of keys the modal handles.

type SessionsModal

type SessionsModal struct {
	// Sessions is the full unfiltered session list (newest first).
	// The modal renders only the rows that survive the filter.
	Sessions []*session.Session

	// ForegroundID is the currently active session's id.  That row is
	// highlighted differently.
	ForegroundID string

	// Cursor is the currently highlighted row index into the filtered list.
	Cursor int

	// FilterValue is the active substring filter.
	FilterValue string

	// FilterFocused is true when keyboard input goes to the filter field.
	FilterFocused bool

	// ShowSubagents controls whether subagent rows are visible.
	ShowSubagents bool

	// ShowDeleted controls whether soft-deleted rows are visible.
	ShowDeleted bool

	// RenameMode is true when the inline rename field is open.
	RenameMode bool

	// RenameValue is the current value in the rename input.
	RenameValue string

	// ConfirmDelete is true when the delete-confirmation prompt is open.
	ConfirmDelete bool

	// ShowHelp toggles the inline keybind cheatsheet.
	ShowHelp bool

	// Toast is an ephemeral single-line message (error / info).
	Toast string

	// Width is the available terminal width.
	Width int

	// Height is the available terminal height.
	Height int

	// Theme is the active theme.
	Theme *styles.Styles

	// Now is the wall-clock used for "N ago" labels.
	Now time.Time

	// AllowNew, when true, shows a "No sessions yet. [n] new session [esc] cancel"
	// affordance when the filtered list is empty.  Used when the picker is
	// opened on start (resume_default="ask", or `hygge resume` in an empty project).
	AllowNew bool
}

SessionsModal is the bubbletea-style component for the session management overlay. It is a pure-view struct: the App owns the state (sessions list, cursor, filter) and calls Update then View on each tick.

The modal supports keyboard navigation, substring filtering, and the following actions: switch, rename, fork at latest, delete.

All user-input / action messages emitted by the modal are returned as tea.Msg values; the App applies the side effects.

func (SessionsModal) FilteredCount

func (m SessionsModal) FilteredCount() int

FilteredCount returns the number of sessions that would survive the current filter/visibility settings. Used by the App to clamp the cursor after a delete.

func (SessionsModal) HandleKey

HandleKey processes one key press in the modal. Returns (newState, emittedMsg). emittedMsg is nil when no action was triggered.

func (SessionsModal) HumanAgo

func (m SessionsModal) HumanAgo(t time.Time, now time.Time) string

HumanAgo renders the elapsed time since t as a compact human string. Exposed as a method for testability.

func (SessionsModal) View

func (m SessionsModal) View() string

View renders the modal centered in Width×Height.

type SessionsModalMsg

type SessionsModalMsg interface {
	// contains filtered or unexported methods
}

SessionsModalMsg is the tagged union of messages the modal emits.

type Sidebar struct {
	// Width is the total column width including the left border.
	Width int
	// Height is the total height of the sidebar column.
	Height int

	// SessionTitle is the display title for the current session.
	// Empty means no active session — the section is omitted entirely.
	SessionTitle string

	// Usage and context data.
	UsedTokens         int64
	MaxTokens          int64
	PctUsed            float64
	CostUSD            float64
	BilledInputTokens  int64 // cumulative input+cache tokens billed
	BilledOutputTokens int64 // cumulative output tokens billed

	// MCPs is the list of configured MCP server statuses.
	MCPs []SidebarMCPStatus

	// Todos is the agent's lightweight todo list for the current session.
	// Nil or empty renders "—" (the fallback stub).
	Todos []SidebarTodo

	// ProjectPath is the tilde-collapsed project directory path.
	ProjectPath string
	// GitBranch is the current git branch (may be empty).
	GitBranch string
	// AppName is the application name, e.g. "Hygge".
	AppName string
	// Version is the application version string, e.g. "v0.1.0-dev".
	Version string

	// Theme is the active theme. Nil is accepted (plain styles used).
	Theme  *styles.Styles
	Styles *styles.Styles
	// NerdFonts controls whether to use the nerd-font git-branch glyph.
	NerdFonts bool
}

Sidebar renders the fixed-width right-side panel containing session context, MCPs, todos, and footer identity.

Layout (top to bottom):

Session title (1–2 lines, bold)

Context  (section header)
  {usedTok} tokens
  {pctUsed}% used
  ${costDollars}

MCPs  (section header)
  ● server-a · N tools
  ○ server-b

Todos  (section header)
  ✓ completed item
  → in-progress item
  ○ pending item

(flex space)

~/path…:branch
● Hygge v0.1.0-dev

The left edge carries a single │ border in the sidebar border color. Inner padding: 1 cell on each side so content doesn't touch the divider.

func (Sidebar) View

func (s Sidebar) View() string

View renders the sidebar column.

type SidebarMCPStatus

type SidebarMCPStatus struct {
	Name      string
	Ready     bool
	Error     string
	ToolCount int
}

SidebarMCPStatus is the UI-side representation of one MCP server's runtime status. Populated at the wiring layer (runTUI) from the CLI's MCPServerStatus type so the sidebar has no import dependency on cmd/.

type SidebarTodo

type SidebarTodo struct {
	// Title is the human-readable todo text.
	Title string
	// Status drives the leading glyph and color.
	Status SidebarTodoStatus
}

SidebarTodo is one row in the sidebar Todos section.

type SidebarTodoStatus

type SidebarTodoStatus string

SidebarTodoStatus is the rendering status for a single sidebar todo row. Mirrors session.TodoStatus values; defined here so the components package has no import dependency on internal/session.

const (
	// SidebarTodoPending is a queued, not-yet-started item.
	SidebarTodoPending SidebarTodoStatus = "pending"
	// SidebarTodoInProgress is the currently-active item.
	SidebarTodoInProgress SidebarTodoStatus = "in_progress"
	// SidebarTodoCompleted is a finished item.
	SidebarTodoCompleted SidebarTodoStatus = "completed"
	// SidebarTodoCancelled is an abandoned item.
	SidebarTodoCancelled SidebarTodoStatus = "cancelled"
)

Sidebar todo status constants.

type StatusPills

type StatusPills struct {
	Width          int
	Theme          *styles.Styles
	QueueCount     int
	QueuedPrompts  []string
	QueuedEditable bool
}

StatusPills renders compact input-adjacent status chips.

func (StatusPills) View

func (p StatusPills) View() string

View renders a single row of pills. Empty state renders nothing so the input keeps its current layout when no status exists.

type SubagentBlock

type SubagentBlock struct {
	State   *SubagentState
	Width   int
	Theme   *styles.Styles
	Now     time.Time
	Anim    *anim.Anim
	Hovered bool
	// Compact, when true, renders the block as only two lines (heading +
	// subtitle) without the blank spacer line or ctrl+g hint.
	Compact bool
}

SubagentBlock renders a single nested sub-agent state in the compact heading + subtitle + hint layout.

Layout (rendered inside a distinct bubble by wrapSubagentBubble):

{Type} Subagent — {Description}
{subtitle}

ctrl+g  view subagent

Width is the available column count for the parent message list; Theme is the active theme; Now is the wall-clock used for elapsed-time math while the state is still running. Anim is the optional animation component for the running state (nil renders a static placeholder).

func (SubagentBlock) View

func (b SubagentBlock) View() string

View renders the compact block. Returns the empty string when State is nil. The output has no leading │ gutter — the surrounding bubble border provides the visual containment.

type SubagentHitZone

type SubagentHitZone struct {
	StartLine    int // inclusive, relative to message list content
	EndLine      int // exclusive
	SubSessionID string
	// contains filtered or unexported fields
}

SubagentHitZone maps a range of content lines to a subagent session ID.

type SubagentState

type SubagentState struct {
	// SubSessionID is the sub-session's id; the map key in App.
	SubSessionID string

	// ParentSessionID is the dispatching session.  Used to filter
	// events when the foreground session changes (a sub-agent of
	// session A should not render in session B's view).
	ParentSessionID string

	// ParentMessageID is the parent's task tool_use_id.  The
	// message-list uses this to find the UIMessage to anchor the
	// nested block under.  Empty when the dispatcher did not
	// supply one.
	ParentMessageID string

	// Type is the sub-agent type name (e.g. "general").
	Type string

	// Description is the short mission label shown in the heading.
	Description string

	// Model is the resolved provider/model string shown in the compact block
	// and detail view accessed via Ctrl+G.
	Model string

	// StartedAt and EndedAt bound the wall-clock elapsed time.
	// EndedAt is the zero value while the sub-agent is still running.
	StartedAt time.Time
	EndedAt   time.Time

	// Cost / InputTokens / OutputTokens are running totals tagged
	// to the sub-session.  Stage C derives these from
	// bus.CostUpdated events that arrive with the sub-session id;
	// the Completed event's totals override them at the end.
	Cost         float64
	InputTokens  int64
	OutputTokens int64

	// Messages is the streaming buffer of nested sub-messages,
	// in chronological order.  Used to derive the tool-count
	// subtitle and the latest-tool hint in the running state.
	Messages []UIMessage

	// Expanded is retained for Ctrl+T toggle compatibility.
	// In the compact layout it controls whether the transcript view
	// is shown when the user follows into the subagent via Ctrl+G.
	Expanded bool
}

SubagentState is the rendering view of one in-flight or completed sub-agent invocation. The App owns the source of truth; this struct is a snapshot the message-list renders.

Lifecycle:

  • Created when bus.SubagentStarted arrives. StartedAt set, EndedAt zero, Messages empty.
  • Updated as the sub-session's events flow through (text deltas, tool calls, cost updates). Caller appends to Messages and overwrites Cost / InputTokens / OutputTokens.
  • Finalised when bus.SubagentCompleted arrives. EndedAt is set.

func (*SubagentState) IsRunning

func (s *SubagentState) IsRunning() bool

IsRunning is true while no Completed event has arrived yet. Used by the App to drive the elapsed-time tick.

type SwitchSessionAction

type SwitchSessionAction struct{ ID string }

SwitchSessionAction asks the App to switch the foreground session.

type ThemeKey

type ThemeKey struct {
	Name  string
	Runes []rune
}

ThemeKey is the dialog-local key event shape used by tests and the UI app.

type ThemeModal

type ThemeModal struct {
	Width, Height int
	Theme         *styles.Styles
	Current       string
	Query         string
	Cursor        int
	Themes        []string
	PreviewTheme  func(string) *styles.Styles
}

ThemeModal renders and updates the theme-selection dialog.

func (ThemeModal) Filtered

func (m ThemeModal) Filtered() []string

Filtered returns the theme list after applying the current search query.

func (ThemeModal) HandleKey

func (m ThemeModal) HandleKey(k ThemeKey) (ThemeModal, ThemeModalMsg)

HandleKey updates dialog state for one key and may emit an action message.

func (ThemeModal) View

func (m ThemeModal) View() string

View renders the dialog into a centered terminal string.

type ThemeModalMsg

type ThemeModalMsg interface {
	// contains filtered or unexported methods
}

ThemeModalMsg is emitted when the dialog wants the App to perform an action.

type ThinkingHitZone added in v0.11.0

type ThinkingHitZone struct {
	StartLine int
	EndLine   int
	MsgIndex  int
	// contains filtered or unexported fields
}

ThinkingHitZone maps a range of content lines to a message index for click-to-expand thinking blocks. MsgIndex is the index of the UIMessage in the slice that was passed to ViewWithHitZones; it is used as a stable key into App.expandedThinking.

type ToggleFavoriteModelAction added in v0.15.0

type ToggleFavoriteModelAction struct{ Provider, Model string }

ToggleFavoriteModelAction requests adding or removing the given model from the global favorites list.

type ToolHitZone

type ToolHitZone struct {
	StartLine int
	EndLine   int
	ToolUseID string
	// contains filtered or unexported fields
}

ToolHitZone maps a range of content lines to a tool use ID for click-to-expand.

type ToolStatus

type ToolStatus int

ToolStatus is the execution lifecycle state of a single tool call. Only meaningful on UIMessage entries where Role == RoleTool.

const (
	// ToolStatusUnknown is the zero value; no status text is rendered.
	// Used for hydrated orphan tool-use entries (tool_use with no matching
	// result — interrupted run). Should not occur in well-formed sessions.
	ToolStatusUnknown ToolStatus = iota
	// ToolStatusPending means the agent requested the tool call; no permission
	// decision has been asked yet. Rarely visible — transitions quickly.
	ToolStatusPending
	// ToolStatusAwaitingPermission means the permission engine published a
	// PermissionAsked event; the user has not yet responded. The modal is
	// visible; the inline row shows "Requesting permission…".
	ToolStatusAwaitingPermission
	// ToolStatusRunning means permission was granted (or not required); the tool
	// is executing. The inline row shows "Waiting for tool response…".
	ToolStatusRunning
	// ToolStatusCompleted means the tool finished without error. No status text.
	ToolStatusCompleted
	// ToolStatusError means the tool finished with an error. Inline row shows "error".
	ToolStatusError
	// ToolStatusCancelled means permission was denied or the user cancelled.
	// Inline row shows "cancelled".
	ToolStatusCancelled
)

type UIMessage

type UIMessage struct {
	Role      MessageRole
	ToolName  string // populated for RoleTool
	ToolUseID string // optional provider-assigned tool_use_id; lets the
	// view correlate this message with a SubagentState
	Target        string          // optional tool target hint (path/cmd)
	ToolArgs      json.RawMessage // raw tool arguments for rich rendering
	Raw           string          // raw text (streaming buffer or plain content)
	FinalMarkdown string          // cached glamour output once streaming completes
	IsStreaming   bool
	IsError       bool // tool result error flag
	// Status is the execution lifecycle state for RoleTool messages.
	// Set by handleBusEvent transitions; hydrated from persisted state.
	Status ToolStatus
	// SubagentID is the SubSessionID of a sub-agent dispatched by this
	// message.  When non-empty and the matching SubagentState is in
	// MessageList.Subagents, the view renders a nested block under this
	// message.  Set on the parent `task` tool UIMessage when
	// bus.SubagentStarted arrives.
	SubagentID string

	// MarkerSummary is the post-compaction context summary, populated on
	// RoleMarker messages.
	MarkerSummary string
	// MarkerTokensSaved is the number of input tokens saved by the
	// compaction, populated on RoleMarker messages.
	MarkerTokensSaved int64

	// Timestamp is the wall-clock time the message was created.
	// Populated for RoleUser and RoleAssistant messages.
	Timestamp time.Time

	// Thinking holds the assistant's reasoning content (inline thinking).
	// Populated for RoleAssistant messages that carry thinking blocks.
	// Rendered in muted italic style at the top of the assistant bubble.
	Thinking string

	// OutputTokens is the number of output tokens for an assistant message.
	// Zero while streaming or when the provider did not report usage.
	OutputTokens int64

	// CostUSD is the per-message cost in USD for an assistant message.
	// Zero while streaming or when cost data is unavailable.
	CostUSD float64

	// DurationMs is the wall-clock elapsed milliseconds for an assistant message.
	// Zero while streaming.
	DurationMs int64

	// AgentType is the agent identity label for the assistant bubble header-left.
	// Defaults to "General" when empty.
	AgentType string

	// ModelName is the model name for the assistant bubble header-right metadata.
	ModelName string

	// ModeColor is the per-mode accent color for the bubble border/header.
	// When non-nil, overrides the theme's default agent border color.
	ModeColor color.Color

	// SubagentColor is a deterministic accent color for subagent bubbles.
	// Derived from the subagent type name. When non-nil, used for both
	// the sidebar bar and header text.
	SubagentColor color.Color

	// VisibleRaw is the streaming assistant text that has been revealed by the
	// typing animation. Raw keeps the full accumulated provider text; VisibleRaw
	// lags behind it while IsStreaming is true so new text can animate in.
	VisibleRaw string

	// IsPlaceholder marks an assistant bubble as a transient "waiting for the
	// next response" indicator. Used after a subagent completes so the user
	// sees feedback near the chat content while the parent's next LLM call is
	// still pending its first token. The first real assistant delta clears
	// the placeholder content before appending.
	IsPlaceholder bool

	// MessageID is the store-assigned identifier for this message.
	// Populated when the message is finalized from a bus.MessageAppended
	// event or hydrated from the store.  Used to detect and suppress
	// duplicate insertions when the same MessageAppended event is processed
	// more than once (e.g. around tool calls or subagent boundaries where
	// the event may be replayed or arrive after the bubble was already
	// flushed).  Empty for messages that were never persisted (placeholders,
	// system error rows).
	MessageID string
}

UIMessage is one entry in the conversation view.

FinalMarkdown is the glamour-rendered output. Set by flushAssistantStream (and hydration/resize paths) once streaming completes; empty while streaming.

type URLHitZone added in v0.12.1

type URLHitZone struct {
	// Line is the content line index (same coordinate space as SubagentHitZone
	// StartLine), i.e. offset from the top of the rendered message list including
	// viewport scroll offset.
	Line     int
	StartCol int    // inclusive visual column (0-indexed screen column)
	EndCol   int    // exclusive visual column
	URL      string // validated http(s) URL, trailing punctuation stripped
}

URLHitZone maps a single screen line + column range to a clickable URL found in user or assistant message output. Clicking within [StartCol, EndCol) on the content line should open the URL with the OS default browser.

type URLPosition added in v0.12.1

type URLPosition struct {
	Line     int    // zero-indexed line within the rendered part
	StartCol int    // zero-indexed column where URL text begins
	EndCol   int    // zero-indexed column just past the last URL character
	URL      string // the matched URL (trailing punctuation stripped)
}

URLPosition records a URL's location within a block of rendered text. Line and StartCol/EndCol are zero-indexed visual positions in the ANSI-stripped text.

func ExtractURLPositions added in v0.12.1

func ExtractURLPositions(rendered string) []URLPosition

ExtractURLPositions scans a rendered (potentially ANSI-styled) text block and returns the visual line/column position of every http(s):// URL found. It strips ANSI sequences before matching so escape codes do not shift column indices. Duplicate URLs on the same line are each returned separately.

type UserMsgHitZone added in v0.13.1

type UserMsgHitZone struct {
	StartLine   int // inclusive, relative to message-list content
	EndLine     int // exclusive
	StartCol    int // inclusive visual column within the chat column
	EndCol      int // exclusive visual column within the chat column
	MessageID   string
	MessageText string // raw message text (for copy action)
	// contains filtered or unexported fields
}

UserMsgHitZone maps a rendered user bubble rectangle to a user message.

Directories

Path Synopsis
Package anim provides a compact colored-runes animation component for use in terminal UIs built with bubbletea v2.
Package anim provides a compact colored-runes animation component for use in terminal UIs built with bubbletea v2.
Package bubble provides the Bubble rendering primitive for the chat-bubble UI redesign (Phase 1).
Package bubble provides the Bubble rendering primitive for the chat-bubble UI redesign (Phase 1).

Jump to

Keyboard shortcuts

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