main
Raw Download raw file
  1package tea
  2
  3import (
  4	"context"
  5	"io"
  6	"sync/atomic"
  7)
  8
  9// ProgramOption is used to set options when initializing a Program. Program can
 10// accept a variable number of options.
 11//
 12// Example usage:
 13//
 14//	p := NewProgram(model, WithInput(someInput), WithOutput(someOutput))
 15type ProgramOption func(*Program)
 16
 17// WithContext lets you specify a context in which to run the Program. This is
 18// useful if you want to cancel the execution from outside. When a Program gets
 19// cancelled it will exit with an error ErrProgramKilled.
 20func WithContext(ctx context.Context) ProgramOption {
 21	return func(p *Program) {
 22		p.ctx = ctx
 23	}
 24}
 25
 26// WithOutput sets the output which, by default, is stdout. In most cases you
 27// won't need to use this.
 28func WithOutput(output io.Writer) ProgramOption {
 29	return func(p *Program) {
 30		p.output = output
 31	}
 32}
 33
 34// WithInput sets the input which, by default, is stdin. In most cases you
 35// won't need to use this. To disable input entirely pass nil.
 36//
 37//	p := NewProgram(model, WithInput(nil))
 38func WithInput(input io.Reader) ProgramOption {
 39	return func(p *Program) {
 40		p.input = input
 41		p.inputType = customInput
 42	}
 43}
 44
 45// WithInputTTY opens a new TTY for input (or console input device on Windows).
 46func WithInputTTY() ProgramOption {
 47	return func(p *Program) {
 48		p.inputType = ttyInput
 49	}
 50}
 51
 52// WithEnvironment sets the environment variables that the program will use.
 53// This useful when the program is running in a remote session (e.g. SSH) and
 54// you want to pass the environment variables from the remote session to the
 55// program.
 56//
 57// Example:
 58//
 59//	var sess ssh.Session // ssh.Session is a type from the github.com/charmbracelet/ssh package
 60//	pty, _, _ := sess.Pty()
 61//	environ := append(sess.Environ(), "TERM="+pty.Term)
 62//	p := tea.NewProgram(model, tea.WithEnvironment(environ)
 63func WithEnvironment(env []string) ProgramOption {
 64	return func(p *Program) {
 65		p.environ = env
 66	}
 67}
 68
 69// WithoutSignalHandler disables the signal handler that Bubble Tea sets up for
 70// Programs. This is useful if you want to handle signals yourself.
 71func WithoutSignalHandler() ProgramOption {
 72	return func(p *Program) {
 73		p.startupOptions |= withoutSignalHandler
 74	}
 75}
 76
 77// WithoutCatchPanics disables the panic catching that Bubble Tea does by
 78// default. If panic catching is disabled the terminal will be in a fairly
 79// unusable state after a panic because Bubble Tea will not perform its usual
 80// cleanup on exit.
 81func WithoutCatchPanics() ProgramOption {
 82	return func(p *Program) {
 83		p.startupOptions |= withoutCatchPanics
 84	}
 85}
 86
 87// WithoutSignals will ignore OS signals.
 88// This is mainly useful for testing.
 89func WithoutSignals() ProgramOption {
 90	return func(p *Program) {
 91		atomic.StoreUint32(&p.ignoreSignals, 1)
 92	}
 93}
 94
 95// WithAltScreen starts the program with the alternate screen buffer enabled
 96// (i.e. the program starts in full window mode). Note that the altscreen will
 97// be automatically exited when the program quits.
 98//
 99// Example:
100//
101//	p := tea.NewProgram(Model{}, tea.WithAltScreen())
102//	if _, err := p.Run(); err != nil {
103//	    fmt.Println("Error running program:", err)
104//	    os.Exit(1)
105//	}
106//
107// To enter the altscreen once the program has already started running use the
108// EnterAltScreen command.
109func WithAltScreen() ProgramOption {
110	return func(p *Program) {
111		p.startupOptions |= withAltScreen
112	}
113}
114
115// WithoutBracketedPaste starts the program with bracketed paste disabled.
116func WithoutBracketedPaste() ProgramOption {
117	return func(p *Program) {
118		p.startupOptions |= withoutBracketedPaste
119	}
120}
121
122// WithMouseCellMotion starts the program with the mouse enabled in "cell
123// motion" mode.
124//
125// Cell motion mode enables mouse click, release, and wheel events. Mouse
126// movement events are also captured if a mouse button is pressed (i.e., drag
127// events). Cell motion mode is better supported than all motion mode.
128//
129// This will try to enable the mouse in extended mode (SGR), if that is not
130// supported by the terminal it will fall back to normal mode (X10).
131//
132// To enable mouse cell motion once the program has already started running use
133// the EnableMouseCellMotion command. To disable the mouse when the program is
134// running use the DisableMouse command.
135//
136// The mouse will be automatically disabled when the program exits.
137func WithMouseCellMotion() ProgramOption {
138	return func(p *Program) {
139		p.startupOptions |= withMouseCellMotion // set
140		p.startupOptions &^= withMouseAllMotion // clear
141	}
142}
143
144// WithMouseAllMotion starts the program with the mouse enabled in "all motion"
145// mode.
146//
147// EnableMouseAllMotion is a special command that enables mouse click, release,
148// wheel, and motion events, which are delivered regardless of whether a mouse
149// button is pressed, effectively enabling support for hover interactions.
150//
151// This will try to enable the mouse in extended mode (SGR), if that is not
152// supported by the terminal it will fall back to normal mode (X10).
153//
154// Many modern terminals support this, but not all. If in doubt, use
155// EnableMouseCellMotion instead.
156//
157// To enable the mouse once the program has already started running use the
158// EnableMouseAllMotion command. To disable the mouse when the program is
159// running use the DisableMouse command.
160//
161// The mouse will be automatically disabled when the program exits.
162func WithMouseAllMotion() ProgramOption {
163	return func(p *Program) {
164		p.startupOptions |= withMouseAllMotion   // set
165		p.startupOptions &^= withMouseCellMotion // clear
166	}
167}
168
169// WithoutRenderer disables the renderer. When this is set output and log
170// statements will be plainly sent to stdout (or another output if one is set)
171// without any rendering and redrawing logic. In other words, printing and
172// logging will behave the same way it would in a non-TUI commandline tool.
173// This can be useful if you want to use the Bubble Tea framework for a non-TUI
174// application, or to provide an additional non-TUI mode to your Bubble Tea
175// programs. For example, your program could behave like a daemon if output is
176// not a TTY.
177func WithoutRenderer() ProgramOption {
178	return func(p *Program) {
179		p.renderer = &nilRenderer{}
180	}
181}
182
183// WithANSICompressor removes redundant ANSI sequences to produce potentially
184// smaller output, at the cost of some processing overhead.
185//
186// This feature is provisional, and may be changed or removed in a future version
187// of this package.
188//
189// Deprecated: this incurs a noticeable performance hit. A future release will
190// optimize ANSI automatically without the performance penalty.
191func WithANSICompressor() ProgramOption {
192	return func(p *Program) {
193		p.startupOptions |= withANSICompressor
194	}
195}
196
197// WithFilter supplies an event filter that will be invoked before Bubble Tea
198// processes a tea.Msg. The event filter can return any tea.Msg which will then
199// get handled by Bubble Tea instead of the original event. If the event filter
200// returns nil, the event will be ignored and Bubble Tea will not process it.
201//
202// As an example, this could be used to prevent a program from shutting down if
203// there are unsaved changes.
204//
205// Example:
206//
207//	func filter(m tea.Model, msg tea.Msg) tea.Msg {
208//		if _, ok := msg.(tea.QuitMsg); !ok {
209//			return msg
210//		}
211//
212//		model := m.(myModel)
213//		if model.hasChanges {
214//			return nil
215//		}
216//
217//		return msg
218//	}
219//
220//	p := tea.NewProgram(Model{}, tea.WithFilter(filter));
221//
222//	if _,err := p.Run(); err != nil {
223//		fmt.Println("Error running program:", err)
224//		os.Exit(1)
225//	}
226func WithFilter(filter func(Model, Msg) Msg) ProgramOption {
227	return func(p *Program) {
228		p.filter = filter
229	}
230}
231
232// WithFPS sets a custom maximum FPS at which the renderer should run. If
233// less than 1, the default value of 60 will be used. If over 120, the FPS
234// will be capped at 120.
235func WithFPS(fps int) ProgramOption {
236	return func(p *Program) {
237		p.fps = fps
238	}
239}
240
241// WithReportFocus enables reporting when the terminal gains and loses
242// focus. When this is enabled [FocusMsg] and [BlurMsg] messages will be sent
243// to your Update method.
244//
245// Note that while most terminals and multiplexers support focus reporting,
246// some do not. Also note that tmux needs to be configured to report focus
247// events.
248func WithReportFocus() ProgramOption {
249	return func(p *Program) {
250		p.startupOptions |= withReportFocus
251	}
252}