| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package tea
- import (
- "context"
- "io"
- "github.com/muesli/termenv"
- )
- // ProgramOption is used to set options when initializing a Program. Program can
- // accept a variable number of options.
- //
- // Example usage:
- //
- // p := NewProgram(model, WithInput(someInput), WithOutput(someOutput))
- type ProgramOption func(*Program)
- // WithContext lets you specify a context in which to run the Program. This is
- // useful if you want to cancel the execution from outside. When a Program gets
- // cancelled it will exit with an error ErrProgramKilled.
- func WithContext(ctx context.Context) ProgramOption {
- return func(p *Program) {
- p.ctx = ctx
- }
- }
- // WithOutput sets the output which, by default, is stdout. In most cases you
- // won't need to use this.
- func WithOutput(output io.Writer) ProgramOption {
- return func(p *Program) {
- if o, ok := output.(*termenv.Output); ok {
- p.output = o
- } else {
- p.output = termenv.NewOutput(output, termenv.WithColorCache(true))
- }
- }
- }
- // WithInput sets the input which, by default, is stdin. In most cases you
- // won't need to use this. To disable input entirely pass nil.
- //
- // p := NewProgram(model, WithInput(nil))
- func WithInput(input io.Reader) ProgramOption {
- return func(p *Program) {
- p.input = input
- p.inputType = customInput
- }
- }
- // WithInputTTY opens a new TTY for input (or console input device on Windows).
- func WithInputTTY() ProgramOption {
- return func(p *Program) {
- p.inputType = ttyInput
- }
- }
- // WithoutSignalHandler disables the signal handler that Bubble Tea sets up for
- // Programs. This is useful if you want to handle signals yourself.
- func WithoutSignalHandler() ProgramOption {
- return func(p *Program) {
- p.startupOptions |= withoutSignalHandler
- }
- }
- // WithoutCatchPanics disables the panic catching that Bubble Tea does by
- // default. If panic catching is disabled the terminal will be in a fairly
- // unusable state after a panic because Bubble Tea will not perform its usual
- // cleanup on exit.
- func WithoutCatchPanics() ProgramOption {
- return func(p *Program) {
- p.startupOptions |= withoutCatchPanics
- }
- }
- // WithoutSignals will ignore OS signals.
- // This is mainly useful for testing.
- func WithoutSignals() ProgramOption {
- return func(p *Program) {
- p.ignoreSignals = true
- }
- }
- // WithAltScreen starts the program with the alternate screen buffer enabled
- // (i.e. the program starts in full window mode). Note that the altscreen will
- // be automatically exited when the program quits.
- //
- // Example:
- //
- // p := tea.NewProgram(Model{}, tea.WithAltScreen())
- // if _, err := p.Run(); err != nil {
- // fmt.Println("Error running program:", err)
- // os.Exit(1)
- // }
- //
- // To enter the altscreen once the program has already started running use the
- // EnterAltScreen command.
- func WithAltScreen() ProgramOption {
- return func(p *Program) {
- p.startupOptions |= withAltScreen
- }
- }
- // WithMouseCellMotion starts the program with the mouse enabled in "cell
- // motion" mode.
- //
- // Cell motion mode enables mouse click, release, and wheel events. Mouse
- // movement events are also captured if a mouse button is pressed (i.e., drag
- // events). Cell motion mode is better supported than all motion mode.
- //
- // To enable mouse cell motion once the program has already started running use
- // the EnableMouseCellMotion command. To disable the mouse when the program is
- // running use the DisableMouse command.
- //
- // The mouse will be automatically disabled when the program exits.
- func WithMouseCellMotion() ProgramOption {
- return func(p *Program) {
- p.startupOptions |= withMouseCellMotion // set
- p.startupOptions &^= withMouseAllMotion // clear
- }
- }
- // WithMouseAllMotion starts the program with the mouse enabled in "all motion"
- // mode.
- //
- // EnableMouseAllMotion is a special command that enables mouse click, release,
- // wheel, and motion events, which are delivered regardless of whether a mouse
- // button is pressed, effectively enabling support for hover interactions.
- //
- // Many modern terminals support this, but not all. If in doubt, use
- // EnableMouseCellMotion instead.
- //
- // To enable the mouse once the program has already started running use the
- // EnableMouseAllMotion command. To disable the mouse when the program is
- // running use the DisableMouse command.
- //
- // The mouse will be automatically disabled when the program exits.
- func WithMouseAllMotion() ProgramOption {
- return func(p *Program) {
- p.startupOptions |= withMouseAllMotion // set
- p.startupOptions &^= withMouseCellMotion // clear
- }
- }
- // WithoutRenderer disables the renderer. When this is set output and log
- // statements will be plainly sent to stdout (or another output if one is set)
- // without any rendering and redrawing logic. In other words, printing and
- // logging will behave the same way it would in a non-TUI commandline tool.
- // This can be useful if you want to use the Bubble Tea framework for a non-TUI
- // application, or to provide an additional non-TUI mode to your Bubble Tea
- // programs. For example, your program could behave like a daemon if output is
- // not a TTY.
- func WithoutRenderer() ProgramOption {
- return func(p *Program) {
- p.renderer = &nilRenderer{}
- }
- }
- // WithANSICompressor removes redundant ANSI sequences to produce potentially
- // smaller output, at the cost of some processing overhead.
- //
- // This feature is provisional, and may be changed or removed in a future version
- // of this package.
- func WithANSICompressor() ProgramOption {
- return func(p *Program) {
- p.startupOptions |= withANSICompressor
- }
- }
- // WithFilter supplies an event filter that will be invoked before Bubble Tea
- // processes a tea.Msg. The event filter can return any tea.Msg which will then
- // get handled by Bubble Tea instead of the original event. If the event filter
- // returns nil, the event will be ignored and Bubble Tea will not process it.
- //
- // As an example, this could be used to prevent a program from shutting down if
- // there are unsaved changes.
- //
- // Example:
- //
- // func filter(m tea.Model, msg tea.Msg) tea.Msg {
- // if _, ok := msg.(tea.QuitMsg); !ok {
- // return msg
- // }
- //
- // model := m.(myModel)
- // if model.hasChanges {
- // return nil
- // }
- //
- // return msg
- // }
- //
- // p := tea.NewProgram(Model{}, tea.WithFilter(filter));
- //
- // if _,err := p.Run(); err != nil {
- // fmt.Println("Error running program:", err)
- // os.Exit(1)
- // }
- func WithFilter(filter func(Model, Msg) Msg) ProgramOption {
- return func(p *Program) {
- p.filter = filter
- }
- }
|