tea

package module
Version: v0.22.0 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2022 License: MIT Imports: 23 Imported by: 664

README

Bubble Tea

Bubble Tea Title Treatment
Latest Release GoDoc Build Status

The fun, functional and stateful way to build terminal apps. A Go framework based on The Elm Architecture. Bubble Tea is well-suited for simple and complex terminal applications, either inline, full-window, or a mix of both.

Bubble Tea Example

Bubble Tea is in use in production and includes a number of features and performance optimizations we’ve added along the way. Among those is a standard framerate-based renderer, a renderer for high-performance scrollable regions which works alongside the main renderer, and mouse support.

To get started, see the tutorial below, the examples, the docs and some common resources.

By the way

Be sure to check out Bubbles, a library of common UI components for Bubble Tea.

Bubbles Badge   Text Input Example from Bubbles


Tutorial

Bubble Tea is based on the functional design paradigms of The Elm Architecture, which happen to work nicely with Go. It's a delightful way to build applications.

By the way, the non-annotated source code for this program is available on GitHub.

This tutorial assumes you have a working knowledge of Go.

Enough! Let's get to it.

For this tutorial we're making a shopping list.

To start we'll define our package and import some libraries. Our only external import will be the Bubble Tea library, which we'll call tea for short.

package main

import (
    "fmt"
    "os"

    tea "github.com/charmbracelet/bubbletea"
)

Bubble Tea programs are comprised of a model that describes the application state and three simple methods on that model:

  • Init, a function that returns an initial command for the application to run.
  • Update, a function that handles incoming events and updates the model accordingly.
  • View, a function that renders the UI based on the data in the model.

The Model

So let's start by defining our model which will store our application's state. It can be any type, but a struct usually makes the most sense.

type model struct {
    choices  []string           // items on the to-do list
    cursor   int                // which to-do list item our cursor is pointing at
    selected map[int]struct{}   // which to-do items are selected
}

Initialization

Next we’ll define our application’s initial state. In this case we’re defining a function to return our initial model, however we could just as easily define the initial model as a variable elsewhere, too.

func initialModel() model {
	return model{
		// Our shopping list is a grocery list
		choices:  []string{"Buy carrots", "Buy celery", "Buy kohlrabi"},

		// A map which indicates which choices are selected. We're using
		// the  map like a mathematical set. The keys refer to the indexes
		// of the `choices` slice, above.
		selected: make(map[int]struct{}),
	}
}

Next we define the Init method. Init can return a Cmd that could perform some initial I/O. For now, we don't need to do any I/O, so for the command we'll just return nil, which translates to "no command."

func (m model) Init() tea.Cmd {
    // Just return `nil`, which means "no I/O right now, please."
    return nil
}

The Update Method

Next up is the update method. The update function is called when ”things happen.” Its job is to look at what has happened and return an updated model in response. It can also return a Cmd to make more things happen, but for now don't worry about that part.

In our case, when a user presses the down arrow, Update’s job is to notice that the down arrow was pressed and move the cursor accordingly (or not).

The “something happened” comes in the form of a Msg, which can be any type. Messages are the result of some I/O that took place, such as a keypress, timer tick, or a response from a server.

We usually figure out which type of Msg we received with a type switch, but you could also use a type assertion.

For now, we'll just deal with tea.KeyMsg messages, which are automatically sent to the update function when keys are pressed.

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {

    // Is it a key press?
    case tea.KeyMsg:

        // Cool, what was the actual key pressed?
        switch msg.String() {

        // These keys should exit the program.
        case "ctrl+c", "q":
            return m, tea.Quit

        // The "up" and "k" keys move the cursor up
        case "up", "k":
            if m.cursor > 0 {
                m.cursor--
            }

        // The "down" and "j" keys move the cursor down
        case "down", "j":
            if m.cursor < len(m.choices)-1 {
                m.cursor++
            }

        // The "enter" key and the spacebar (a literal space) toggle
        // the selected state for the item that the cursor is pointing at.
        case "enter", " ":
            _, ok := m.selected[m.cursor]
            if ok {
                delete(m.selected, m.cursor)
            } else {
                m.selected[m.cursor] = struct{}{}
            }
        }
    }

    // Return the updated model to the Bubble Tea runtime for processing.
    // Note that we're not returning a command.
    return m, nil
}

You may have noticed that ctrl+c and q above return a tea.Quit command with the model. That’s a special command which instructs the Bubble Tea runtime to quit, exiting the program.

The View Method

At last, it’s time to render our UI. Of all the methods, the view is the simplest. We look at the model in it's current state and use it to return a string. That string is our UI!

Because the view describes the entire UI of your application, you don’t have to worry about redrawing logic and stuff like that. Bubble Tea takes care of it for you.

func (m model) View() string {
    // The header
    s := "What should we buy at the market?\n\n"

    // Iterate over our choices
    for i, choice := range m.choices {

        // Is the cursor pointing at this choice?
        cursor := " " // no cursor
        if m.cursor == i {
            cursor = ">" // cursor!
        }

        // Is this choice selected?
        checked := " " // not selected
        if _, ok := m.selected[i]; ok {
            checked = "x" // selected!
        }

        // Render the row
        s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
    }

    // The footer
    s += "\nPress q to quit.\n"

    // Send the UI for rendering
    return s
}

All Together Now

The last step is to simply run our program. We pass our initial model to tea.NewProgram and let it rip:

func main() {
    p := tea.NewProgram(initialModel())
    if err := p.Start(); err != nil {
        fmt.Printf("Alas, there's been an error: %v", err)
        os.Exit(1)
    }
}

What’s Next?

This tutorial covers the basics of building an interactive terminal UI, but in the real world you'll also need to perform I/O. To learn about that have a look at the Command Tutorial. It's pretty simple.

There are also several Bubble Tea examples available and, of course, there are Go Docs.

Debugging with Delve

Since Bubble Tea apps assume control of stdin and stdout, you’ll need to run delve in headless mode and then connect to it:

# Start the debugger
$ dlv debug --headless .
API server listening at: 127.0.0.1:34241

# Connect to it from another terminal
$ dlv connect 127.0.0.1:34241

Note that the default port used will vary on your system and per run, so actually watch out what address the first dlv run tells you to connect to.

Libraries we use with Bubble Tea

  • Bubbles: Common Bubble Tea components such as text inputs, viewports, spinners and so on
  • Lip Gloss: Style, format and layout tools for terminal applications
  • Harmonica: A spring animation library for smooth, natural motion
  • Termenv: Advanced ANSI styling for terminal applications
  • Reflow: Advanced ANSI-aware methods for working with text

Bubble Tea in the Wild

For some Bubble Tea programs in production, see:

  • AT CLI: a utility for executing AT Commands via serial port connections
  • Canard: an RSS client
  • The Charm Tool: the Charm user account manager
  • clidle: a Wordle clone for your terminal
  • fm: a terminal-based file manager
  • fork-cleaner: cleans up old and inactive forks in your GitHub account
  • gambit: play chess in the terminal
  • gembro: a mouse-driven Gemini browser
  • gh-b: GitHub CLI extension to easily manage your branches
  • gh-dash: GitHub cli extension to display a dashboard of PRs and issues
  • gitflow-toolkit: a GitFlow submission tool
  • Glow: a markdown reader, browser and online markdown stash
  • gocovsh: explore Go coverage reports from the CLI
  • httpit: a rapid http(s) benchmark tool
  • IDNT: batch software uninstaller
  • kboard: a typing game
  • mergestat: run SQL queries on git repositories
  • mc: the official MinIO client
  • portal: securely send transfer between computers
  • redis-viewer: browse Redis databases
  • Slides: a markdown-based presentation tool
  • Soft Serve: a command-line-first Git server that runs a TUI over SSH
  • StormForge Optimize Controller: a tool for experimenting with application configurations in Kubernetes
  • STTG: teletext client for SVT, Sweden’s national public television station
  • sttr: run various text transformations
  • tasktimer: a dead-simple task timer
  • termdbms: a keyboard and mouse driven database browser
  • ticker: a terminal stock watcher and stock position tracker
  • tran: securely transfer stuff between computers (based on portal)
  • tz: an aid for scheduling across multiple time zones
  • Typer: a typing test
  • wishlist: an SSH directory

Feedback

We'd love to hear your thoughts on this tutorial. Feel free to drop us a note!

Acknowledgments

Bubble Tea is based on the paradigms of The Elm Architecture by Evan Czaplicki et alia and the excellent go-tea by TJ Holowaychuk.

License

MIT


Part of Charm.

The Charm logo

Charm热爱开源 • Charm loves open source

Documentation

Overview

Package tea provides a framework for building rich terminal user interfaces based on the paradigms of The Elm Architecture. It's well-suited for simple and complex terminal applications, either inline, full-window, or a mix of both. It's been battle-tested in several large projects and is production-ready.

A tutorial is available at https://github.com/charmbracelet/bubbletea/tree/master/tutorials

Example programs can be found at https://github.com/charmbracelet/bubbletea/tree/master/examples

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LogToFile

func LogToFile(path string, prefix string) (*os.File, error)

LogToFile sets up default logging to log to a file. This is helpful as we can't print to the terminal since our TUI is occupying it. If the file doesn't exist it will be created.

Don't forget to close the file when you're done with it.

  f, err := LogToFile("debug.log", "debug")
  if err != nil {
		fmt.Println("fatal:", err)
		os.Exit(1)
  }
  defer f.Close()

Types

type Cmd

type Cmd func() Msg

Cmd is an IO operation that returns a message when it's complete. If it's nil it's considered a no-op. Use it for things like HTTP requests, timers, saving and loading from disk, and so on.

Note that there's almost never a reason to use a command to send a message to another part of your program. That can almost always be done in the update function.

func Batch

func Batch(cmds ...Cmd) Cmd

Batch performs a bunch of commands concurrently with no ordering guarantees about the results. Use a Batch to return several commands.

Example:

    func (m model) Init() Cmd {
	       return tea.Batch(someCommand, someOtherCommand)
    }

func Every

func Every(duration time.Duration, fn func(time.Time) Msg) Cmd

Every is a command that ticks in sync with the system clock. So, if you wanted to tick with the system clock every second, minute or hour you could use this. It's also handy for having different things tick in sync.

Because we're ticking with the system clock the tick will likely not run for the entire specified duration. For example, if we're ticking for one minute and the clock is at 12:34:20 then the next tick will happen at 12:35:00, 40 seconds later.

To produce the command, pass a duration and a function which returns a message containing the time at which the tick occurred.

type TickMsg time.Time

cmd := Every(time.Second, func(t time.Time) Msg {
   return TickMsg(t)
})

Beginners' note: Every sends a single message and won't automatically dispatch messages at an interval. To do that, you'll want to return another Every command after receiving your tick message. For example:

type TickMsg time.Time

// Send a message every second.
func tickEvery() Cmd {
    return Every(time.Second, func(t time.Time) Msg {
        return TickMsg(t)
    })
}

func (m model) Init() Cmd {
    // Start ticking.
    return tickEvery()
}

func (m model) Update(msg Msg) (Model, Cmd) {
    switch msg.(type) {
    case TickMsg:
        // Return your Every command again to loop.
        return m, tickEvery()
    }
    return m, nil
}

Every is analogous to Tick in the Elm Architecture.

func Exec added in v0.21.0

func Exec(c ExecCommand, fn ExecCallback) Cmd

Exec is used to perform arbitrary I/O in a blocking fashion, effectively pausing the Program while execution is runnning and resuming it when execution has completed.

Most of the time you'll want to use ExecProcess, which runs an exec.Cmd.

For non-interactive i/o you should use a Cmd (that is, a tea.Cmd).

func ExecProcess added in v0.21.0

func ExecProcess(c *exec.Cmd, fn ExecCallback) Cmd

ExecProcess runs the given *exec.Cmd in a blocking fashion, effectively pausing the Program while the command is running. After the *exec.Cmd exists the Program resumes. It's useful for spawning other interactive applications such as editors and shells from within a Program.

To produce the command, pass an *exec.Cmd and a function which returns a message containing the error which may have occurred when running the ExecCommand.

type VimFinishedMsg struct { err error }

c := exec.Command("vim", "file.txt")

cmd := ExecProcess(c, func(err error) Msg {
    return VimFinishedMsg{err: error}
})

Or, if you don't care about errors, you could simply:

cmd := ExecProcess(exec.Command("vim", "file.txt"), nil)

For non-interactive i/o you should use a Cmd (that is, a tea.Cmd).

func Printf added in v0.22.0

func Printf(template string, args ...interface{}) Cmd

Printf prints above the Program. It takes a format template followed by values similar to fmt.Printf. This output is unmanaged by the program and will persist across renders by the Program.

Unlike fmt.Printf (but similar to log.Printf) the message will be print on its own line.

If the altscreen is active no output will be printed.

func Println added in v0.22.0

func Println(args ...interface{}) Cmd

Printf prints above the Program. This output is unmanaged by the program and will persist across renders by the Program.

Unlike fmt.Printf (but similar to log.Printf) the message will be print on its own line.

If the altscreen is active no output will be printed.

func ScrollDown added in v0.9.0

func ScrollDown(newLines []string, topBoundary, bottomBoundary int) Cmd

ScrollDown adds lines to the bottom of the scrollable region, pushing existing lines above up. Lines that are pushed out of the scrollable region disappear from view.

For high-performance, scroll-based rendering only.

func ScrollUp added in v0.9.0

func ScrollUp(newLines []string, topBoundary, bottomBoundary int) Cmd

ScrollUp adds lines to the top of the scrollable region, pushing existing lines below down. Lines that are pushed out the scrollable region disappear from view.

For high-performance, scroll-based rendering only.

func Sequentially added in v0.12.4

func Sequentially(cmds ...Cmd) Cmd

Sequentially produces a command that sequentially executes the given commands. The Msg returned is the first non-nil message returned by a Cmd.

func saveStateCmd() Msg {
   if err := save(); err != nil {
       return errMsg{err}
   }
   return nil
}

cmd := Sequentially(saveStateCmd, Quit)

func SyncScrollArea added in v0.9.0

func SyncScrollArea(lines []string, topBoundary int, bottomBoundary int) Cmd

SyncScrollArea performs a paint of the entire region designated to be the scrollable area. This is required to initialize the scrollable region and should also be called on resize (WindowSizeMsg).

For high-performance, scroll-based rendering only.

func Tick

func Tick(d time.Duration, fn func(time.Time) Msg) Cmd

Tick produces a command at an interval independent of the system clock at the given duration. That is, the timer begins when precisely when invoked, and runs for its entire duration.

To produce the command, pass a duration and a function which returns a message containing the time at which the tick occurred.

type TickMsg time.Time

cmd := Tick(time.Second, func(t time.Time) Msg {
   return TickMsg(t)
})

Beginners' note: Tick sends a single message and won't automatically dispatch messages at an interval. To do that, you'll want to return another Tick command after receiving your tick message. For example:

type TickMsg time.Time

func doTick() Cmd {
    return Tick(time.Second, func(t time.Time) Msg {
        return TickMsg(t)
    })
}

func (m model) Init() Cmd {
    // Start ticking.
    return doTick()
}

func (m model) Update(msg Msg) (Model, Cmd) {
    switch msg.(type) {
    case TickMsg:
        // Return your Tick command again to loop.
        return m, doTick()
    }
    return m, nil
}

type ExecCallback added in v0.21.0

type ExecCallback func(error) Msg

ExecCallback is used when executing an *exec.Command to return a message with an error, which may or may not be nil.

type ExecCommand added in v0.21.0

type ExecCommand interface {
	Run() error
	SetStdin(io.Reader)
	SetStdout(io.Writer)
	SetStderr(io.Writer)
}

ExecCommand can be implemented to execute things in a blocking fashion in the current terminal.

type Key

type Key struct {
	Type  KeyType
	Runes []rune
	Alt   bool
}

Key contains information about a keypress.

func (Key) String added in v0.13.0

func (k Key) String() (str string)

String returns a friendly string representation for a key. It's safe (and encouraged) for use in key comparison.

k := Key{Type: KeyEnter}
fmt.Println(k)
// Output: enter

type KeyMsg

type KeyMsg Key

KeyMsg contains information about a keypress. KeyMsgs are always sent to the program's update function. There are a couple general patterns you could use to check for keypresses:

// Switch on the string representation of the key (shorter)
switch msg := msg.(type) {
case KeyMsg:
    switch msg.String() {
    case "enter":
        fmt.Println("you pressed enter!")
    case "a":
        fmt.Println("you pressed a!")
    }
}

// Switch on the key type (more foolproof)
switch msg := msg.(type) {
case KeyMsg:
    switch msg.Type {
    case KeyEnter:
        fmt.Println("you pressed enter!")
    case KeyRunes:
        switch string(msg.Runes) {
        case "a":
            fmt.Println("you pressed a!")
        }
    }
}

Note that Key.Runes will always contain at least one character, so you can always safely call Key.Runes[0]. In most cases Key.Runes will only contain one character, though certain input method editors (most notably Chinese IMEs) can input multiple runes at once.

func (KeyMsg) String

func (k KeyMsg) String() (str string)

String returns a string representation for a key message. It's safe (and encouraged) for use in key comparison.

type KeyType

type KeyType int

KeyType indicates the key pressed, such as KeyEnter or KeyBreak or KeyCtrlC. All other keys will be type KeyRunes. To get the rune value, check the Rune method on a Key struct, or use the Key.String() method:

k := Key{Type: KeyRunes, Runes: []rune{'a'}, Alt: true}
if k.Type == KeyRunes {

    fmt.Println(k.Runes)
    // Output: a

    fmt.Println(k.String())
    // Output: alt+a

}
const (
	KeyNull      KeyType = keyNUL
	KeyBreak     KeyType = keyETX
	KeyEnter     KeyType = keyCR
	KeyBackspace KeyType = keyDEL
	KeyTab       KeyType = keyHT
	KeyEsc       KeyType = keyESC
	KeyEscape    KeyType = keyESC

	KeyCtrlAt           KeyType = keyNUL // ctrl+@
	KeyCtrlA            KeyType = keySOH
	KeyCtrlB            KeyType = keySTX
	KeyCtrlC            KeyType = keyETX
	KeyCtrlD            KeyType = keyEOT
	KeyCtrlE            KeyType = keyENQ
	KeyCtrlF            KeyType = keyACK
	KeyCtrlG            KeyType = keyBEL
	KeyCtrlH            KeyType = keyBS
	KeyCtrlI            KeyType = keyHT
	KeyCtrlJ            KeyType = keyLF
	KeyCtrlK            KeyType = keyVT
	KeyCtrlL            KeyType = keyFF
	KeyCtrlM            KeyType = keyCR
	KeyCtrlN            KeyType = keySO
	KeyCtrlO            KeyType = keySI
	KeyCtrlP            KeyType = keyDLE
	KeyCtrlQ            KeyType = keyDC1
	KeyCtrlR            KeyType = keyDC2
	KeyCtrlS            KeyType = keyDC3
	KeyCtrlT            KeyType = keyDC4
	KeyCtrlU            KeyType = keyNAK
	KeyCtrlV            KeyType = keySYN
	KeyCtrlW            KeyType = keyETB
	KeyCtrlX            KeyType = keyCAN
	KeyCtrlY            KeyType = keyEM
	KeyCtrlZ            KeyType = keySUB
	KeyCtrlOpenBracket  KeyType = keyESC // ctrl+[
	KeyCtrlBackslash    KeyType = keyFS  // ctrl+\
	KeyCtrlCloseBracket KeyType = keyGS  // ctrl+]
	KeyCtrlCaret        KeyType = keyRS  // ctrl+^
	KeyCtrlUnderscore   KeyType = keyUS  // ctrl+_
	KeyCtrlQuestionMark KeyType = keyDEL // ctrl+?
)

Control key aliases.

const (
	KeyRunes KeyType = -(iota + 1)
	KeyUp
	KeyDown
	KeyRight
	KeyLeft
	KeyShiftTab
	KeyHome
	KeyEnd
	KeyPgUp
	KeyPgDown
	KeyDelete
	KeySpace
	KeyCtrlUp
	KeyCtrlDown
	KeyCtrlRight
	KeyCtrlLeft
	KeyShiftUp
	KeyShiftDown
	KeyShiftRight
	KeyShiftLeft
	KeyCtrlShiftUp
	KeyCtrlShiftDown
	KeyCtrlShiftLeft
	KeyCtrlShiftRight
	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyF13
	KeyF14
	KeyF15
	KeyF16
	KeyF17
	KeyF18
	KeyF19
	KeyF20
)

Other keys.

func (KeyType) String added in v0.13.0

func (k KeyType) String() (str string)

type Model

type Model interface {
	// Init is the first function that will be called. It returns an optional
	// initial command. To not perform an initial command return nil.
	Init() Cmd

	// Update is called when a message is received. Use it to inspect messages
	// and, in response, update the model and/or send a command.
	Update(Msg) (Model, Cmd)

	// View renders the program's UI, which is just a string. The view is
	// rendered after every Update.
	View() string
}

Model contains the program's state as well as its core functions.

type MouseEvent added in v0.10.0

type MouseEvent struct {
	X    int
	Y    int
	Type MouseEventType
	Alt  bool
	Ctrl bool
}

MouseEvent represents a mouse event, which could be a click, a scroll wheel movement, a cursor movement, or a combination.

func (MouseEvent) String added in v0.10.0

func (m MouseEvent) String() (s string)

String returns a string representation of a mouse event.

type MouseEventType added in v0.10.5

type MouseEventType int

MouseEventType indicates the type of mouse event occurring.

const (
	MouseUnknown MouseEventType = iota
	MouseLeft
	MouseRight
	MouseMiddle
	MouseRelease
	MouseWheelUp
	MouseWheelDown
	MouseMotion
)

Mouse event types.

type MouseMsg added in v0.10.0

type MouseMsg MouseEvent

MouseMsg contains information about a mouse event and are sent to a programs update function when mouse activity occurs. Note that the mouse must first be enabled via in order the mouse events to be received.

type Msg

type Msg interface{}

Msg contain data from the result of a IO operation. Msgs trigger the update function and, henceforth, the UI.

func ClearScrollArea added in v0.9.0

func ClearScrollArea() Msg

ClearScrollArea deallocates the scrollable region and returns the control of those lines to the main rendering routine.

For high-performance, scroll-based rendering only.

func DisableMouse added in v0.13.3

func DisableMouse() Msg

DisableMouse is a special command that stops listening for mouse events.

func EnableMouseAllMotion added in v0.13.3

func EnableMouseAllMotion() Msg

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.

Because commands run asynchronously, this command should not be used in your model's Init function. Use the WithMouseAllMotion ProgramOption instead.

func EnableMouseCellMotion added in v0.13.3

func EnableMouseCellMotion() Msg

EnableMouseCellMotion is a special command that enables mouse click, release, and wheel events. Mouse movement events are also captured if a mouse button is pressed (i.e., drag events).

Because commands run asynchronously, this command should not be used in your model's Init function. Use the WithMouseCellMotion ProgramOption instead.

func EnterAltScreen added in v0.13.0

func EnterAltScreen() Msg

EnterAltScreen is a special command that tells the Bubble Tea program to enter the alternate screen buffer.

Because commands run asynchronously, this command should not be used in your model's Init function. To initialize your program with the altscreen enabled use the WithAltScreen ProgramOption instead.

func ExitAltScreen

func ExitAltScreen() Msg

ExitAltScreen is a special command that tells the Bubble Tea program to exit the alternate screen buffer. This command should be used to exit the alternate screen buffer while the program is running.

Note that the alternate screen buffer will be automatically exited when the program quits.

func HideCursor added in v0.12.3

func HideCursor() Msg

HideCursor is a special command for manually instructing Bubble Tea to hide the cursor. In some rare cases, certain operations will cause the terminal to show the cursor, which is normally hidden for the duration of a Bubble Tea program's lifetime. You will most likely not need to use this command.

func Quit

func Quit() Msg

Quit is a special command that tells the Bubble Tea program to exit.

type Program

type Program struct {

	// CatchPanics is incredibly useful for restoring the terminal to a usable
	// state after a panic occurs. When this is set, Bubble Tea will recover
	// from panics, print the stack trace, and disable raw mode. This feature
	// is on by default.
	CatchPanics bool
	// contains filtered or unexported fields
}

Program is a terminal user interface.

func NewProgram

func NewProgram(model Model, opts ...ProgramOption) *Program

NewProgram creates a new Program.

func (*Program) DisableMouseAllMotion deprecated added in v0.10.0

func (p *Program) DisableMouseAllMotion()

DisableMouseAllMotion disables All Motion mouse tracking. This will be called automatically when exiting a Bubble Tea program.

Deprecated: The mouse will automatically be disabled when the program exits.

func (*Program) DisableMouseCellMotion deprecated added in v0.10.0

func (p *Program) DisableMouseCellMotion()

DisableMouseCellMotion disables Mouse Cell Motion tracking. This will be called automatically when exiting a Bubble Tea program.

Deprecated: The mouse will automatically be disabled when the program exits.

func (*Program) EnableMouseAllMotion deprecated added in v0.10.0

func (p *Program) EnableMouseAllMotion()

EnableMouseAllMotion enables mouse click, release, wheel and motion events, regardless of whether a mouse button is pressed. Many modern terminals support this, but not all.

Deprecated: Use the WithMouseAllMotion ProgramOption instead.

func (*Program) EnableMouseCellMotion deprecated added in v0.10.0

func (p *Program) EnableMouseCellMotion()

EnableMouseCellMotion enables mouse click, release, wheel and motion events if a mouse button is pressed (i.e., drag events).

Deprecated: Use the WithMouseCellMotion ProgramOption instead.

func (*Program) EnterAltScreen deprecated added in v0.10.0

func (p *Program) EnterAltScreen()

EnterAltScreen enters the alternate screen buffer, which consumes the entire terminal window. ExitAltScreen will return the terminal to its former state.

Deprecated: Use the WithAltScreen ProgramOption instead.

func (*Program) ExitAltScreen deprecated added in v0.10.0

func (p *Program) ExitAltScreen()

ExitAltScreen exits the alternate screen buffer.

Deprecated: The altscreen will exited automatically when the program exits.

func (*Program) Kill added in v0.20.0

func (p *Program) Kill()

Kill stops the program immediately and restores the former terminal state. The final render that you would normally see when quitting will be skipped.

func (*Program) Printf added in v0.22.0

func (p *Program) Printf(template string, args ...interface{})

Printf prints above the Program. It takes a format template followed by values similar to fmt.Printf. This output is unmanaged by the program and will persist across renders by the Program.

Unlike fmt.Printf (but similar to log.Printf) the message will be print on its own line.

If the altscreen is active no output will be printed.

func (*Program) Println added in v0.22.0

func (p *Program) Println(args ...interface{})

Printf prints above the Program. This output is unmanaged by the program and will persist across renders by the Program.

Unlike fmt.Printf (but similar to log.Printf) the message will be print on its own line.

If the altscreen is active no output will be printed.

func (*Program) Quit added in v0.18.0

func (p *Program) Quit()

Quit is a convenience function for quitting Bubble Tea programs. Use it when you need to shut down a Bubble Tea program from the outside.

If you wish to quit from within a Bubble Tea program use the Quit command.

If the program is not running this will be a no-op, so it's safe to call if the program is unstarted or has already exited.

func (*Program) ReleaseTerminal added in v0.21.0

func (p *Program) ReleaseTerminal() error

ReleaseTerminal restores the original terminal state and cancels the input reader. You can return control to the Program with RestoreTerminal.

func (*Program) RestoreTerminal added in v0.21.0

func (p *Program) RestoreTerminal() error

RestoreTerminal reinitializes the Program's input reader, restores the terminal to the former state when the program was running, and repaints. Use it to reinitialize a Program after running ReleaseTerminal.

func (*Program) Send added in v0.15.0

func (p *Program) Send(msg Msg)

Send sends a message to the main update function, effectively allowing messages to be injected from outside the program for interoperability purposes.

If the program is not running this this will be a no-op, so it's safe to send messages if the program is unstarted, or has exited.

func (*Program) Start

func (p *Program) Start() error

Start initializes the program. Ignores the final model.

func (*Program) StartReturningModel added in v0.19.0

func (p *Program) StartReturningModel() (Model, error)

StartReturningModel initializes the program. Returns the final model.

type ProgramOption added in v0.12.3

type ProgramOption func(*Program)

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))

func WithANSICompressor added in v0.19.0

func WithANSICompressor() ProgramOption

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 removed in a future version of this package.

func WithAltScreen added in v0.14.0

func WithAltScreen() ProgramOption

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.Start(); 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 WithInput added in v0.12.3

func WithInput(input io.Reader) ProgramOption

WithInput sets the input which, by default, is stdin. In most cases you won't need to use this.

func WithInputTTY added in v0.15.0

func WithInputTTY() ProgramOption

WithInputTTY open a new TTY for input (or console input device on Windows).

func WithMouseAllMotion added in v0.14.0

func WithMouseAllMotion() ProgramOption

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 WithMouseCellMotion added in v0.14.0

func WithMouseCellMotion() ProgramOption

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 WithOutput added in v0.12.3

func WithOutput(output io.Writer) ProgramOption

WithOutput sets the output which, by default, is stdout. In most cases you won't need to use this.

func WithoutCatchPanics added in v0.12.3

func WithoutCatchPanics() ProgramOption

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 WithoutRenderer added in v0.13.0

func WithoutRenderer() ProgramOption

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.

type WindowSizeMsg added in v0.9.0

type WindowSizeMsg struct {
	Width  int
	Height int
}

WindowSizeMsg is used to report the terminal size. It's sent to Update once initially and then on every terminal resize. Note that Windows does not have support for reporting when resizes occur as it does not support the SIGWINCH signal.

Jump to

Keyboard shortcuts

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