tea

package module
v0.0.0-...-1ecfd45 Latest Latest
Warning

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

Go to latest
Published: Feb 13, 2026 License: MIT Imports: 26 Imported by: 0

README

Bubble Tea


最新版本 GoDoc 构建状态

构建终端应用的有趣、实用且有状态的方法。一个基于 The Elm Architecture 的 Go 框架。Bubble Tea 非常适合简单和复杂的终端应用程序,无论是内联、全屏窗口还是两者的混合。

Bubble Tea 示例

Bubble Tea 已在生产环境中使用,并包含了我们在开发过程中添加的许多功能和性能优化。其中包括基于帧率的渲染器、鼠标支持、焦点报告等。

要开始使用,请查看下面的教程、示例文档视频教程 和一些常见的 资源

顺便说一下

请务必查看 Bubbles,这是一个为 Bubble Tea 提供常见 UI 组件的库。

Bubbles 徽章   来自 Bubbles 的文本输入示例


教程

Bubble Tea 基于 The Elm Architecture 的函数式设计范式,这种范式恰好与 Go 语言配合得很好。这是一种令人愉悦的应用程序构建方式。

本教程假设你已经具备 Go 语言的工作知识。

顺便说一下,本程序的未注释源代码可在 GitHub 上找到。

好了!让我们开始吧。

在本教程中,我们将创建一个购物清单应用。

首先,我们将定义包并导入一些库。我们唯一的外部导入是 Bubble Tea 库,我们将其简称为 tea

package main

// 这些导入将在教程的后续部分使用。如果你现在保存文件,
// Go 可能会抱怨它们未使用,但这没关系。
// 你可能还需要运行 `go mod tidy` 来下载 bubbletea 及其依赖项。
import (
    "fmt"
    "os"

    tea "github.com/purpose168/bubbletea-cn"
)

Bubble Tea 程序由一个描述应用程序状态的 模型 和该模型上的三个简单方法组成:

  • Init:一个返回应用程序初始命令的函数。
  • Update:一个处理传入事件并相应更新模型的函数。
  • View:一个基于模型中的数据渲染 UI 的函数。
模型

让我们首先定义我们的模型,它将存储应用程序的状态。它可以是任何类型,但 struct 通常是最合理的选择。

// model 定义了应用程序的状态
type model struct {
    choices  []string           // 待办事项列表中的项目
    cursor   int                // 光标指向的待办事项索引
    selected map[int]struct{}   // 已选择的待办事项
}
初始化

接下来,我们将定义应用程序的初始状态。在这种情况下,我们定义一个函数来返回我们的初始模型,但我们也可以在其他地方将初始模型定义为变量。

// initialModel 返回应用程序的初始模型
func initialModel() model {
	return model{
		// 我们的待办事项列表是一个购物清单
		choices:  []string{"Buy carrots", "Buy celery", "Buy kohlrabi"},

		// 一个表示哪些选项被选中的映射。我们将映射用作数学集合。
		// 键引用上面 `choices` 切片的索引。
		selected: make(map[int]struct{}),
	}
}

接下来,我们定义 Init 方法。Init 可以返回一个 Cmd,用于执行一些初始 I/O 操作。现在,我们不需要执行任何 I/O 操作,所以对于命令,我们只返回 nil,这表示"无命令"。

// Init 返回应用程序的初始命令
func (m model) Init() tea.Cmd {
    // 只需返回 `nil`,这表示"现在不需要 I/O 操作"。
    return nil
}
Update 方法

接下来是更新方法。当"事情发生"时,会调用更新函数。它的任务是查看发生了什么,并返回一个更新后的模型作为响应。它还可以返回一个 Cmd 来使更多事情发生,但现在不用担心这部分。

在我们的例子中,当用户按下向下箭头时,Update 的任务是注意到按下了向下箭头,并相应地移动光标(或不移动)。

"发生的事情"以 Msg 的形式出现,它可以是任何类型。消息是某些 I/O 操作的结果,例如按键、计时器滴答声或服务器的响应。

我们通常使用类型开关来确定我们收到的 Msg 类型,但你也可以使用类型断言。

现在,我们只处理 tea.KeyMsg 消息,当按键时,这些消息会自动发送到更新函数。

// Update 处理消息并更新模型状态
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {

    // 是按键消息吗?
    case tea.KeyMsg:

        // 很酷,实际按下的是什么键?
        switch msg.String() {

        // 这些键应该退出程序。
        case "ctrl+c", "q":
            return m, tea.Quit

        // "up" 和 "k" 键向上移动光标
        case "up", "k":
            if m.cursor > 0 {
                m.cursor--
            }

        // "down" 和 "j" 键向下移动光标
        case "down", "j":
            if m.cursor < len(m.choices)-1 {
                m.cursor++
            }

        // "enter" 键和空格键(字面意义上的空格)切换
        // 光标指向的项目的选择状态。
        case "enter", " ":
            _, ok := m.selected[m.cursor]
            if ok {
                delete(m.selected, m.cursor)
            } else {
                m.selected[m.cursor] = struct{}{}
            }
        }
    }

    // 将更新后的模型返回给 Bubble Tea 运行时进行处理。
    // 注意,我们没有返回命令。
    return m, nil
}

你可能已经注意到,上面的 ctrl+c 和 q 返回带有模型的 tea.Quit 命令。这是一个特殊命令,指示 Bubble Tea 运行时退出程序。

View 方法

最后,是时候渲染我们的 UI 了。在所有方法中,视图是最简单的。我们查看当前状态下的模型,并使用它返回一个 string。这个字符串就是我们的 UI!

因为视图描述了应用程序的整个 UI,所以你不必担心重绘逻辑之类的事情。Bubble Tea 会为你处理这些。

// View 根据模型状态渲染 UI
func (m model) View() string {
    // 头部
    s := "What should we buy at the market?\n\n"

    // 遍历我们的选项
    for i, choice := range m.choices {

        // 光标是否指向这个选项?
        cursor := " " // 无光标
        if m.cursor == i {
            cursor = ">" // 有光标!
        }

        // 这个选项是否被选中?
        checked := " " // 未选中
        if _, ok := m.selected[i]; ok {
            checked = "x" // 已选中!
        }

        // 渲染行
        s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
    }

    // 底部
    s += "\nPress q to quit.\n"

    // 发送 UI 进行渲染
    return s
}
全部整合

最后一步是简单地运行我们的程序。我们将初始模型传递给 tea.NewProgram 并让它运行:

// main 是应用程序的入口点
func main() {
    p := tea.NewProgram(initialModel())
    if _, err := p.Run(); err != nil {
        fmt.Printf("Alas, there's been an error: %v", err)
        os.Exit(1)
    }
}

接下来做什么?

本教程涵盖了构建交互式终端 UI 的基础知识,但在现实世界中,你还需要执行 I/O 操作。要了解这方面的内容,请查看 命令教程。它非常简单。

还有几个 Bubble Tea 示例 可供参考,当然,还有 Go 文档

调试

使用 Delve 调试

由于 Bubble Tea 应用程序会控制 stdin 和 stdout,你需要以无头模式运行 delve,然后连接到它:

# 启动调试器
$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
API server listening at: 127.0.0.1:43000

# 从另一个终端连接到它
$ dlv connect 127.0.0.1:43000

如果你没有明确提供 --listen 标志,使用的端口会在每次运行时变化,因此传入此标志可以使调试器更易于从脚本或你选择的 IDE 中使用。

此外,我们传入 --api-version=2,因为 delve 默认使用版本 1 以保持向后兼容性。然而,delve 建议对所有新开发使用版本 2,并且一些客户端可能不再与版本 1 兼容。有关更多信息,请参阅 Delve 文档

日志记录

你不能真正使用 Bubble Tea 向 stdout 记录日志,因为你的 TUI 正忙于占用它!但是,你可以通过在启动 Bubble Tea 程序之前包含以下内容来将日志记录到文件:

// 如果设置了 DEBUG 环境变量,则启用日志记录
if len(os.Getenv("DEBUG")) > 0 {
	f, err := tea.LogToFile("debug.log", "debug")
	if err != nil {
		fmt.Println("fatal:", err)
		os.Exit(1)
	}
	defer f.Close()
}

要实时查看正在记录的内容,请在另一个窗口中运行 tail -f debug.log,同时运行你的程序。

我们与 Bubble Tea 一起使用的库

  • Bubbles:常见的 Bubble Tea 组件,如文本输入、视口、加载指示器等
  • Lip Gloss:终端应用程序的样式、格式和布局工具
  • Harmonica:用于平滑、自然运动的弹簧动画库
  • BubbleZone:Bubble Tea 组件的简单鼠标事件跟踪
  • ntcharts:为 Bubble Tea 和 Lip Gloss 构建的终端图表库

实际应用中的 Bubble Tea

有超过 10,000 个应用程序 是使用 Bubble Tea 构建的!以下是其中的一部分。

员工推荐
  • chezmoi:跨多台机器安全管理你的点文件
  • circumflex:在终端中阅读 Hacker News
  • gh-dash:用于 PR 和问题的 GitHub CLI 扩展
  • Tetrigo:终端中的俄罗斯方块
  • Signls:专为作曲和现场表演设计的生成式 MIDI sequencer
  • Superfile:超级文件管理器
行业应用
  • Microsoft Azure – Aztify:将 Microsoft Azure 资源纳入 Terraform 管理
  • Daytona – Daytona:开源开发环境管理器
  • Cockroach Labs – CockroachDB:云原生、高可用性分布式 SQL 数据库
  • Truffle Security Co. – Trufflehog:查找泄露的凭据
  • NVIDIA – container-canary:容器验证器
  • AWS – eks-node-viewer:用于可视化 EKS 集群中动态节点使用情况的工具
  • MinIO – mc:官方 MinIO 客户端
  • Ubuntu – Authd:用于基于云的身份提供商的身份验证守护程序
Charm 相关项目
  • Glow:Markdown 阅读器、浏览器和在线 Markdown 存储
  • Huh?:交互式提示和表单工具包
  • Mods:CLI 上的 AI,为管道构建
  • Wishlist:SSH 目录(和堡垒机!)
还有更多

要了解更多使用 Bubble Tea 构建的应用程序,请查看 Charm & Friends。你用 Bubble Tea 制作了很酷的东西并想分享吗?欢迎提交 PR

贡献

请参阅 contributing

反馈

我们很想听听你对这个项目的想法。随时给我们留言!

致谢

Bubble Tea 基于 Evan Czaplicki 等人的 The Elm Architecture 范式和 TJ Holowaychuk 的优秀 go-tea。它的灵感来自于过去许多伟大的 Zeichenorientierte Benutzerschnittstellen(字符导向用户界面)。

许可证

MIT

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/purpose168/bubbletea-cn/tree/master/tutorials

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

Index

Constants

This section is empty.

Variables

View Source
var ErrInterrupted = errors.New("program was interrupted")

ErrInterrupted is returned by Program.Run when the program get a SIGINT signal, or when it receives a InterruptMsg.

View Source
var ErrProgramKilled = errors.New("program was killed")

ErrProgramKilled is returned by Program.Run when the program gets killed.

View Source
var ErrProgramPanic = errors.New("program experienced a panic")

ErrProgramPanic is returned by Program.Run when the program recovers from a panic.

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

func LogToFileWith

func LogToFileWith(path string, prefix string, log LogOptionsSetter) (*os.File, error)

LogToFileWith does allows to call LogToFile with a custom LogOptionsSetter.

Types

type BatchMsg

type BatchMsg []Cmd

BatchMsg is a message used to perform a bunch of commands concurrently with no ordering guarantees. You can send a BatchMsg with Batch.

type BlurMsg

type BlurMsg struct{}

BlurMsg represents a terminal blur message. This occurs when the terminal loses focus.

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

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

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: err}
})

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

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

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

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

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

If the altscreen is active no output will be printed.

func ScrollDown deprecated

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.

Deprecated: This option will be removed in a future version of this package.

func ScrollUp deprecated

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.

Deprecated: This option will be removed in a future version of this package.

func Sequence

func Sequence(cmds ...Cmd) Cmd

Sequence runs the given commands one at a time, in order. Contrast this with Batch, which runs commands concurrently.

func Sequentially deprecated

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)

Deprecated: use Sequence instead.

func SetWindowTitle

func SetWindowTitle(title string) Cmd

SetWindowTitle produces a command that sets the terminal title.

For example:

func (m model) Init() Cmd {
    // Set title.
    return tea.SetWindowTitle("My App")
}

func SyncScrollArea deprecated

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.

Deprecated: This option will be removed in a future version of this package.

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

func WindowSize

func WindowSize() Cmd

WindowSize is a command that queries the terminal for its current size. It delivers the results to Update via a WindowSizeMsg. Keep in mind that WindowSizeMsgs will automatically be delivered to Update when the Program starts and when the window dimensions change so in many cases you will not need to explicitly invoke this command.

type ExecCallback

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

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 FocusMsg

type FocusMsg struct{}

FocusMsg represents a terminal focus message. This occurs when the terminal gains focus.

type InterruptMsg

type InterruptMsg struct{}

InterruptMsg signals the program should suspend. This usually happens when ctrl+c is pressed on common programs, but since bubbletea puts the terminal in raw mode, we need to handle it in a per-program basis.

You can send this message with [Interrupt()].

type Key

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

Key contains information about a keypress.

func (Key) String

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
	KeyCtrlPgUp
	KeyCtrlPgDown
	KeyDelete
	KeyInsert
	KeySpace
	KeyCtrlUp
	KeyCtrlDown
	KeyCtrlRight
	KeyCtrlLeft
	KeyCtrlHome
	KeyCtrlEnd
	KeyShiftUp
	KeyShiftDown
	KeyShiftRight
	KeyShiftLeft
	KeyShiftHome
	KeyShiftEnd
	KeyCtrlShiftUp
	KeyCtrlShiftDown
	KeyCtrlShiftLeft
	KeyCtrlShiftRight
	KeyCtrlShiftHome
	KeyCtrlShiftEnd
	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

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

type LogOptionsSetter

type LogOptionsSetter interface {
	SetOutput(io.Writer)
	SetPrefix(string)
}

LogOptionsSetter is an interface implemented by stdlib's log and charm's log libraries.

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 MouseAction

type MouseAction int

MouseAction represents the action that occurred during a mouse event.

const (
	MouseActionPress MouseAction = iota
	MouseActionRelease
	MouseActionMotion
)

Mouse event actions.

type MouseButton

type MouseButton int

MouseButton represents the button that was pressed during a mouse event.

const (
	MouseButtonNone MouseButton = iota
	MouseButtonLeft
	MouseButtonMiddle
	MouseButtonRight
	MouseButtonWheelUp
	MouseButtonWheelDown
	MouseButtonWheelLeft
	MouseButtonWheelRight
	MouseButtonBackward
	MouseButtonForward
	MouseButton10
	MouseButton11
)

Mouse event buttons

This is based on X11 mouse button codes.

1 = left button
2 = middle button (pressing the scroll wheel)
3 = right button
4 = turn scroll wheel up
5 = turn scroll wheel down
6 = push scroll wheel left
7 = push scroll wheel right
8 = 4th button (aka browser backward button)
9 = 5th button (aka browser forward button)
10
11

Other buttons are not supported.

type MouseEvent

type MouseEvent struct {
	X      int
	Y      int
	Shift  bool
	Alt    bool
	Ctrl   bool
	Action MouseAction
	Button MouseButton

	// Deprecated: Use MouseAction & MouseButton instead.
	Type MouseEventType
}

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

func (MouseEvent) IsWheel

func (m MouseEvent) IsWheel() bool

IsWheel returns true if the mouse event is a wheel event.

func (MouseEvent) String

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

String returns a string representation of a mouse event.

type MouseEventType deprecated

type MouseEventType int

MouseEventType indicates the type of mouse event occurring.

Deprecated: Use MouseAction & MouseButton instead.

const (
	MouseUnknown MouseEventType = iota
	MouseLeft
	MouseRight
	MouseMiddle
	MouseRelease // mouse button release (X10 only)
	MouseWheelUp
	MouseWheelDown
	MouseWheelLeft
	MouseWheelRight
	MouseBackward
	MouseForward
	MouseMotion
)

Mouse event types.

Deprecated: Use MouseAction & MouseButton instead.

type MouseMsg

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 in order for the mouse events to be received.

func (MouseMsg) String

func (m MouseMsg) String() string

String returns a string representation of a mouse event.

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 ClearScreen

func ClearScreen() Msg

ClearScreen is a special command that tells the program to clear the screen before the next update. This can be used to move the cursor to the top left of the screen and clear visual clutter when the alt screen is not in use.

Note that it should never be necessary to call ClearScreen() for regular redraws.

func ClearScrollArea deprecated

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.

Deprecated: This option will be removed in a future version of this package.

func DisableBracketedPaste

func DisableBracketedPaste() Msg

DisableBracketedPaste is a special command that tells the Bubble Tea program to stop processing bracketed paste input.

Note that bracketed paste will be automatically disabled when the program quits.

func DisableMouse

func DisableMouse() Msg

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

func DisableReportFocus

func DisableReportFocus() Msg

DisableReportFocus is a special command that tells the Bubble Tea program to stop reporting focus events to the program.

func EnableBracketedPaste

func EnableBracketedPaste() Msg

EnableBracketedPaste is a special command that tells the Bubble Tea program to accept bracketed paste input.

Note that bracketed paste will be automatically disabled when the program quits.

func EnableMouseAllMotion

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

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 EnableReportFocus

func EnableReportFocus() Msg

EnableReportFocus is a special command that tells the Bubble Tea program to report focus events to the program.

func EnterAltScreen

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

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 Interrupt

func Interrupt() Msg

Interrupt is a special command that tells the Bubble Tea program to interrupt.

func Quit

func Quit() Msg

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

func ShowCursor

func ShowCursor() Msg

ShowCursor is a special command for manually instructing Bubble Tea to show the cursor.

func Suspend

func Suspend() Msg

Suspend is a special command that tells the Bubble Tea program to suspend.

type Program

type Program struct {
	// 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

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

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

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

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

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

func (p *Program) ExitAltScreen()

ExitAltScreen exits the alternate screen buffer.

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

func (*Program) Kill

func (p *Program) Kill()

Kill signals the program to stop immediately and restore the former terminal state. The final render that you would normally see when quitting will be skipped. [program.Run] returns a ErrProgramKilled error.

func (*Program) Printf

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

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

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

If the altscreen is active no output will be printed.

func (*Program) Quit

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

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

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

func (p *Program) Run() (returnModel Model, returnErr error)

Run initializes the program and runs its event loops, blocking until it gets terminated by either Program.Quit, Program.Kill, or its signal handler. Returns the final model.

func (*Program) Send

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 hasn't started yet this will be a blocking operation. If the program has already been terminated this will be a no-op, so it's safe to send messages after the program has exited.

func (*Program) SetWindowTitle deprecated

func (p *Program) SetWindowTitle(title string)

SetWindowTitle sets the terminal window title.

Deprecated: Use the SetWindowTitle command instead.

func (*Program) Start deprecated

func (p *Program) Start() error

Start initializes the program and runs its event loops, blocking until it gets terminated by either Program.Quit, Program.Kill, or its signal handler.

Deprecated: please use Program.Run instead.

func (*Program) StartReturningModel deprecated

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

StartReturningModel initializes the program and runs its event loops, blocking until it gets terminated by either Program.Quit, Program.Kill, or its signal handler. Returns the final model.

Deprecated: please use Program.Run instead.

func (*Program) Wait

func (p *Program) Wait()

Wait waits/blocks until the underlying Program finished shutting down.

type ProgramOption

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 deprecated

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

Deprecated: this incurs a noticeable performance hit. A future release will optimize ANSI automatically without the performance penalty.

func WithAltScreen

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.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 WithContext

func WithContext(ctx context.Context) ProgramOption

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 WithEnvironment

func WithEnvironment(env []string) ProgramOption

WithEnvironment sets the environment variables that the program will use. This useful when the program is running in a remote session (e.g. SSH) and you want to pass the environment variables from the remote session to the program.

Example:

var sess ssh.Session // ssh.Session is a type from the github.com/charmbracelet/ssh package
pty, _, _ := sess.Pty()
environ := append(sess.Environ(), "TERM="+pty.Term)
p := tea.NewProgram(model, tea.WithEnvironment(environ)

func WithFPS

func WithFPS(fps int) ProgramOption

WithFPS sets a custom maximum FPS at which the renderer should run. If less than 1, the default value of 60 will be used. If over 120, the FPS will be capped at 120.

func WithFilter

func WithFilter(filter func(Model, Msg) Msg) ProgramOption

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 WithInput

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. To disable input entirely pass nil.

p := NewProgram(model, WithInput(nil))

func WithInputTTY

func WithInputTTY() ProgramOption

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

func WithMouseAllMotion

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.

This will try to enable the mouse in extended mode (SGR), if that is not supported by the terminal it will fall back to normal mode (X10).

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

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.

This will try to enable the mouse in extended mode (SGR), if that is not supported by the terminal it will fall back to normal mode (X10).

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

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 WithReportFocus

func WithReportFocus() ProgramOption

WithReportFocus enables reporting when the terminal gains and loses focus. When this is enabled FocusMsg and BlurMsg messages will be sent to your Update method.

Note that while most terminals and multiplexers support focus reporting, some do not. Also note that tmux needs to be configured to report focus events.

func WithoutBracketedPaste

func WithoutBracketedPaste() ProgramOption

WithoutBracketedPaste starts the program with bracketed paste disabled.

func WithoutCatchPanics

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

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.

func WithoutSignalHandler

func WithoutSignalHandler() ProgramOption

WithoutSignalHandler disables the signal handler that Bubble Tea sets up for Programs. This is useful if you want to handle signals yourself.

func WithoutSignals

func WithoutSignals() ProgramOption

WithoutSignals will ignore OS signals. This is mainly useful for testing.

type QuitMsg

type QuitMsg struct{}

QuitMsg signals that the program should quit. You can send a QuitMsg with Quit.

type ResumeMsg

type ResumeMsg struct{}

ResumeMsg can be listen to do something once a program is resumed back from a suspend state.

type SuspendMsg

type SuspendMsg struct{}

SuspendMsg signals the program should suspend. This usually happens when ctrl+z is pressed on common programs, but since bubbletea puts the terminal in raw mode, we need to handle it in a per-program basis.

You can send this message with [Suspend()].

type WindowSizeMsg

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.

Directories

Path Synopsis
examples
autocomplete command
cellbuffer command
chat command
debounce command
exec command
eyes command
roughly converted to Go from https://github.com/dmtrKovalenko/esp32-smooth-eye-blinking/blob/main/src/main.cpp
roughly converted to Go from https://github.com/dmtrKovalenko/esp32-smooth-eye-blinking/blob/main/src/main.cpp
file-picker command
focus-blur command
fullscreen command
glamour command
help command
http command
list-default command
list-fancy command
list-simple command
mouse command
package-manager command
pager command
paginator command
pipe command
prevent-quit command
progress-static command
realtime command
result command
send-msg command
sequence command
simple command
spinner command
spinners command
split-editors command
stopwatch command
suspend command
table command
table-resize command
tabs command
textarea command
textinput command
textinputs command
timer command
views command
window-size command
tutorials
basics command
commands command

Jump to

Keyboard shortcuts

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