Terminal Reference
Overview
The Terminal interface abstracts all communication with the user's terminal. It handles screen rendering, cursor management, raw mode, alternate screen buffers, and mouse event reporting. go-tui ships with two implementations: ANSITerminal for real terminals and MockTerminal for testing.
Most applications never interact with Terminal directly; the App type handles terminal setup and teardown. You'll use these types when you need custom terminal behavior, direct rendering, or test verification.
Terminal Interface
type Terminal interface {
Size() (width, height int)
Flush(changes []CellChange)
Clear()
ClearToEnd()
SetCursor(x, y int)
HideCursor()
ShowCursor()
EnterRawMode() error
ExitRawMode() error
EnterAltScreen()
ExitAltScreen()
EnableMouse()
DisableMouse()
Caps() Capabilities
WriteDirect([]byte) (int, error)
}
Size
Size() (width, height int)
Returns the terminal dimensions in cells (columns and rows).
Flush
Flush(changes []CellChange)
Writes a batch of cell changes to the terminal. Changes should be in row-major order for best performance. The implementation optimizes cursor movement and only emits style escape codes when the style differs from the previous cell.
Clear
Clear()
Clears the entire terminal screen, including scrollback on real terminals.
ClearToEnd
ClearToEnd()
Clears from the current cursor position to the end of the screen.
SetCursor
SetCursor(x, y int)
Moves the cursor to the given position. Coordinates are 0-indexed, with (0, 0) at the top-left corner.
HideCursor / ShowCursor
HideCursor()
ShowCursor()
Controls cursor visibility. HideCursor is typically called during rendering to prevent flicker, and ShowCursor restores visibility afterward.
EnterRawMode / ExitRawMode
EnterRawMode() error
ExitRawMode() error
Raw mode disables terminal line buffering so the application can read individual keystrokes. EnterRawMode saves the current terminal state; ExitRawMode restores it. Both return an error if the terminal state cannot be changed.
EnterAltScreen / ExitAltScreen
EnterAltScreen()
ExitAltScreen()
The alternate screen buffer is a separate display area that preserves the user's original terminal content. Full-screen applications use it so that quitting restores the previous scrollback. Inline-mode applications skip it.
EnableMouse / DisableMouse
EnableMouse()
DisableMouse()
Enables or disables SGR mouse event reporting. When enabled, mouse clicks, drags, and wheel scrolls generate MouseEvent values through the EventReader. Always call DisableMouse before exiting to restore normal terminal behavior.
Caps
Caps() Capabilities
Returns the terminal's detected capabilities: color support level, Unicode, true color, and alternate screen availability. See Capabilities below.
WriteDirect
WriteDirect([]byte) (int, error)
Writes raw bytes to the terminal output, bypassing the cell-based rendering pipeline. Use this for escape sequences or raw content that the higher-level API does not cover.
ANSITerminal
ANSITerminal is the production implementation of Terminal. It communicates with real terminal emulators through ANSI escape sequences.
Creating an ANSITerminal
NewANSITerminal
func NewANSITerminal(out io.Writer, in io.Reader) (*ANSITerminal, error)
Creates a terminal with auto-detected capabilities. The out parameter is typically os.Stdout and in is os.Stdin. File descriptors are extracted from the writers if they implement *os.File, which enables raw mode and terminal size queries.
import (
"os"
tui "github.com/grindlemire/go-tui"
)
term, err := tui.NewANSITerminal(os.Stdout, os.Stdin)
if err != nil {
// handle error
}
NewANSITerminalWithCaps
func NewANSITerminalWithCaps(out io.Writer, in io.Reader, caps Capabilities) *ANSITerminal
Creates a terminal with explicit capabilities instead of auto-detecting them. Use this when you know the target environment or want to force specific behavior.
caps := tui.Capabilities{
Colors: tui.ColorTrue,
Unicode: true,
TrueColor: true,
AltScreen: true,
}
term := tui.NewANSITerminalWithCaps(os.Stdout, os.Stdin, caps)
Additional Methods
ANSITerminal provides methods beyond the Terminal interface:
SetCaps
func (t *ANSITerminal) SetCaps(caps Capabilities)
Updates the terminal's capabilities after creation. You might call this if you detect capabilities at runtime through a terminal query/response sequence.
ResetStyle
func (t *ANSITerminal) ResetStyle()
Resets internal style tracking, forcing the next Flush call to emit style escape codes regardless of whether the style changed. Call this after writing directly to the terminal output to re-sync the style state.
Writer
func (t *ANSITerminal) Writer() io.Writer
Returns the underlying output writer. Be careful: writes through this bypass the terminal's style optimization and cursor tracking.
BeginSyncUpdate / EndSyncUpdate
func (t *ANSITerminal) BeginSyncUpdate()
func (t *ANSITerminal) EndSyncUpdate()
Brackets a synchronized update. Terminal emulators that support this protocol buffer output between Begin and End, then display everything at once. This prevents tearing during complex frame updates. Terminals that don't recognize the sequence just ignore it.
Size Defaults
ANSITerminal.Size() returns 80x24 if the terminal dimensions cannot be determined (e.g., when stdout is not a TTY).
BufferedWriter
A write buffer that batches output before sending it to an underlying writer.
type BufferedWriter struct {
// contains unexported fields
}
NewBufferedWriter
func NewBufferedWriter(out io.Writer) *BufferedWriter
Creates a BufferedWriter wrapping the given writer.
Write
func (w *BufferedWriter) Write(p []byte) (int, error)
Appends bytes to the internal buffer. Does not write to the underlying writer.
Flush
func (w *BufferedWriter) Flush() error
Writes the buffered content to the underlying writer and clears the buffer.
bw := tui.NewBufferedWriter(os.Stdout)
bw.Write([]byte("hello "))
bw.Write([]byte("world"))
bw.Flush() // writes "hello world" to stdout in one call
EventReader
The EventReader interface reads terminal input events for the application's event loop.
type EventReader interface {
PollEvent(timeout time.Duration) (Event, bool)
Close() error
}
PollEvent
PollEvent(timeout time.Duration) (Event, bool)
Reads the next input event within the given timeout. Returns (event, true) when an event is available, or (nil, false) on timeout. Timeout behavior:
- Positive duration: waits up to that long for an event
- Zero: non-blocking check, returns immediately
- Negative: blocks indefinitely until an event arrives
Resize events are handled at the App level, not by the reader. The App catches SIGWINCH signals and dispatches ResizeEvent through the event queue. The reader only handles keyboard and mouse input.
Close
Close() error
Releases resources held by the reader (signal handlers, file descriptors). Must be called when the reader is no longer needed.
NewEventReader
func NewEventReader(in *os.File) (EventReader, error)
Creates an EventReader for the given input file (typically os.Stdin). The terminal should already be in raw mode before creating the reader. The reader handles keyboard and mouse input only; resize events (SIGWINCH) are handled at the App level.
import (
"os"
tui "github.com/grindlemire/go-tui"
)
reader, err := tui.NewEventReader(os.Stdin)
if err != nil {
// handle error
}
defer reader.Close()
event, ok := reader.PollEvent(100 * time.Millisecond)
if ok {
// process event
}
InterruptibleReader
Extends EventReader with the ability to wake up a blocking PollEvent call from another goroutine.
type InterruptibleReader interface {
EventReader
EnableInterrupt() error
Interrupt() error
}
EnableInterrupt
EnableInterrupt() error
Sets up the interrupt mechanism (a self-pipe on Unix). The framework calls this automatically during App initialization. Calling it multiple times is safe; subsequent calls are no-ops.
Interrupt
Interrupt() error
Wakes up a blocking PollEvent call. The blocked call returns (nil, false). Safe to call even when PollEvent is not currently blocking.
The App uses InterruptibleReader internally to wake the event loop when state changes are queued via QueueUpdate.
Capabilities
Capabilities describes what features the terminal supports.
type Capabilities struct {
Colors ColorCapability
Unicode bool
TrueColor bool
AltScreen bool
}
| Field | Type | Description |
|---|---|---|
Colors |
ColorCapability |
Level of color support (none, 16, 256, or true color) |
Unicode |
bool |
Whether the terminal renders Unicode characters |
TrueColor |
bool |
Whether 24-bit RGB colors are supported |
AltScreen |
bool |
Whether the alternate screen buffer is available |
DetectCapabilities
func DetectCapabilities() Capabilities
Determines terminal capabilities from environment variables. Detection checks, in order:
COLORTERM—truecoloror24bitindicates true color support- Terminal-specific environment variables —
WT_SESSION(Windows Terminal),ITERM_SESSION_ID(iTerm2),KITTY_WINDOW_ID(Kitty),KONSOLE_VERSION(Konsole),VTE_VERSION(GNOME Terminal, Tilix) TERM—dumbdisables all features;256colorsuffix enables 256-color;truecolorenables true color
Default capabilities when detection finds nothing specific: 16-color, Unicode enabled, no true color, alternate screen available.
caps := tui.DetectCapabilities()
fmt.Println(caps) // e.g., "true-color, unicode, altscreen"
ColorCapability Constants
const (
ColorNone ColorCapability = iota // Monochrome, no color
Color16 // Standard 16 ANSI colors
Color256 // 256-color palette
ColorTrue // 24-bit RGB true color
)
SupportsColor
func (c Capabilities) SupportsColor(color Color) bool
Reports whether the terminal can display the given color. ANSI colors require at least Color16 support; RGB colors require TrueColor.
caps := tui.DetectCapabilities()
color := tui.RGBColor(255, 128, 0) // orange
if caps.SupportsColor(color) {
// use the color directly
} else {
// fall back to an ANSI approximation
}
EffectiveColor
func (c Capabilities) EffectiveColor(color Color) Color
Returns the best color the terminal can actually display. If the terminal supports the color type, returns the original. Otherwise, RGB colors are approximated to the nearest ANSI color, and ANSI colors on colorless terminals fall back to DefaultColor().
caps := tui.DetectCapabilities()
requested := tui.RGBColor(0, 200, 100)
actual := caps.EffectiveColor(requested) // RGB on true-color, ANSI approximation otherwise
String
func (c Capabilities) String() string
Returns a human-readable summary like "true-color, unicode, altscreen" or "16-color, ascii".
Render Functions
Package-level functions that App uses internally for rendering. They're also available if you're building a custom render loop.
Render
func Render(term Terminal, buf *Buffer)
Diff-based render. Computes the cells that changed since the last Swap() and calls term.Flush() with only those changes. This is the standard render path and minimizes bytes sent to the terminal.
RenderFull
func RenderFull(term Terminal, buf *Buffer)
Full redraw. Sends every non-empty cell to the terminal regardless of whether it changed. Use this after operations that may have corrupted the terminal state (e.g., a child process writing to stdout).
Cross-References
- Testing Reference —
MockTerminalandMockEventReadertest utilities - Buffer Reference —
Buffer,Cell, andCellChangetypes used byFlush - Events Reference —
Event,KeyEvent,MouseEventtypes returned byPollEvent - Styling Reference —
Style,Color, andCapabilitiescolor handling - App Reference —
AppmanagesTerminalandEventReaderlifecycle