Documentation
¶
Overview ¶
Package tui is the Bubble Tea three-pane review cockpit (files / findings / detail). Lands in M4.
Package tui implements the interactive TUI for reviewing findings using the Bubble Tea framework.
Index ¶
- func Run(m *Model) error
- type InboxAction
- type InboxModel
- type LoadErrorMsg
- type LoadReadyMsg
- type LoaderModel
- func (m *LoaderModel) Err() error
- func (m *LoaderModel) GetApprovedFindings() []review.Finding
- func (m *LoaderModel) GetFindingsMarkedForPost() []review.Finding
- func (m *LoaderModel) Init() tea.Cmd
- func (m *LoaderModel) Quarantined() []review.Quarantined
- func (m *LoaderModel) ReviewModel() *Model
- func (m *LoaderModel) TotalReviewed() int
- func (m *LoaderModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *LoaderModel) View() string
- type Model
- func (m *Model) ApproveCurrent()
- func (m *Model) ApprovedCount() int
- func (m *Model) CurrentFinding() *review.Finding
- func (m *Model) DismissCurrent()
- func (m *Model) DismissedCount() int
- func (m *Model) EditCurrentComment(newComment string)
- func (m *Model) EditCurrentEvidence(newEvidence string)
- func (m *Model) EditCurrentFixHint(newFixHint string)
- func (m *Model) EditCurrentTitle(newTitle string)
- func (m *Model) EditMode() bool
- func (m *Model) GetApprovedFindings() []review.Finding
- func (m *Model) GetFindingsMarkedForPost() []review.Finding
- func (m *Model) Init() tea.Cmd
- func (m *Model) IsPostBoundRow(i int) bool
- func (m *Model) MarkCurrentForPost()
- func (m *Model) MoveDown()
- func (m *Model) MoveUp()
- func (m *Model) TransientStatus() string
- func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *Model) View() string
- type ModelPickerItem
- type ModelPickerModel
- func (m *ModelPickerModel) Cancelled() bool
- func (m *ModelPickerModel) Confirmed() bool
- func (m *ModelPickerModel) Init() tea.Cmd
- func (m *ModelPickerModel) IsChecked(name string) bool
- func (m *ModelPickerModel) SelectedNames() []string
- func (m *ModelPickerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *ModelPickerModel) View() string
- type ModelStatusMsg
- type PhaseStatusMsg
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type InboxAction ¶
type InboxAction int
InboxAction encodes how the user exited the inbox screen. The top-level loop in app/inbox.go switches on this to decide whether to open a review, refresh the list, or quit the program.
const ( InboxActionNone InboxAction = iota InboxActionOpen InboxActionRefresh InboxActionQuit )
type InboxModel ¶
type InboxModel struct {
// contains filtered or unexported fields
}
InboxModel renders a single-pane selectable list of PRSummary rows. It is intentionally separate from the review Model so we can run a fresh tea.NewProgram for each (per the step-out-between-picks pattern from the design spec §7).
func NewInboxModel ¶
func NewInboxModel(summaries []provider.PRSummary, owner, name string) *InboxModel
func (*InboxModel) Action ¶
func (m *InboxModel) Action() InboxAction
Action returns how the user exited the inbox. None until Update sees a terminal key.
func (*InboxModel) Init ¶
func (m *InboxModel) Init() tea.Cmd
func (*InboxModel) Pick ¶
func (m *InboxModel) Pick() *provider.PRSummary
Pick returns the chosen summary, only meaningful when Action() == InboxActionOpen.
func (*InboxModel) ResetSession ¶ added in v0.3.0
func (m *InboxModel) ResetSession()
ResetSession clears the exit state (action, pick) so a reused model can host a fresh Bubble Tea session while keeping the cached list. The app reuses one InboxModel across sessions (spec §7: the list persists between picks); without this reset a teardown-without- keypress after the first open replayed the stale InboxActionOpen and re-launched the previous review. diffsmith-qe5.
func (*InboxModel) Selected ¶
func (m *InboxModel) Selected() int
Selected returns the current cursor index. Exposed for tests.
func (*InboxModel) View ¶
func (m *InboxModel) View() string
type LoadErrorMsg ¶
type LoadErrorMsg struct{ Err error }
LoadErrorMsg surfaces a pipeline failure. The loader renders the error and waits for the user to dismiss with q/ctrl+c.
type LoadReadyMsg ¶
type LoadReadyMsg struct {
Findings []review.Finding
Quarantined []review.Quarantined
}
LoadReadyMsg hands validated findings + quarantined ones to the loader. After this arrives the loader transitions to the inner ReviewModel.
The per-run summary string (which models ran, counts, synthesis lead) is intentionally NOT carried on this message — it lives as a closure variable in the caller (app/review.go) and is written to stdout after the loader exits. Keeping it out of the loader avoids dead state on the model and keeps the run-summary write outside the TUI's render loop where it belongs.
type LoaderModel ¶
type LoaderModel struct {
// contains filtered or unexported fields
}
LoaderModel wraps the review Model so the TUI can launch immediately when the user runs `diffsmith review` and stream pipeline phases (fetch → model → validate) through an animated spinner + status text before findings arrive. Once LoadReadyMsg fires, View delegates to the inner ReviewModel for the rest of the session.
Pattern: a goroutine in the app layer drives the pipeline and pushes messages via tea.Program.Send. The loader stays in the bubbletea event loop the whole time, so the spinner keeps animating without any extra goroutine inside the TUI.
func NewLoaderModel ¶
func NewLoaderModel(initialStatus string) *LoaderModel
NewLoaderModel constructs a LoaderModel with a default-styled spinner and an initial status line. The status updates as PhaseStatusMsg messages arrive from the pipeline.
func (*LoaderModel) Err ¶
func (m *LoaderModel) Err() error
Err returns any pipeline error pushed via LoadErrorMsg. The app layer reads this after the TUI quits and propagates as the process exit code.
func (*LoaderModel) GetApprovedFindings ¶
func (m *LoaderModel) GetApprovedFindings() []review.Finding
GetApprovedFindings delegates to the inner ReviewModel; returns nil before findings have loaded.
func (*LoaderModel) GetFindingsMarkedForPost ¶
func (m *LoaderModel) GetFindingsMarkedForPost() []review.Finding
GetFindingsMarkedForPost delegates to the inner ReviewModel; returns nil before findings have loaded.
func (*LoaderModel) Quarantined ¶
func (m *LoaderModel) Quarantined() []review.Quarantined
Quarantined returns the validator-rejected findings (or nil before load completes).
func (*LoaderModel) ReviewModel ¶
func (m *LoaderModel) ReviewModel() *Model
ReviewModel returns the inner ReviewModel once findings have loaded, or nil before LoadReadyMsg arrives. Used by the app-layer test seam to drive the existing test fakes against the inner model without exposing the loader's transition wiring to tests.
func (*LoaderModel) TotalReviewed ¶
func (m *LoaderModel) TotalReviewed() int
TotalReviewed is the number of valid findings handed to the inner ReviewModel (i.e., what the user saw in the TUI), used by writeFindings to disambiguate "model returned nothing" vs "user approved nothing".
func (*LoaderModel) Update ¶
Update routes messages either to the loader (during the wait) or to the inner ReviewModel (after findings have arrived). The transition is one-way: once a LoadReadyMsg arrives we hand off and never look back.
func (*LoaderModel) View ¶
func (m *LoaderModel) View() string
View renders the loading state or delegates to the inner ReviewModel.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the Bubble Tea model representing the TUI state and findings.
markedForPost is a TUI-local intent set kept out of review.Finding so the validated finding contract stays unchanged. Approval (State) and post-intent are orthogonal: the user can approve without posting (for the M5a clipboard workflow), post without approving, or both.
editMode + editor implement F9's "edit the suggested comment" contract (diffsmith-axv). When editMode is true the textarea owns key input; the normal-mode key bindings resume on exit.
func (*Model) ApproveCurrent ¶
func (m *Model) ApproveCurrent()
ApproveCurrent marks the currently selected finding as approved.
func (*Model) ApprovedCount ¶
ApprovedCount returns the number of approved findings.
func (*Model) CurrentFinding ¶
CurrentFinding returns the currently selected finding, or nil if none.
func (*Model) DismissCurrent ¶
func (m *Model) DismissCurrent()
DismissCurrent marks the currently selected finding as dismissed and drops it from the post-bound set. Without the second step a sequence like a→p→d→a would silently resurrect the post mark on re-approve (markedForPost[i] was never cleared), bypassing the rule that only an explicit 'p' on an approved finding enqueues it for posting.
func (*Model) DismissedCount ¶
DismissedCount returns the number of dismissed findings.
func (*Model) EditCurrentComment ¶
EditCurrentComment updates the suggested comment of the currently selected finding.
func (*Model) EditCurrentEvidence ¶
EditCurrentEvidence updates the evidence of the currently selected finding.
func (*Model) EditCurrentFixHint ¶
EditCurrentFixHint updates the fix hint of the currently selected finding.
func (*Model) EditCurrentTitle ¶
EditCurrentTitle updates the title of the currently selected finding.
func (*Model) EditMode ¶
EditMode reports whether the model is currently in edit mode. Tests and the View consult this to gate behavior.
func (*Model) GetApprovedFindings ¶
GetApprovedFindings returns a slice of all approved findings in order.
func (*Model) GetFindingsMarkedForPost ¶
GetFindingsMarkedForPost returns findings the user explicitly intends to post upstream, in the original order they appeared in the model. Only currently-approved findings are returned — a finding that was approved, marked, then later dismissed is filtered out so the dismiss always wins. Callers (the confirmation prompt count, the upstream submitter) can rely on this as a single source of truth.
func (*Model) IsPostBoundRow ¶ added in v0.1.6
IsPostBoundRow reports whether the finding at index i is currently in the post-bound set. View renderers consult this to draw the '[post]' badge; it must match the semantics of GetFindingsMarkedForPost so the badge can never claim a finding is queued for posting that the filter will silently drop.
func (*Model) MarkCurrentForPost ¶
func (m *Model) MarkCurrentForPost()
MarkCurrentForPost flags the currently selected finding for upstream posting. Only approved findings are eligible: pressing 'p' on a Pending or Dismissed finding leaves the marked set untouched and sets a transient status explaining what to do. 'a' remains the only path to approval — this keeps the trust boundary explicit so a user can never post a finding they have not first approved.
func (*Model) MoveDown ¶
func (m *Model) MoveDown()
MoveDown moves the selection down (towards the last finding).
func (*Model) MoveUp ¶
func (m *Model) MoveUp()
MoveUp moves the selection up (towards the first finding).
func (*Model) TransientStatus ¶
TransientStatus returns the current ephemeral status message, or "" if none. The View consults this to render a transient line in the footer; tests assert against it to verify user-visible feedback without rendering the full TUI.
type ModelPickerItem ¶
type ModelPickerItem struct {
Name string
Available bool
// contains filtered or unexported fields
}
ModelPickerItem represents one row in the picker.
type ModelPickerModel ¶
type ModelPickerModel struct {
// contains filtered or unexported fields
}
ModelPickerModel is the multi-select Bubble Tea screen shown at startup. After Update sees a terminal key, Confirmed() or Cancelled() returns true; the app layer reads SelectedNames() to build the SelectedModels for the session.
func NewModelPickerModel ¶
func NewModelPickerModel(items []ModelPickerItem) *ModelPickerModel
NewModelPickerModel constructs a picker with default checks applied: every known available model (the keys of pickerPriority) is pre-checked. If codex is unavailable, the highest-priority available model is pre-checked alone as a fallback.
func (*ModelPickerModel) Cancelled ¶
func (m *ModelPickerModel) Cancelled() bool
Cancelled returns true if the user pressed q / ctrl+c.
func (*ModelPickerModel) Confirmed ¶
func (m *ModelPickerModel) Confirmed() bool
Confirmed returns true if the user pressed enter.
func (*ModelPickerModel) Init ¶
func (m *ModelPickerModel) Init() tea.Cmd
func (*ModelPickerModel) IsChecked ¶
func (m *ModelPickerModel) IsChecked(name string) bool
IsChecked reports whether the given name is currently checked.
func (*ModelPickerModel) SelectedNames ¶
func (m *ModelPickerModel) SelectedNames() []string
SelectedNames returns the names of currently-checked items, in priority order (codex > claude > antigravity > unknown names after). Both the ordering and the known-name set derive from pickerPriority, the single source of truth in this file — no hand-maintained name lists.
func (*ModelPickerModel) View ¶
func (m *ModelPickerModel) View() string
type ModelStatusMsg ¶
type ModelStatusMsg struct {
Name string
State string // "queued" | "running" | "done" | "failed"
Err error // populated when State == "failed"
}
ModelStatusMsg reports a state transition for a single model in the multi-model review fan-out. Loader uses these to render per- model rows.