main
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}