tui

package
v0.0.0-...-55af0c3 Latest Latest
Warning

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

Go to latest
Published: Mar 3, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package tui provides a bubbletea-based interactive TUI for proto-cli. It implements the protocli.TUIProvider interface, allowing users to browse and invoke gRPC methods through a terminal UI.

Usage:

app, err := protocli.RootCommand("myapp",
    protocli.Service(svc),
    protocli.WithInteractive(tui.New()),
)

Theming

The quickest way to retheme the TUI is WithTheme, which accepts a Theme value controlling colors, spacing tokens, border shapes, and optional custom styles. All lipgloss styles are derived automatically:

tui.New(tui.WithTheme(bubbles.Theme{
    Colors: bubbles.ThemeColors{
        Primary:   lipgloss.Color("205"),
        Secondary: lipgloss.Color("241"),
        Accent:    lipgloss.Color("213"),
        Error:     lipgloss.Color("196"),
        Success:   lipgloss.Color("2"),
        Border:    lipgloss.Color("238"),
    },
}))

Spacing and border shapes can also be customised through the theme:

theme := bubbles.DefaultTheme()
theme.Spacing.SM = 3                             // wider tab padding
theme.Border.Control = lipgloss.NormalBorder()   // square control borders
tui.New(tui.WithTheme(theme))

Register custom styles in Theme.Custom and retrieve them in your own bubbles via Styles.Get:

theme := bubbles.DefaultTheme()
theme.Custom = map[string]lipgloss.Style{
    "badge": lipgloss.NewStyle().Bold(true).Background(lipgloss.Color("57")),
}
tui.New(tui.WithTheme(theme))

// Inside a custom FormControl or ResponseView:
badge := styles.Get("badge").Render("NEW")

For fine-grained per-field adjustments on top of a theme, use WithStyleOverride:

tui.New(
    tui.WithTheme(myTheme),
    tui.WithStyleOverride(func(s *bubbles.Styles) {
        s.FocusedControl = s.FocusedControl.MaxWidth(80)
    }),
)

For complete control, replace the full style set with WithStyles:

s := bubbles.DefaultStyles()
s.Title = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
tui.New(tui.WithStyles(s))

Custom response views

Register a ResponseViewFactory via WithResponseView to replace the default JSON viewport with any bubbletea sub-model:

tui.New(tui.WithResponseView(bubbles.NewTableResponseView()))

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NavigateToForm(serviceName, methodName string, fieldValues map[string]string) tea.Cmd

NavigateToForm returns a tea.Cmd that navigates the TUI to the named service/method form, pre-filling any fields specified in fieldValues. Use it from a bubbles.CardSelectHandler to jump context after a card selection:

bubbles.WithOnSelect(func(ctx context.Context, msg proto.Message) bubbles.CardSelectResult {
    person := msg.(*pb.PersonCard)
    return bubbles.CardSelectCmd(tui.NavigateToForm("greeter", "greet", map[string]string{
        "name": person.Name,
    }))
})

func New

func New(opts ...Option) protocli.TUIProvider

New creates a new TUI provider. Default styles are applied before any options.

func ShowModal

func ShowModal(title, content string) tea.Cmd

ShowModal returns a tea.Cmd that triggers a modal overlay with the given title and content. Pass it as the return value of a bubbles.CardSelectHandler.

Types

type NavigateToFormMsg struct {
	// ServiceName is the TUI name of the target service (e.g. "greeter").
	ServiceName string
	// MethodName is the TUI name of the target method (e.g. "greet").
	MethodName string
	// FieldValues pre-populates specific form fields keyed by field flag-name.
	// Values override the proto-defined default for the matching field.
	FieldValues map[string]string
}

NavigateToFormMsg instructs the root model to navigate to a specific method's form screen on a given service, optionally pre-populating named fields. Return it from a CardSelectHandler via CardSelectCmd to jump the user to a form after selecting a card — for example, to pre-fill a recipient name.

type Option

type Option func(*provider)

Option configures the TUI provider.

func WithCustomControl

func WithCustomControl(messageFullName string, factory bubbles.ControlFactory) Option

WithCustomControl registers a custom FormControl factory for a given proto message full name (e.g. "google.protobuf.Timestamp" or "mypackage.MyType"). The factory is called in newFormModel when a TUIFieldKindMessage field with a matching MessageFullName is encountered.

func WithCustomControlForField

func WithCustomControlForField(fieldName string, factory bubbles.ControlFactory) Option

WithCustomControlForField registers a custom FormControl factory for a specific field identified by its flag name (e.g. "metadata", "when"). This works for any field kind — use it when you want to override a scalar, repeated, or message field's default control for a specific field. Name-based registrations take priority over type-based registrations (WithCustomControl / WithTimestampControl), so you can use this to give a particular field different behaviour from the global type-based default.

func WithOptionalTimestampControl

func WithOptionalTimestampControl(opts ...bubbles.DateTimeControlOption) Option

WithOptionalTimestampControl is identical to WithTimestampControl but prepends WithOptionalDefault so the picker starts empty (Value returns "") rather than pre-filled with the current time. Submitting the form without touching the field leaves the timestamp unset — useful for optional filter fields such as "after" and "before" on a list-events request.

func WithResponseView

func WithResponseView(factory bubbles.ResponseViewFactory) Option

WithResponseView registers a factory that creates a custom ResponseView for displaying RPC responses. The default implementation marshals the proto to indented JSON and presents it in a scrollable viewport.

func WithStyleOverride

func WithStyleOverride(fn func(*bubbles.Styles)) Option

WithStyleOverride applies a modifier function to the current style set in place. Use this to adjust individual styles after WithPalette (or without replacing the entire set via WithStyles). Options are applied in order, so WithPalette followed by WithStyleOverride works as expected.

func WithStyles

func WithStyles(styles bubbles.Styles) Option

WithStyles replaces the provider's full style set. Obtain the defaults via bubbles.DefaultStyles, modify the fields you care about, then pass the result here.

func WithTheme

func WithTheme(theme bubbles.Theme) Option

WithTheme rebuilds the full style set from the given theme. The theme controls colors, spacing tokens, border shapes, and any custom styles forwarded to Styles.Custom. Use WithStyleOverride afterwards to tweak any individual style that the theme does not capture.

func WithTimestampControl

func WithTimestampControl(opts ...bubbles.DateTimeControlOption) Option

WithTimestampControl registers an interactive date+time picker as the custom form control for google.protobuf.Timestamp fields. Use this instead of the default RFC3339 text input when you want a segment-by-segment picker UI.

Pass DateTimeControlOption values to configure timezone behaviour:

tui.WithTimestampControl(
    bubbles.WithInputTimezone(bubbles.UserProvidedTimezone),
    bubbles.WithTZNormalization(bubbles.RetainSourceTimezone),
)

WithOptionalTimestampControl is a variant that starts empty instead of defaulting to the current time. Prefer it for optional filter fields (e.g. "after", "before") where leaving the field blank should mean "no filter".

type ShowModalMsg

type ShowModalMsg struct {
	// Title is rendered at the top of the modal box. May be empty.
	Title string
	// Content is the body of the modal box.
	Content string
}

ShowModalMsg is a bubbletea message that instructs the root model to display a modal overlay on top of the current screen. Return it from a bubbles.CardSelectHandler to pop up a modal when a card is selected:

bubbles.WithOnSelect(func(msg proto.Message) tea.Cmd {
    return tui.ShowModal("Selected", renderContent(msg))
})

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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