From 477f76c6286e0ab0ceb01c6e413eedf4fc864efa Mon Sep 17 00:00:00 2001 From: "Luis Gustavo S. Barreto" Date: Thu, 12 Jun 2025 22:32:11 -0300 Subject: [PATCH] feat(tea): add provisional support for customizing tea runtime options Add `gumtea.Options` struct and `gumtea.NewProgram` wrapper to configure `tea.ProgramOptions` such as `WithFPS` and `WithAltScreen`. This enables tuning behavior across all tea-based gum commands. This change preserves defaults and is opt-in. Non-tea commands remain unaffected. Note: This is provisional and may be removed or replaced in future. Signed-off-by: Luis Gustavo S. Barreto --- choose/command.go | 3 ++- confirm/command.go | 3 ++- file/command.go | 3 ++- filter/command.go | 3 ++- input/command.go | 3 ++- internal/gumtea/gumtea.go | 35 +++++++++++++++++++++++++++++++++++ pager/command.go | 3 ++- spin/command.go | 3 ++- table/command.go | 3 ++- write/command.go | 3 ++- 10 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 internal/gumtea/gumtea.go diff --git a/choose/command.go b/choose/command.go index 8821258..4405dd7 100644 --- a/choose/command.go +++ b/choose/command.go @@ -11,6 +11,7 @@ import ( "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/paginator" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" "github.com/charmbracelet/gum/internal/tty" @@ -150,7 +151,7 @@ func (o Options) Run() error { defer cancel() // Disable Keybindings since we will control it ourselves. - tm, err := tea.NewProgram( + tm, err := gumtea.NewProgram( m, tea.WithOutput(os.Stderr), tea.WithContext(ctx), diff --git a/confirm/command.go b/confirm/command.go index e1f30bc..cde6725 100644 --- a/confirm/command.go +++ b/confirm/command.go @@ -8,6 +8,7 @@ import ( "github.com/charmbracelet/bubbles/help" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/gum/internal/exit" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" ) @@ -42,7 +43,7 @@ func (o Options) Run() error { unselectedStyle: o.UnselectedStyle.ToLipgloss(), promptStyle: o.PromptStyle.ToLipgloss(), } - tm, err := tea.NewProgram( + tm, err := gumtea.NewProgram( m, tea.WithOutput(os.Stderr), tea.WithContext(ctx), diff --git a/file/command.go b/file/command.go index 09b53c1..5fdcc00 100644 --- a/file/command.go +++ b/file/command.go @@ -9,6 +9,7 @@ import ( "github.com/charmbracelet/bubbles/filepicker" "github.com/charmbracelet/bubbles/help" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/timeout" ) @@ -58,7 +59,7 @@ func (o Options) Run() error { ctx, cancel := timeout.Context(o.Timeout) defer cancel() - tm, err := tea.NewProgram( + tm, err := gumtea.NewProgram( &m, tea.WithOutput(os.Stderr), tea.WithContext(ctx), diff --git a/filter/command.go b/filter/command.go index 4185100..0216fe2 100644 --- a/filter/command.go +++ b/filter/command.go @@ -12,6 +12,7 @@ import ( "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/gum/internal/files" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" "github.com/charmbracelet/gum/internal/tty" @@ -141,7 +142,7 @@ func (o Options) Run() error { } } - tm, err := tea.NewProgram(m, options...).Run() + tm, err := gumtea.NewProgram(m, options...).Run() if err != nil { return fmt.Errorf("unable to run filter: %w", err) } diff --git a/input/command.go b/input/command.go index 7d96e72..677d822 100644 --- a/input/command.go +++ b/input/command.go @@ -9,6 +9,7 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/gum/cursor" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" ) @@ -56,7 +57,7 @@ func (o Options) Run() error { ctx, cancel := timeout.Context(o.Timeout) defer cancel() - p := tea.NewProgram( + p := gumtea.NewProgram( m, tea.WithOutput(os.Stderr), tea.WithReportFocus(), diff --git a/internal/gumtea/gumtea.go b/internal/gumtea/gumtea.go new file mode 100644 index 0000000..501888d --- /dev/null +++ b/internal/gumtea/gumtea.go @@ -0,0 +1,35 @@ +// Package gumtea wraps tea.NewProgram to allow custom options. +package gumtea + +import ( + "os" + "strconv" + + tea "github.com/charmbracelet/bubbletea" +) + +// NewProgram wraps tea.NewProgram, injecting options from the environment. +func NewProgram(model tea.Model, baseOpts ...tea.ProgramOption) *tea.Program { + opts := append(baseOpts, loadOptionsFromEnv()...) + return tea.NewProgram(model, opts...) +} + +// loadOptionsFromEnv loads options from environment variables. +// This feature is provisional. It may be altered or removed in a future version of this package. +func loadOptionsFromEnv() []tea.ProgramOption { + var opts []tea.ProgramOption + + if fps := os.Getenv("GUM_FPS"); fps != "" { + if v, err := strconv.Atoi(fps); err == nil && v > 0 { + opts = append(opts, tea.WithFPS(v)) + } + } + + if alt := os.Getenv("GUM_ALTSCREEN"); alt != "" { + if altEnabled, err := strconv.ParseBool(alt); err == nil && altEnabled { + opts = append(opts, tea.WithAltScreen()) + } + } + + return opts +} diff --git a/pager/command.go b/pager/command.go index 414bee7..b90ab3c 100644 --- a/pager/command.go +++ b/pager/command.go @@ -7,6 +7,7 @@ import ( "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" ) @@ -47,7 +48,7 @@ func (o Options) Run() error { ctx, cancel := timeout.Context(o.Timeout) defer cancel() - _, err := tea.NewProgram( + _, err := gumtea.NewProgram( m, tea.WithAltScreen(), tea.WithReportFocus(), diff --git a/spin/command.go b/spin/command.go index 08cb3bd..23653c8 100644 --- a/spin/command.go +++ b/spin/command.go @@ -7,6 +7,7 @@ import ( "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/gum/internal/exit" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/timeout" "github.com/charmbracelet/x/term" ) @@ -34,7 +35,7 @@ func (o Options) Run() error { ctx, cancel := timeout.Context(o.Timeout) defer cancel() - tm, err := tea.NewProgram( + tm, err := gumtea.NewProgram( m, tea.WithOutput(os.Stderr), tea.WithContext(ctx), diff --git a/table/command.go b/table/command.go index 4ee0fb9..ba2ff46 100644 --- a/table/command.go +++ b/table/command.go @@ -8,6 +8,7 @@ import ( "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" "github.com/charmbracelet/gum/style" @@ -148,7 +149,7 @@ func (o Options) Run() error { help: help.New(), keymap: defaultKeymap(), } - tm, err := tea.NewProgram( + tm, err := gumtea.NewProgram( m, tea.WithOutput(os.Stderr), tea.WithContext(ctx), diff --git a/write/command.go b/write/command.go index adc3c69..5f16351 100644 --- a/write/command.go +++ b/write/command.go @@ -10,6 +10,7 @@ import ( "github.com/charmbracelet/bubbles/textarea" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/gum/cursor" + "github.com/charmbracelet/gum/internal/gumtea" "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/gum/internal/timeout" ) @@ -65,7 +66,7 @@ func (o Options) Run() error { ctx, cancel := timeout.Context(o.Timeout) defer cancel() - p := tea.NewProgram( + p := gumtea.NewProgram( m, tea.WithOutput(os.Stderr), tea.WithReportFocus(),