tui

package
v0.17.14 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package tui provides terminal UI utilities.

Package tui provides terminal UI utilities.

Package tui provides terminal UI utilities.

Package tui provides terminal UI utilities.

Package tui provides terminal UI utilities.

Package tui provides terminal UI utilities.

Package tui provides the terminal user interface for stackit.

It handles:

  • Interactive prompts and selections (using survey and bubbletea)
  • Terminal styling and colors (using lipgloss)
  • Progress indicators and UI components

Index

Constants

View Source
const (
	StatusPending = core.StatusPending
	StatusActive  = core.StatusActive
	StatusDone    = core.StatusDone
	StatusError   = core.StatusError
	StatusSkipped = core.StatusSkipped
	StatusWaiting = core.StatusWaiting
)

Status constants re-exported from core for backwards compatibility.

View Source
const (
	KeyCtrlC = core.KeyCtrlC
	KeyQuit  = core.KeyQuit
	KeyEsc   = core.KeyEsc
	KeyEnter = core.KeyEnter
	KeyUp    = core.KeyUp
	KeyDown  = core.KeyDown
	KeyTab   = core.KeyTab
)

Key constants re-exported from core for backwards compatibility.

Variables

View Source
var ErrInteractiveDisabled = fmt.Errorf("interactive prompts are disabled (running with --no-interactive or not in a TTY)")

ErrInteractiveDisabled is returned when interactive prompts are disabled

View Source
var PromptConfirm = func(prompt string, defaultValue bool) (bool, error) {
	if err := CheckInteractiveAllowed(); err != nil {
		return false, err
	}

	m := confirmModel{
		prompt: prompt,
		choice: defaultValue,
		help:   help.New(),
		keys:   confirmPromptKeys,
	}

	p := tea.NewProgram(m, tea.WithInput(os.Stdin), tea.WithOutput(os.Stdout))
	model, err := p.Run()
	if err != nil {
		return false, err
	}

	if finalModel, ok := model.(confirmModel); ok {
		if finalModel.err != nil {
			return false, finalModel.err
		}
		return finalModel.choice, nil
	}

	return false, fmt.Errorf("unexpected model type")
}

PromptConfirm prompts the user for yes/no confirmation

View Source
var Stories = []Story{}

Stories is a registry of all component stories

Functions

func BuildFullAnnotation

func BuildFullAnnotation(eng engine.Engine, branch engine.Branch, enrichment *AnnotationEnrichment) tree.BranchAnnotation

BuildFullAnnotation returns a fully populated BranchAnnotation including git operations (SHA, commits, diff stats), CI status, review status, and worktree info. Pass nil for enrichment to get just the base annotation without CI/worktree enrichment.

func CheckInteractiveAllowed

func CheckInteractiveAllowed() error

CheckInteractiveAllowed returns an error if interactive mode is disabled

func GetBranchAnnotation

func GetBranchAnnotation(eng engine.BranchReader, branch engine.Branch) tree.BranchAnnotation

GetBranchAnnotation returns a tree.BranchAnnotation populated with standard branch metadata. This includes git operations (SHA, commit count, diff stats) which may be slow.

func GetEmptyWorktrees

func GetEmptyWorktrees(eng engine.Engine) map[string]*engine.WorktreeInfo

GetEmptyWorktrees returns a map of worktree anchor branch names to their WorktreeInfo for worktrees that have no child branches (empty worktrees).

func GetMinimalAnnotationWithWorktreeAndEmpty

func GetMinimalAnnotationWithWorktreeAndEmpty(eng engine.Engine, branch engine.Branch, wtData *WorktreeData) tree.BranchAnnotation

GetMinimalAnnotationWithWorktreeAndEmpty returns minimal annotations plus worktree info, with support for marking empty worktrees. This is used for fast initial rendering before full data is loaded. Only includes cached/instant fields - no git or network calls.

func IsTTY

func IsTTY() bool

IsTTY returns true if we can use a TTY for interactive TUI. Re-export from utils for backward compatibility.

func NewBranchSelectModel

func NewBranchSelectModel(message string, choices []BranchChoice, initialIndex int) tea.Model

NewBranchSelectModel creates a tea.Model for a branch selection prompt (used by stories/demo)

func NewConfirmModel

func NewConfirmModel(prompt string, defaultValue bool) tea.Model

NewConfirmModel creates a tea.Model for a confirmation prompt (used by stories/demo)

func NewReorderModel

func NewReorderModel(branches []string, trunk string) tea.Model

NewReorderModel creates a tea.Model for a reorder prompt (used by stories/demo)

func NewSelectModel

func NewSelectModel(title string, options []SelectOption, defaultIndex int) tea.Model

NewSelectModel creates a tea.Model for a selection prompt (used by stories/demo)

func NewStackTreeRenderer

func NewStackTreeRenderer(eng engine.BranchReader) *tree.StackTreeRenderer

NewStackTreeRenderer creates a tree renderer configured for the current engine state using the SMART sorting strategy (active path hoisting + newest first).

func NewStackTreeRendererWithEmptyWorktrees

func NewStackTreeRendererWithEmptyWorktrees(eng engine.BranchReader, emptyWorktrees map[string]bool) *tree.StackTreeRenderer

NewStackTreeRendererWithEmptyWorktrees creates a tree renderer that shows empty worktree anchors

func NewStackTreeRendererWithFilter

func NewStackTreeRendererWithFilter(eng engine.BranchReader, filter func(string) bool) *tree.StackTreeRenderer

NewStackTreeRendererWithFilter creates a tree renderer with a filter function

func NewStackTreeRendererWithOptions

func NewStackTreeRendererWithOptions(eng engine.BranchReader, strategy engine.SortStrategy, filter func(string) bool, emptyWorktrees map[string]bool) *tree.StackTreeRenderer

NewStackTreeRendererWithOptions creates a tree renderer with all options

func NewStackTreeRendererWithStrategy

func NewStackTreeRendererWithStrategy(eng engine.BranchReader, strategy engine.SortStrategy, filter func(string) bool) *tree.StackTreeRenderer

NewStackTreeRendererWithStrategy creates a tree renderer with a specific sorting strategy and optional filter

func NewTextInputModel

func NewTextInputModel(prompt, defaultValue string) tea.Model

NewTextInputModel creates a tea.Model for a text input prompt (used by stories/demo)

func OpenEditor

func OpenEditor(initialContent, filenamePattern string) (string, error)

OpenEditor opens the user's preferred editor with the given initial content. It returns the edited content or an error.

func PromptBranchCheckout

func PromptBranchCheckout(branches []engine.Branch, eng engine.BranchReader) (string, error)

PromptBranchCheckout shows an interactive branch selector for checkout. It takes a list of branches and the engine context, formats them using tree rendering, and presents them for selection.

func PromptBranchSelection

func PromptBranchSelection(message string, choices []BranchChoice, initialIndex int) (string, error)

PromptBranchSelection prompts the user to select a branch

func PromptLogSelect

func PromptLogSelect(ctx context.Context, eng engine.Engine, ghClient github.Client, opts LogOptions) (string, error)

PromptLogSelect runs the interactive log in selection mode and returns the selected branch name

func PromptMultiSelect

func PromptMultiSelect(title string, options []string) ([]string, error)

PromptMultiSelect prompts the user to select multiple items from a list

func PromptMultiSelectWithDefaults

func PromptMultiSelectWithDefaults(title string, options []string, preSelected []bool) ([]string, error)

PromptMultiSelectWithDefaults prompts the user to select multiple items from a list with optional pre-selected items. If preSelected is nil, nothing is selected by default.

func PromptSelect

func PromptSelect(title string, options []SelectOption, defaultIndex int) (string, error)

PromptSelect prompts the user to select from a list of options

func PromptSelectHunks

func PromptSelectHunks(hunks []git.Hunk) ([]git.Hunk, error)

PromptSelectHunks shows an interactive hunk selector and returns the selected hunks

func PromptTextInput

func PromptTextInput(prompt, defaultValue string) (string, error)

PromptTextInput prompts the user for text input

func RegisterStory

func RegisterStory(story Story)

RegisterStory registers a new component story

func RenderFlattenPreview

func RenderFlattenPreview(preview FlattenPreviewData) string

RenderFlattenPreview renders a flatten preview showing: - List of branches that will be moved and their new parents - Count of branches that will stay unchanged - Conflict status

func RenderMovePreviewSimple

func RenderMovePreviewSimple(preview MovePreviewData) string

RenderMovePreviewSimple renders a simplified move preview showing: - Current location (dimmed) - New location (highlighted) - Conflict status

func RunReorderTUI

func RunReorderTUI(branches []string, trunk string) ([]string, error)

RunReorderTUI runs the reorder TUI and returns the new order trunk is displayed at the bottom but is not selectable or reorderable

func RunSubmitTUI

func RunSubmitTUI(items []submit.Item, submitFunc func(idx int) tea.Cmd) error

RunSubmitTUI runs the submit TUI and returns when complete

func RunSubmitTUISimple

func RunSubmitTUISimple(items []submit.Item, submitFunc func(idx int) (string, error), splog output.Output) error

RunSubmitTUISimple runs a simple non-interactive version for non-TTY environments

func SafeCmd

func SafeCmd(name string, logger output.Logger, cmd tea.Cmd) tea.Cmd

SafeCmd wraps a tea.Cmd with panic recovery. If the command panics, it logs the error and returns a PanicError message. This is useful for commands that perform IO or call external APIs.

func SafeCmdFunc

func SafeCmdFunc(name string, logger output.Logger, fn func() tea.Msg) tea.Cmd

SafeCmdFunc wraps a function that returns tea.Msg with panic recovery. If the function panics, it logs the error and returns a PanicError message.

func SetInteractive

func SetInteractive(interactive bool)

SetInteractive sets whether the TUI should be interactive. Re-export from utils for backward compatibility. This function is thread-safe and can be called from concurrent goroutines.

Types

type AllDoneMsg

type AllDoneMsg struct{}

AllDoneMsg signals all submissions are complete

type AnnotationEnrichment

type AnnotationEnrichment struct {
	CIStatuses          map[string]*github.CheckStatus
	EmptyWorktrees      map[string]*engine.WorktreeInfo
	WorktreeByStackRoot map[string]*engine.WorktreeInfo
}

AnnotationEnrichment holds pre-fetched data for enriching branch annotations. This allows CI statuses and worktree info to be computed once and shared across all branches, avoiding redundant lookups.

type BaseModel

type BaseModel = core.BaseModel

BaseModel is an alias to core.BaseModel for backwards compatibility. New code should import from tui/core directly to avoid import cycles.

type BranchChoice

type BranchChoice struct {
	Display string // What to show (may include tree visualization)
	Value   string // Actual branch name
}

BranchChoice represents a branch option in a selection prompt

type CompleteMsg

type CompleteMsg struct {
	Success bool   // True if operation succeeded
	Summary string // Summary message to display
	Error   error  // Error if Success is false
}

CompleteMsg signals operation completion. Use this to indicate that the overall operation is done.

type Direction

type Direction string

Direction represents where to place a new branch

const (
	DirectionBelow Direction = "below"
	DirectionAbove Direction = "above"
)

Direction constants for split operations.

func PromptDirectionSelect

func PromptDirectionSelect(eng engine.BranchReader, currentBranch, parentBranch string, children []string) (Direction, error)

PromptDirectionSelect shows an interactive direction selector and returns the chosen direction

type DirectionSelectModel

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

DirectionSelectModel is a bubbletea model for selecting split direction

func NewDirectionSelectModel

func NewDirectionSelectModel(eng engine.BranchReader, currentBranch, parentBranch string, children []string) *DirectionSelectModel

NewDirectionSelectModel creates a model for selecting split direction

func (*DirectionSelectModel) Back

func (m *DirectionSelectModel) Back() bool

Back returns true if the user pressed back

func (*DirectionSelectModel) Direction

func (m *DirectionSelectModel) Direction() Direction

Direction returns the selected direction

func (*DirectionSelectModel) Err

func (m *DirectionSelectModel) Err() error

Err returns any error that occurred

func (*DirectionSelectModel) Init

func (m *DirectionSelectModel) Init() tea.Cmd

Init implements tea.Model.

func (*DirectionSelectModel) Update

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

Update implements tea.Model.

func (*DirectionSelectModel) View

func (m *DirectionSelectModel) View() tea.View

View implements tea.Model.

type FileGroup

type FileGroup struct {
	File   string
	Hunks  []int // Indices into the items slice
	Binary bool  // Is this a binary file?
}

FileGroup groups hunks by file for rendering

type FlattenExcludedBranch

type FlattenExcludedBranch struct {
	Branch string // Branch name
	Reason string // Why it was kept in place
}

FlattenExcludedBranch represents a branch that was kept in place due to code dependencies. This is a local struct to avoid import cycles with the actions/flatten package.

type FlattenPlannedMove

type FlattenPlannedMove struct {
	Branch    string // Branch being moved
	OldParent string // Current parent branch
	NewParent string // Target parent branch (closer to trunk)
}

FlattenPlannedMove represents a single branch move in the flatten plan. This is a local struct to avoid import cycles with the actions/flatten package.

type FlattenPreviewData

type FlattenPreviewData struct {
	Moves            []FlattenPlannedMove    // Branches that will be moved
	UnchangedCount   int                     // Number of branches that won't change
	ExcludedBranches []FlattenExcludedBranch // Branches excluded due to conflicts
}

FlattenPreviewData contains the data needed to render a flatten preview. This is a local struct to avoid import cycles with the actions/flatten package.

type Handler

type Handler interface {
	// IsInteractive returns true if this handler supports interactive prompts.
	// Interactive handlers can pause the TUI for user input.
	IsInteractive() bool

	// Cleanup performs any necessary cleanup. Safe to call multiple times.
	// For interactive handlers, this typically delegates to the Runner.
	Cleanup()
}

Handler is the base interface for all TUI handlers. Handlers abstract the difference between interactive (TTY) and non-interactive output.

type HunkItem

type HunkItem struct {
	Hunk       git.Hunk
	Selected   bool
	Expanded   bool // Manual expand/collapse override
	Splittable bool // Can this hunk be split further?
}

HunkItem represents a single hunk in the selector

type HunkSelectorModel

type HunkSelectorModel struct {
	core.BaseModel // Embedded for ReadySignaler interface
	// contains filtered or unexported fields
}

HunkSelectorModel is a bubbletea model for selecting hunks. It embeds core.BaseModel for standard lifecycle handling.

func NewHunkSelectorModel

func NewHunkSelectorModel(hunks []git.Hunk) *HunkSelectorModel

NewHunkSelectorModel creates a new hunk selector model

func (*HunkSelectorModel) Err

func (m *HunkSelectorModel) Err() error

Err returns any error that occurred

func (*HunkSelectorModel) Init

func (m *HunkSelectorModel) Init() tea.Cmd

Init implements tea.Model

func (*HunkSelectorModel) Reset

func (m *HunkSelectorModel) Reset()

Reset resets the model state for reuse

func (*HunkSelectorModel) SelectedHunks

func (m *HunkSelectorModel) SelectedHunks() []git.Hunk

SelectedHunks returns the hunks that were selected

func (*HunkSelectorModel) SetHunks

func (m *HunkSelectorModel) SetHunks(hunks []git.Hunk)

SetHunks replaces the hunks in the model for reuse in subsequent selections. This allows the hunk selector to be reused in a loop without creating new models.

func (*HunkSelectorModel) Update

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

Update implements tea.Model

func (*HunkSelectorModel) View

func (m *HunkSelectorModel) View() tea.View

View implements tea.Model

type LogMode

type LogMode int

LogMode defines how the log is used

const (
	// LogModeView is the default view mode for browsing the log
	LogModeView LogMode = iota
	// LogModeSelect is the selection mode for choosing a branch
	LogModeSelect
)

type LogModel

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

LogModel is the bubbletea model for the interactive log

func NewLogModel

func NewLogModel(ctx context.Context, eng engine.Engine, ghClient github.Client, opts LogOptions) *LogModel

NewLogModel creates a new LogModel

func (*LogModel) Init

func (m *LogModel) Init() tea.Cmd

Init initializes the bubbletea model

func (*LogModel) SetAltScreen

func (m *LogModel) SetAltScreen(enabled bool)

SetAltScreen sets whether the model should use alt screen mode

func (*LogModel) Update

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

Update handles message updates for the bubbletea model

func (*LogModel) View

func (m *LogModel) View() tea.View

View renders the bubbletea model

type LogOptions

type LogOptions struct {
	Style               string
	ShowUntracked       bool
	Exclude             map[string]bool                  // Branches to exclude from selection
	NonSelectable       map[string]bool                  // Branches visible but not selectable (cursor skips them)
	AnnotationOverrides map[string]tree.BranchAnnotation // Override annotations (e.g., add custom labels)
	Logger              output.Logger                    // Optional logger for IO timing diagnostics
	Header              string                           // Custom header text for selection mode (e.g., "Select new parent for branch X")
	SkipEnrichment      bool                             // Skip background GitHub/git enrichment for faster startup
	Inline              bool                             // Run inline without alt-screen (doesn't take over terminal)

	// ValidateSelection is called (with debounce) when selection changes to validate the current selection.
	// If provided, the result is displayed in the UI footer.
	ValidateSelection func(branchName string) *SelectionValidation
}

LogOptions repeated here to avoid circular dependency if needed, but we'll probably use actions.LogOptions

type MessageRecorder

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

MessageRecorder records messages for test assertions. It can be used to verify that specific messages were sent during tests.

func NewMessageRecorder

func NewMessageRecorder() *MessageRecorder

NewMessageRecorder creates a new MessageRecorder.

func (*MessageRecorder) Count

func (r *MessageRecorder) Count() int

Count returns the number of recorded messages.

func (*MessageRecorder) HasMessage

func (r *MessageRecorder) HasMessage(predicate func(tea.Msg) bool) bool

HasMessage returns true if any recorded message matches the predicate.

func (*MessageRecorder) Messages

func (r *MessageRecorder) Messages() []tea.Msg

Messages returns a copy of all recorded messages.

func (*MessageRecorder) Record

func (r *MessageRecorder) Record(msg tea.Msg)

Record adds a message to the recorder.

func (*MessageRecorder) Reset

func (r *MessageRecorder) Reset()

Reset clears all recorded messages.

type MockRunner

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

MockRunner is a test double for Runner. It records all messages sent to it and provides methods to inspect them.

func NewMockRunner

func NewMockRunner() *MockRunner

NewMockRunner creates a new MockRunner.

func (*MockRunner) Cleanup

func (m *MockRunner) Cleanup()

Cleanup marks the runner as stopped.

func (*MockRunner) IsHealthy

func (m *MockRunner) IsHealthy() bool

IsHealthy returns true if the runner has been started and not stopped.

func (*MockRunner) MessageCount

func (m *MockRunner) MessageCount() int

MessageCount returns the number of recorded messages.

func (*MockRunner) Messages

func (m *MockRunner) Messages() []tea.Msg

Messages returns a copy of all recorded messages.

func (*MockRunner) Pause

func (m *MockRunner) Pause()

Pause is a no-op for the mock runner.

func (*MockRunner) Reset

func (m *MockRunner) Reset()

Reset clears all recorded messages and state.

func (*MockRunner) Resume

func (m *MockRunner) Resume()

Resume is a no-op for the mock runner.

func (*MockRunner) Send

func (m *MockRunner) Send(msg tea.Msg)

Send records a message for later inspection.

func (*MockRunner) Start

func (m *MockRunner) Start()

Start marks the runner as started.

func (*MockRunner) Wait

func (m *MockRunner) Wait()

Wait is a no-op for the mock runner.

type MoveModel

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

MoveModel is the bubbletea model for the interactive move flow

func NewMoveModel

func NewMoveModel(eng engine.Engine, config MoveModelConfig) *MoveModel

NewMoveModel creates a new MoveModel for interactive branch selection

func (*MoveModel) Init

func (m *MoveModel) Init() tea.Cmd

Init initializes the model

func (*MoveModel) Result

func (m *MoveModel) Result() MoveResult

Result returns the result of the move selection

func (*MoveModel) Update

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

Update handles messages and updates state

func (*MoveModel) View

func (m *MoveModel) View() tea.View

View renders the current state

type MoveModelConfig

type MoveModelConfig struct {
	SourceBranch string          // Branch being moved
	Descendants  []engine.Branch // Descendants that will be restacked
	OldParent    *engine.Branch  // Current parent branch
	OldParentRev string          // Current parent revision for rebase specs
	Validator    MoveValidator   // Validation function for conflict checking
}

MoveModelConfig contains configuration for the move model

type MovePreviewData

type MovePreviewData struct {
	SourceBranch   string   // Branch being moved
	OldParent      string   // Current parent branch
	NewParent      string   // Target parent branch
	Commits        []string // Commit subjects that will be moved
	Descendants    []string // Descendant branches that will be restacked
	HasConflicts   bool     // Whether the move will cause conflicts
	ConflictBranch string   // Which branch would have conflicts (if any)
	ConflictError  string   // Error message describing the conflict
}

MovePreviewData contains the data needed to render a move preview. This is a local struct to avoid import cycles with the actions/move package.

type MoveResult

type MoveResult struct {
	SelectedParent string              // The branch selected as new parent
	RebaseSpecs    []engine.RebaseSpec // Precomputed rebase specs for the selection
	Canceled       bool                // Whether the user canceled
}

MoveResult contains the result of the interactive move selection

func PromptMoveSelect

func PromptMoveSelect(eng engine.Engine, config MoveModelConfig) (MoveResult, error)

PromptMoveSelect runs the interactive move selection and returns the selection result.

type MoveValidation

type MoveValidation struct {
	Valid          bool                // Whether the move is valid (no conflicts)
	Message        string              // Status message
	Commits        []string            // Commits that will be moved
	HasConflicts   bool                // Whether conflicts were detected
	ConflictBranch string              // Branch with conflicts
	ConflictError  string              // Conflict error message
	RebaseSpecs    []engine.RebaseSpec // Precomputed rebase specs for this selection
}

MoveValidation contains the result of validating a move

type MoveValidator

type MoveValidator func(ontoBranch string) (*MoveValidation, error)

MoveValidator validates a potential move operation

type PanicError

type PanicError struct {
	Source string // Name of the operation that panicked
	Err    error  // The panic value wrapped as an error
	Stack  string // Stack trace at the time of panic
}

PanicError is sent when a tea.Cmd panics during execution. Models can handle this to show an error message or recover gracefully.

func (PanicError) Error

func (p PanicError) Error() string

type PhaseHandler

type PhaseHandler interface {
	ProgressHandler

	// StartPhase begins a named phase.
	// Only one phase can be active at a time.
	StartPhase(phase string)

	// PhaseDetail adds a detail line to the current phase.
	// Use this for per-item progress within a phase.
	PhaseDetail(phase, detail string)

	// CompletePhase marks a phase as done.
	// Call this before starting the next phase.
	CompletePhase(phase string)
}

PhaseHandler extends ProgressHandler with phase tracking. Use this for operations that have distinct phases (e.g., sync: trunk, github, clean, restack).

type PhaseMsg

type PhaseMsg struct {
	Phase  string // Name of the phase
	Status Status // Current status of the phase
	Detail string // Optional detail message
}

PhaseMsg indicates a phase state change. Use this to communicate phase transitions to TUI models.

type ProgressHandler

type ProgressHandler interface {
	Handler

	// Start initializes progress tracking with total operations.
	// Call this at the beginning of the operation.
	Start(totalOps int)

	// Progress updates the current progress.
	// completed should be <= total passed to Start().
	Progress(completed, total int)

	// Complete signals completion with a summary message.
	// Call this when the operation is done.
	Complete(summary string)
}

ProgressHandler extends Handler with progress tracking. Use this for operations that have a known number of steps.

type ProgressMsg

type ProgressMsg struct {
	Completed int // Number of completed operations
	Total     int // Total number of operations
}

ProgressMsg updates progress state. Use this to communicate progress updates to TUI models.

func (ProgressMsg) Percent

func (m ProgressMsg) Percent() float64

Percent returns the completion percentage (0.0 to 1.0). Returns 0 if Total is 0.

type PromptHandler

type PromptHandler interface {
	Handler

	// SupportsPrompts returns true if this handler can show prompts.
	// This is typically the same as IsInteractive(), but allows for
	// handlers that are interactive but don't support prompts.
	SupportsPrompts() bool
}

PromptHandler provides interactive prompt capabilities. Handlers that support prompts should implement this interface.

type ReadySignaler

type ReadySignaler = core.ReadySignaler

ReadySignaler is an alias to core.ReadySignaler for backwards compatibility.

type Runner

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

Runner manages async bubbletea program lifecycle with panic recovery. It handles signal handling, terminal cleanup, and crash logging.

func NewRunner

func NewRunner(model tea.Model, out output.Output, logger output.Logger) *Runner

NewRunner creates a new TUI runner for async program execution. Use NewRunnerWithContext if you need cancellation support.

func NewRunnerWithContext

func NewRunnerWithContext(ctx context.Context, model tea.Model, out output.Output, logger output.Logger) *Runner

NewRunnerWithContext creates a new TUI runner with context support. The context will be canceled when Cleanup is called, allowing background operations to be properly terminated.

func (*Runner) Cleanup

func (r *Runner) Cleanup()

Cleanup ensures the terminal is restored to normal mode. This is safe to call multiple times and on nil receivers.

func (*Runner) Context

func (r *Runner) Context() context.Context

Context returns the runner's context for use in background operations. If the runner was created without a context (using NewRunner), this returns context.Background().

func (*Runner) IsHealthy

func (r *Runner) IsHealthy() bool

IsHealthy returns true if the TUI is running and responsive. This is a more comprehensive check than IsRunning, verifying the program is not nil.

func (*Runner) IsRunning

func (r *Runner) IsRunning() bool

IsRunning returns true if the program is currently running. Safe to call on nil receivers.

func (*Runner) MustSend

func (r *Runner) MustSend(msg tea.Msg)

MustSend sends a message and logs error if timeout occurs. Uses a default 5-second timeout. This is the recommended way to send messages when you want hang detection without blocking indefinitely.

func (*Runner) Pause

func (r *Runner) Pause()

Pause releases the terminal for interactive prompts. This is safe to call on nil receivers.

func (*Runner) Resume

func (r *Runner) Resume()

Resume restores the TUI after Pause. This is safe to call on nil receivers.

func (*Runner) Send

func (r *Runner) Send(msg tea.Msg)

Send sends a message to the running program. Safe to call on nil receivers or when program is not running (no-op).

func (*Runner) SendWithTimeout

func (r *Runner) SendWithTimeout(msg tea.Msg, timeout time.Duration) error

SendWithTimeout sends a message with a timeout. Returns error if the send doesn't complete within the timeout or if the runner's context is canceled (e.g., during Cleanup). This is useful for detecting hangs in the TUI event loop.

func (*Runner) Start

func (r *Runner) Start()

Start begins running the tea.Program in a background goroutine. It sets up signal handling and panic recovery. If the model implements ReadySignaler, Start waits for the model to signal readiness before returning, preventing race conditions with Send().

func (*Runner) Wait

func (r *Runner) Wait()

Wait blocks until the program exits. Safe to call on nil receivers.

type SelectOption

type SelectOption struct {
	Label string // What to show
	Value string // Value to return
}

SelectOption represents an option in a selection prompt

type SelectionValidation

type SelectionValidation struct {
	Valid   bool   // Whether the selection is valid (no conflicts)
	Message string // Status message to display (e.g., "Move will complete without conflicts")
}

SelectionValidation contains the result of validating a selection

type Sender

type Sender interface {
	// Send sends a message to the TUI model.
	Send(msg tea.Msg)

	// Pause pauses TUI rendering for interactive prompts.
	Pause()

	// Resume resumes TUI rendering after a pause.
	Resume()

	// Wait blocks until the TUI exits.
	Wait()

	// Cleanup performs terminal cleanup.
	Cleanup()

	// IsHealthy returns true if the TUI is running and responsive.
	IsHealthy() bool
}

Sender is the interface for sending messages to a TUI. Both *Runner and *MockRunner implement this interface.

type Status

type Status = core.Status

Status is an alias to core.Status for backwards compatibility. New code should import from tui/core directly to avoid import cycles.

type Story

type Story struct {
	Name        string
	Category    string
	Description string
	CreateModel func() tea.Model
}

Story represents a specific state of a TUI component

type SubmitResultMsg

type SubmitResultMsg struct {
	Idx   int
	URL   string
	Error error
}

SubmitResultMsg is sent when a single submit completes

type SubmitTUIModel

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

SubmitTUIModel is the bubbletea model for submit progress

func NewSubmitTUIModel

func NewSubmitTUIModel(items []submit.Item, submitFunc func(idx int) tea.Cmd) SubmitTUIModel

NewSubmitTUIModel creates a new submit TUI model

func (SubmitTUIModel) Init

func (m SubmitTUIModel) Init() tea.Cmd

Init initializes the bubbletea model

func (SubmitTUIModel) Update

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

Update handles message updates for the bubbletea model

func (SubmitTUIModel) View

func (m SubmitTUIModel) View() tea.View

View renders the bubbletea model

type WorktreeData

type WorktreeData struct {
	EmptyWorktrees      map[string]*engine.WorktreeInfo // Anchor branches with no children
	WorktreeByStackRoot map[string]*engine.WorktreeInfo // Stack root -> worktree info
}

WorktreeData holds pre-computed worktree information from a single ListManagedWorktrees call.

func GetWorktreeData

func GetWorktreeData(eng engine.Engine) *WorktreeData

GetWorktreeData builds both empty worktree and stack-root worktree maps from a single ListManagedWorktrees call, avoiding redundant lookups.

Directories

Path Synopsis
components
flatten
Package flatten provides a TUI component for displaying flatten progress.
Package flatten provides a TUI component for displaying flatten progress.
foreach
Package foreach provides a TUI component for displaying the progress of foreach command execution.
Package foreach provides a TUI component for displaying the progress of foreach command execution.
merge
Package merge provides a TUI component for displaying merge progress.
Package merge provides a TUI component for displaying merge progress.
split
Package split provides a unified TUI component for split operations.
Package split provides a unified TUI component for split operations.
submit
Package submit provides a TUI component for displaying the progress of a stack submission.
Package submit provides a TUI component for displaying the progress of a stack submission.
sync
Package sync provides a TUI component for displaying sync progress.
Package sync provides a TUI component for displaying sync progress.
tree
Package tree provides a renderer for branch tree visualizations.
Package tree provides a renderer for branch tree visualizations.
Package config provides TUI components for configuration management.
Package config provides TUI components for configuration management.
Package core provides foundational TUI types that can be imported without cycles.
Package core provides foundational TUI types that can be imported without cycles.
Package keys provides shared keybindings for TUI views.
Package keys provides shared keybindings for TUI views.
Package style provides styling and coloring for the TUI.
Package style provides styling and coloring for the TUI.

Jump to

Keyboard shortcuts

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