Documentation
¶
Overview ¶
Package vterm wraps a virtual terminal emulator (vt10x) that interprets PTY output into a 2D screen buffer suitable for rendering in the TUI. This enables support for interactive programs like vim, htop, and less.
Index ¶
- Constants
- type VTerm
- func (v *VTerm) ClearDirty()
- func (v *VTerm) ClearScrollback()
- func (v *VTerm) Cols() int
- func (v *VTerm) CursorPos() (row, col int)
- func (v *VTerm) IsAltScreen() bool
- func (v *VTerm) IsAppCursorKeys() bool
- func (v *VTerm) IsCursorHidden() bool
- func (v *VTerm) IsDirty() bool
- func (v *VTerm) IsMouseEnabled() bool
- func (v *VTerm) MouseProtocol() (mode string, sgr bool)
- func (v *VTerm) Render() []string
- func (v *VTerm) RenderANSI() []string
- func (v *VTerm) RenderANSIWithCursor() []string
- func (v *VTerm) Repaint() []byte
- func (v *VTerm) ResetMouseModes()
- func (v *VTerm) Resize(rows, cols int)
- func (v *VTerm) Rows() int
- func (v *VTerm) ScrollbackANSI() []string
- func (v *VTerm) ScrollbackEvictedTotal() int64
- func (v *VTerm) ScrollbackLen() int
- func (v *VTerm) ScrollbackTailANSI(n int) []string
- func (v *VTerm) SetScrollbackMax(n int)
- func (v *VTerm) Write(p []byte) (int, error)
Constants ¶
const ( MouseOff = "" // no tracking MouseX10 = "x10" // \x1b[?9h — button presses only, no release, no wheel MouseNormal = "normal" // \x1b[?1000h — press + release MouseButton = "button" // \x1b[?1002h — press + release + motion while a button is held MouseAny = "any" // \x1b[?1003h — press + release + all motion )
Mouse tracking protocols a child program can request. These name the tracking MODE — which events the child wants reported. The wire ENCODING is a separate axis, reported by MouseProtocol's sgr return.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type VTerm ¶
type VTerm struct {
// contains filtered or unexported fields
}
VTerm wraps a virtual terminal emulator that interprets PTY output into a 2D screen buffer suitable for rendering in the TUI.
func NewWithWriter ¶
NewWithWriter creates a VTerm with a response writer. The writer is used by terminal query responses such as CPR (ESC[6n -> ESC[row;colR), which interactive programs expect from a real terminal.
func (*VTerm) ClearScrollback ¶
func (v *VTerm) ClearScrollback()
ClearScrollback discards all retained scrollback history.
func (*VTerm) IsAltScreen ¶
IsAltScreen returns true if the alternate screen buffer is active. This indicates an interactive fullscreen program (vim, htop, less, etc.).
func (*VTerm) IsAppCursorKeys ¶
IsAppCursorKeys returns true while DECCKM (\x1b[?1h, terminfo smkx) is active: the child program expects cursor keys in the SS3 "application" encoding (\x1bOA..\x1bOD) instead of CSI (\x1b[A..\x1b[D). less and other termcap-driven programs IGNORE the CSI form entirely, so web/mobile clients must consult this before synthesizing arrow keys.
func (*VTerm) IsCursorHidden ¶
IsCursorHidden returns true if the terminal cursor is hidden (\x1b[?25l). TUI frameworks like Bubble Tea (used by Claude Code) hide the cursor on startup even when they don't use alternate screen mode.
func (*VTerm) IsDirty ¶
IsDirty returns true if the screen has been written to since last ClearDirty.
func (*VTerm) IsMouseEnabled ¶
IsMouseEnabled returns true if any mouse tracking mode is active. Programs that want mouse input (vim, htop) enable tracking via \x1b[?1000h, \x1b[?1002h, \x1b[?1003h, etc. When mouse tracking is NOT enabled, mouse events should not be forwarded to the PTY — the shell would display them as garbled text.
func (*VTerm) MouseProtocol ¶ added in v0.2.3
MouseProtocol reports what the child program actually asked for: its tracking mode (one of the Mouse* constants, MouseOff when tracking is off) and whether it also enabled SGR extended encoding (\x1b[?1006h).
Both halves matter when synthesizing an event for the child. A program that enabled \x1b[?1000h WITHOUT \x1b[?1006h expects the legacy X10 byte encoding (\x1b[M Cb+32 Cx+32 Cy+32) and cannot parse an SGR report (\x1b[<0;5;7M) — a line editor handed one typically eats the escape introducer and echoes the rest into its input buffer as literal text.
func (*VTerm) Render ¶
Render produces the current screen content as a slice of strings (one per row).
func (*VTerm) RenderANSI ¶
RenderANSI produces the current screen content as a slice of strings with ANSI escape sequences that preserve foreground/background colours and text attributes (bold, italic, underline, blink, reverse). Trailing cells that are plain spaces with default colours are trimmed to keep lines compact.
func (*VTerm) RenderANSIWithCursor ¶
RenderANSIWithCursor is like RenderANSI but draws a block cursor (reverse video on the cursor cell) when the cursor is visible. It is used for the in-pane VT rendering: the TUI renders the screen as plain text and cannot position a real hardware cursor, so without this the cursor of interactive programs such as vim would be invisible. When the cursor is hidden (\x1b[?25l, e.g. Bubble Tea apps like Claude Code) no cursor is drawn.
func (*VTerm) Repaint ¶
Repaint returns a byte sequence that, when written to a freshly created terminal emulator, reconstructs the current screen contents and cursor position. It is used to resume an interactive share session for a (re)joining subscriber whose remote VTerm starts empty: the source replays this so the subscriber sees the live app immediately instead of waiting for the app to redraw on its own.
The sequence clears the screen, then positions the cursor explicitly at the start of each row before writing that row's ANSI-styled content (avoiding any reliance on auto-wrap), and finally restores the real cursor position.
func (*VTerm) ResetMouseModes ¶ added in v0.2.3
func (v *VTerm) ResetMouseModes()
ResetMouseModes turns every mouse tracking and encoding mode off (\x1b[?9l, ?1000l, ?1002l, ?1003l, ?1006l).
The emulator outlives the programs that run in the pane: it is created once and fed every byte that pane's PTY ever produces. A program that enables tracking and dies without disabling it — killed with Ctrl+C, crashed, or simply sloppy on teardown — therefore leaves the tracking bit set for the rest of the pane's life, and every later program looks like it wants mouse reports. The TUI then forwards wheel and click events into the PTY of something that never asked for them (Claude Code, a bare shell), which shows them as literal text like "<65;50;54M".
Callers reset when the pane's foreground program changes; anything that wants tracking re-enables it on startup.
func (*VTerm) ScrollbackANSI ¶
ScrollbackANSI returns the scrollback history rendered to ANSI strings, oldest line first.
func (*VTerm) ScrollbackEvictedTotal ¶
ScrollbackEvictedTotal returns the monotonic count of lines ever captured into scrollback. Lets a consumer compute how many new lines appeared since it last checked, even after the ring has dropped older lines.
func (*VTerm) ScrollbackLen ¶
ScrollbackLen returns the number of retained scrollback lines.
func (*VTerm) ScrollbackTailANSI ¶
ScrollbackTailANSI returns the last n scrollback lines rendered to ANSI strings, oldest of the returned set first (fewer if the ring holds fewer).
func (*VTerm) SetScrollbackMax ¶
SetScrollbackMax sets how many scrolled-off lines the emulator retains.
func (*VTerm) Write ¶
Write feeds raw PTY output bytes into the VT emulator. Thread-safe: can be called from the PTY read goroutine.
Before forwarding to vt10x, CSI sequences with private parameter markers '>', '<', or '=' are stripped. These are modern terminal protocol extensions (Kitty keyboard protocol, xterm modifyOtherKeys, etc.) that vt10x does not understand. Without filtering, vt10x misinterprets e.g. ESC[>1u (Kitty keyboard push) as ESC[u (SCORC — restore cursor), resetting the cursor to the origin and breaking inline TUI layout (Claude Code, Bubble Tea apps).