tui

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package tui implements PureLink's interactive Bubble Tea UI for batch results. It is intentionally a self-contained component: callers feed it a snapshot of engine results and the TUI handles navigation, filtering, sorting, detail rendering, and graceful quit. No raw v2rayN secrets, share links, or credentials are accepted by this package; only the public engine.BatchItem fields are displayed.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoTTY = errors.New("tui: no terminal attached; falling back to static output")

ErrNoTTY is returned by Run when the program detects it is not connected to a terminal capable of supporting the TUI. Callers should fall back to static output.

Functions

func IsEmptySnapshot

func IsEmptySnapshot(err error) bool

IsEmptySnapshot reports whether the supplied error matches the package's empty-snapshot sentinel. Callers can use this to fall back to static rendering instead of failing hard.

Types

type BatchCompleteMsg

type BatchCompleteMsg struct {
	Summary engine.BatchSummary
}

BatchCompleteMsg signals that the streaming batch finished and a final summary is available. Static callers can ignore this type.

type BatchModel

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

BatchModel is the top-level Bubble Tea model for `purelink batch -i`. It is intentionally driven by a snapshot rather than a live engine to keep the package self-contained and testable without spawning real workers.

func NewBatchModel

func NewBatchModel(snap Snapshot, opts Options) BatchModel

NewBatchModel constructs a model from a snapshot. The model is fully usable in tests without ever rendering to a terminal.

func Run

func Run(ctx context.Context, opts RunOptions) (BatchModel, error)

Run launches the interactive TUI for a completed batch run. The function blocks until the user quits or an error is returned. The returned model is the final BatchModel state, which callers can inspect for selections or metrics.

func (BatchModel) Cursor

func (m BatchModel) Cursor() int

Cursor returns the current cursor index into the visible slice.

func (*BatchModel) CycleFilter

func (m *BatchModel) CycleFilter()

CycleFilter advances the filter band to the next key in the cycle.

func (*BatchModel) CycleSort

func (m *BatchModel) CycleSort()

CycleSort advances the sort column to the next key in the cycle.

func (BatchModel) FilterKey

func (m BatchModel) FilterKey() FilterKey

FilterKey returns the active filter band.

func (BatchModel) Init

func (m BatchModel) Init() tea.Cmd

Init satisfies tea.Model. The TUI starts the spinner so streaming callers see motion while results stream in. Static callers see the spinner stop on the first BatchCompleteMsg.

func (BatchModel) Mode

func (m BatchModel) Mode() Mode

Mode returns the current input mode.

func (*BatchModel) MoveCursor

func (m *BatchModel) MoveCursor(delta int)

MoveCursor adjusts the cursor by delta, clamped to [0, len(visible)-1].

func (BatchModel) Quitting

func (m BatchModel) Quitting() bool

Quitting reports whether the model has signalled exit.

func (BatchModel) Search

func (m BatchModel) Search() string

Search returns the current free-text search string applied on top of the filter band.

func (BatchModel) Selected

func (m BatchModel) Selected() (engine.BatchItem, bool)

Selected returns the currently highlighted item, if any.

func (*BatchModel) SetSearch

func (m *BatchModel) SetSearch(s string)

SetSearch sets the free-text search string and recomputes the visible set.

func (*BatchModel) SetSize

func (m *BatchModel) SetSize(w, h int)

SetSize updates the render dimensions and propagates to sub-components. Negative values are treated as zero. The caller is expected to invoke this from a tea.WindowSizeMsg.

func (BatchModel) SnapshotData

func (m BatchModel) SnapshotData() Snapshot

Snapshot returns the immutable snapshot the model was constructed with.

func (BatchModel) SortKey

func (m BatchModel) SortKey() SortKey

SortKey returns the active sort column.

func (BatchModel) Update

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

Update implements the Bubble Tea reducer.

func (BatchModel) View

func (m BatchModel) View() string

View renders the multi-panel layout described in 07-wireframes.md §9.

func (BatchModel) Visible

func (m BatchModel) Visible() []engine.BatchItem

Visible returns the currently filtered+sorted slice. It is exported for tests so they can assert the result of filter/sort operations without rendering.

type CheckResultMsg

type CheckResultMsg struct {
	Endpoint endpoint.Endpoint
	Item     engine.BatchItem
}

CheckResultMsg is dispatched when a single batch item finishes. Streaming callers (future Phase 4 wiring) can deliver these as the engine produces them; the static integration path simply seeds the model with a fully populated BatchResult and never sends this message.

type ErrorMsg

type ErrorMsg struct {
	Err error
}

ErrorMsg surfaces a non-fatal error to the TUI for display.

type FilterKey

type FilterKey int

FilterKey identifies the active filter band shown above the table.

const (
	FilterAll FilterKey = iota
	FilterReachable
	FilterUnreachable
	FilterAbusive
	FilterSuspicious
	FilterClean
	FilterErrors
)

func (FilterKey) String

func (f FilterKey) String() string

String returns the lower-case label that matches engine.FilterItems.

type LogHandler

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

LogHandler is a slog.Handler that buffers records in memory while the TUI owns the terminal. Direct stderr writes corrupt the Bubble Tea frame; the CLI wires this handler in interactive mode and optionally flushes the buffered records to a log file on exit (see 15-logging-observability.md).

func NewLogHandler

func NewLogHandler(level slog.Level) *LogHandler

NewLogHandler returns a buffering handler that emits records at level or higher.

func (*LogHandler) Enabled

func (h *LogHandler) Enabled(_ context.Context, level slog.Level) bool

Enabled reports whether the handler accepts records at the given level.

func (*LogHandler) Handle

func (h *LogHandler) Handle(_ context.Context, r slog.Record) error

Handle stores the record. The slog.Record is intentionally a value copy: Clone is used to prevent aliasing back to the caller's attribute pointers.

func (*LogHandler) Records

func (h *LogHandler) Records() []slog.Record

Records returns a snapshot of the buffered records. The slice is safe to iterate without holding the handler lock.

func (*LogHandler) Reset

func (h *LogHandler) Reset()

Reset clears the buffer. Useful for tests and for flushing after the records are written to a log file sink.

func (*LogHandler) WithAttrs

func (h *LogHandler) WithAttrs(_ []slog.Attr) slog.Handler

WithAttrs returns the same handler. Per slog spec we should return a new handler bound to the supplied attrs; in this MVP the buffer is shared because UI consumers do not chain attrs.

func (*LogHandler) WithGroup

func (h *LogHandler) WithGroup(_ string) slog.Handler

WithGroup returns the same handler for the same reason as WithAttrs.

type Mode

type Mode int

Mode represents the current focus of the BatchModel.

const (
	// ModeList is the default mode: navigate the result table.
	ModeList Mode = iota
	// ModeFilter is active while the user types into the filter box.
	ModeFilter
	// ModeDetail shows the full provider/diagnostic detail for the cursor.
	ModeDetail
)

type Options

type Options struct {
	NoColor bool
	// Width is the initial render width; if 0 the model adapts on the first
	// tea.WindowSizeMsg. A reasonable terminal default is used for tests.
	Width int
	// Height is the initial render height with the same semantics as Width.
	Height int
}

Options configures BatchModel rendering. NoColor and Width default to safe values when unset.

type RunOptions

type RunOptions struct {
	// Snapshot is the data the model renders. Required.
	Snapshot Snapshot
	// NoColor disables coloured output (matches the global --no-color flag).
	NoColor bool
	// Output overrides the destination Bubble Tea writes to. Defaults to
	// os.Stdout when nil. Tests pass io.Discard for non-terminal verification.
	Output io.Writer
	// Input overrides the input source. Defaults to os.Stdin.
	Input *os.File
	// Headless skips opening the alt screen and starting the program loop.
	// Used by tests to verify model construction without a TTY.
	Headless bool
	// AllowEmpty permits launching the TUI without batch results. The default
	// batch integration leaves this false so empty batch inputs still fail fast.
	AllowEmpty bool
}

RunOptions configures Run. It is intentionally minimal so cmd/purelink can adopt the TUI with a one-line call once integration is wired.

type Snapshot

type Snapshot struct {
	Items   []engine.BatchItem
	Summary engine.BatchSummary
	Source  string // optional batch source label, e.g. "endpoints.txt"
}

Snapshot captures the data the TUI needs from a completed (or partial) batch run. It is designed to be assembled by the caller from the existing engine.BatchResult so cmd/purelink does not need to know any TUI internals.

type SortKey

type SortKey int

SortKey identifies a column to sort by. The cycle order matches the help bar shown to the user.

const (
	SortAbuse SortKey = iota
	SortLatency
	SortHost
	SortPort
	SortPurity
)

func (SortKey) String

func (k SortKey) String() string

String returns the lower-case label used in headers and key hints.

type Theme

type Theme struct {
	NoColor bool

	Title    lipgloss.Style
	Subtitle lipgloss.Style

	Header   lipgloss.Style
	Cell     lipgloss.Style
	Selected lipgloss.Style

	Good lipgloss.Style
	Warn lipgloss.Style
	Bad  lipgloss.Style
	Mute lipgloss.Style

	Help lipgloss.Style

	Border        lipgloss.Style
	FocusedBorder lipgloss.Style

	Filter   lipgloss.Style
	Detail   lipgloss.Style
	StatusOK lipgloss.Style
	Spinner  lipgloss.Style
}

Theme bundles every Lip Gloss style the TUI uses. Two themes are supported: the default colored theme, and a no-color theme that maps every style to a no-op (matching --no-color behaviour required by the architecture).

func DefaultTheme

func DefaultTheme() Theme

DefaultTheme returns the colored Lip Gloss theme used in interactive mode. All foreground colors meet WCAG AA against the standard dark terminal backgrounds shipped by GNOME, Windows Terminal, iTerm2, and Alacritty.

func NoColorTheme

func NoColorTheme() Theme

NoColorTheme returns a theme where every style is a passthrough. It is applied when the user passes --no-color or when the program is connected to a non-terminal sink.

func (Theme) AbuseStyle

func (t Theme) AbuseStyle(score int) lipgloss.Style

AbuseStyle returns the style associated with an abuse score band.

func (Theme) PurityStyle

func (t Theme) PurityStyle(purity string) lipgloss.Style

PurityStyle returns the style associated with a purity verdict, falling back to the muted style for unknown or empty verdicts.

Jump to

Keyboard shortcuts

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