Open-Source Wikis

/

Bubble Tea

/

Features

/

Terminal querying

charmbracelet/bubbletea

Terminal querying

Active contributors: aymanbagabas, meowgorithm

Purpose

Bubble Tea provides a small family of Cmds that ask the terminal questions and deliver typed replies through Update. Together they let programs adapt to the actual capabilities of the host terminal — color depth, current foreground/background colors, supported features, version, etc.

Color profile

The runtime always sends a ColorProfileMsg after detecting the terminal's profile via colorprofile.Detect (tea.go). To upgrade the profile to true color when supported, ask the terminal for the RGB and Tc capabilities:

func (m model) Init() tea.Cmd {
    return tea.Batch(
        tea.RequestCapability("RGB"),
        tea.RequestCapability("Tc"),
    )
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.ColorProfileMsg:
        m.profile = msg.Profile
    case tea.CapabilityMsg:
        // "RGB:..." or "Tc:..." — runtime upgrades profile to TrueColor automatically
    }
    return m, nil
}

Note: some terminals (notably Apple Terminal) reply incorrectly to XTGETTCAP and may break the program's output. The README warns about this. If you target Apple Terminal, gate the request on os.Getenv("TERM_PROGRAM") != "Apple_Terminal".

Current colors

return m, tea.Batch(
    tea.RequestForegroundColor(),
    tea.RequestBackgroundColor(),
    tea.RequestCursorColor(),
)

Replies arrive as ForegroundColorMsg, BackgroundColorMsg, and CursorColorMsg. Each embeds color.Color and has an IsDark() helper — handy when you want to pick a light or dark theme:

case tea.BackgroundColorMsg:
    m.styles = newStyles(msg.IsDark())

Cursor position

return m, tea.RequestCursorPosition
// Reply:
case tea.CursorPositionMsg:
    fmt.Printf("cursor at (%d, %d)\n", msg.X, msg.Y)

This is rarely needed during normal rendering — the renderer tracks cursor position internally. It is useful for one-off measurements (e.g. computing how many lines the program has scrolled past).

Window size

tea.RequestWindowSize asks for a fresh WindowSizeMsg. The runtime emits one automatically on startup and on every resize, so most programs do not need this. The exceptional case is right after tea.Exec returns and the program wants to confirm the dimensions.

Terminal version

tea.RequestTerminalVersion issues XTVERSION. The reply is a TerminalVersionMsg{Name string} where Name is the vendor-supplied string (e.g. "xterm.js (vscode 1.85)"). Use it to gate features that only work on certain terminal builds.

Mode reports

ModeReportMsg (screen.go) is sent when the terminal answers a mode-status query (DECRPM). The runtime handles ModeSynchronizedOutput and ModeUnicodeCore automatically; user code can request other modes with tea.Raw(ansi.RequestMode(...)) and observe the answers via ModeReportMsg. See the GoDoc for usage.

Capability replies

CapabilityMsg (termcap.go) carries Content strings like "RGB:..." or "Tc:...". Bubble Tea uses these to upgrade the color profile, but you can subscribe to other capabilities by issuing tea.RequestCapability("smcup"), "E3", etc.

Putting it all together

A typical "adapt-to-terminal" startup looks like:

func (m model) Init() tea.Cmd {
    return tea.Batch(
        tea.RequestBackgroundColor(),
        tea.RequestCapability("RGB"),
        tea.RequestCapability("Tc"),
    )
}

The model collects whatever replies arrive (some may not arrive at all if the terminal does not support the query) and adjusts its styling accordingly.

  • Commands — how request commands flow through the runtime.
  • Cursed renderer — how synchronized output and unicode core are auto-enabled when the terminal opts in.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Terminal querying – Bubble Tea wiki | Factory