Documentation
¶
Overview ¶
Package term is a full-featured terminal-emulator widget for the go-gui framework. It spawns a real shell via PTY and renders the cell grid through GPU-accelerated canvas drawing.
Quick start ¶
t, err := term.New(win, term.Cfg{})
if err != nil {
log.Fatal(err)
}
win.SetView(t.View(win))
Lifecycle ¶
New starts the PTY and a background reader goroutine. Close kills the child process, closes the PTY, and shuts down the reader. Always call Close when the window is closed to avoid leaking file descriptors and goroutines.
Use Cfg.OnExit to detect child-process death. Use Term.Alive to poll liveness without a callback.
Multi-Term windows (pane manager) ¶
Set Cfg.NoWindowHandler when embedding multiple Term instances in one window. A pane manager should install its own window-level event handler that routes events to the focused Term via Term.HandleWindowEvent and keyboard input to the focused Term's Term.View container. Use Term.SetFocused to switch focus between panes.
The Term.Rows, Term.Cols, Term.Write, Term.PID, and Term.Alive methods support pane-manager introspection without reaching into internal state.
Thread safety ¶
The widget's exported methods (Cwd, SetTheme, View, Close, Rows, Cols, Write, PID, Alive, SetFocused, HandleWindowEvent) are safe to call from any goroutine. Internal grid state is protected by a single mutex.
Security: OSC 52 clipboard ¶
OSC 52 clipboard write is disabled by default. Set Cfg.AllowOSC52Write to true only in trusted environments — untrusted terminal output can silently replace the clipboard.
Theme configuration ¶
Use Cfg.Themes to provide a list of named themes for runtime switching. The first entry is the initial theme: it seeds the grid and decides the COLORFGBG a child is spawned with, which cannot be corrected once the process is running.
BundledThemes returns the ~600 color themes go-term ships, sorted by name, decoded on first call. DefaultTheme is separate and is what a grid falls back to when Cfg.Themes is empty. A typical embedder registers the default first and the corpus after it. Theme.IsDark reports a theme's light/dark character — the same question DSR ?996 answers for the child — for an embedder theming its own chrome.
A light theme does not fix an application's *own* colors: a 24-bit SGR is not themeable, and tools that pick colors for a dark background hand a light theme text at 1.5:1. Cfg.MinimumContrast is the render-time floor that does, and go-term sets COLORFGBG at spawn so a child that checks it can choose correctly in the first place.
Cwd ¶
Term.Cwd returns the current working directory reported by the shell via OSC 7. Empty if the shell has not emitted a CWD escape sequence.
Supported platforms ¶
macOS, Linux, and Windows. The PTY boundary uses creack/pty on Unix and the ConPTY API on Windows; everything above it is platform-agnostic.
Stability ¶
go-term is pre-1.0. The public API is deliberately small so embedders have a narrow, well-defined contract to code against.
Stable: NamedTheme, Theme, DefaultTheme and BundledThemes — the bundled names won't change and their color values won't shift in ways that break contrast; Theme.IsDark, which answers the same light/dark question the emulator reports to the child through DSR ?996, for an embedder that themes its own chrome to match; the MaxGridDim and MaxScrollbackCap constants; the New constructor; every exported Term method (Term.View, Term.Close — idempotent, Term.Cwd, Term.Theme, Term.SetTheme, Term.Rows, Term.Cols, Term.Write, Term.PID, Term.Alive, Term.SetFocused, Term.HandleWindowEvent, Term.SetMinimumContrast); and Shortcuts / ShortcutInfo. Term is an opaque handle: all fields are unexported, so embedders interact only through methods.
What may change before 1.0:
- Cfg fields: new fields may be added. Renames and removals go through a deprecation cycle (at least one minor version with the old name still accepted). New fields are always zero-value-safe, so untouched configs keep working across minor bumps.
- Term methods: new methods may appear; existing signatures stay.
- The gui.View tree returned by Term.View is an implementation detail and may gain new widgets; embedders only pass the result to UpdateView, and that contract holds.
- Internal layout: import only this package; the source-file organisation within it is not a contract.
- Go version: the go directive in go.mod reflects the oldest Go release tested against and may advance on minor version bumps.
Concurrency details, render-pass structure, canvas IDs and draw versions, and parser dispatch sites are internal and not part of the contract.
Versioning ¶
Semantic Versioning with a pre-1.0 interpretation:
- Patch (0.x.Y): bug fix; no new API surface. Safe to upgrade.
- Minor (0.X.0): new feature; may add Cfg fields or Term methods, but existing signatures stay backwards compatible. Read the changelog before upgrading.
- Major (1.0.0): first stable release; standard semver afterwards.
Guidance for embedders: pin a minor version in go.mod; use Cfg zero values for everything you don't explicitly set; stick to the documented methods and open an issue rather than depending on internal state. The term/workspace package wires the multi-Term methods together for split-pane and tab embedding.
Index ¶
- Constants
- type Action
- type ActivityKind
- type BellMode
- type Cfg
- type Fixture
- type InputKind
- type KeyMap
- type NamedTheme
- type ReplayCfg
- type ShortcutInfo
- type Term
- func (t *Term) AdjustFontSize(delta float32)
- func (t *Term) Alive() bool
- func (t *Term) AvailableShortcuts() []ShortcutInfo
- func (t *Term) Close() error
- func (t *Term) Cols() int
- func (t *Term) Cwd() string
- func (t *Term) FocusID() string
- func (t *Term) FontSize() float32
- func (t *Term) HandleWindowEvent(e *gui.Event)
- func (t *Term) KeyBindings() KeyMap
- func (t *Term) PID() int
- func (t *Term) Recording() bool
- func (t *Term) ResetFontSize()
- func (t *Term) Rows() int
- func (t *Term) RunAction(a Action, w *gui.Window) bool
- func (t *Term) SendInput(p []byte, kind InputKind)
- func (t *Term) SetBellMode(m BellMode)
- func (t *Term) SetFocused(v bool)
- func (t *Term) SetFontSize(size float32)
- func (t *Term) SetKeyBindings(km KeyMap)
- func (t *Term) SetMiddleClickPaste(on bool)
- func (t *Term) SetMinimumContrast(ratio float64)
- func (t *Term) SetNotifyAfter(d time.Duration)
- func (t *Term) SetScrollbackRows(n int)
- func (t *Term) SetScrollbarWidth(px float32)
- func (t *Term) SetTextStyle(ts gui.TextStyle)
- func (t *Term) SetTheme(th Theme)
- func (t *Term) Shortcuts() []ShortcutInfo
- func (t *Term) StartRecording(path string) error
- func (t *Term) StopRecording() error
- func (t *Term) Theme() Theme
- func (t *Term) View(w *gui.Window) gui.View
- func (t *Term) Write(p []byte) (int, error)
- type Theme
Examples ¶
Constants ¶
const MaxGridDim = 1024
MaxGridDim caps each dimension of the cell buffer. Real terminals stay well below this; the cap exists so a runaway resize (huge canvas, NaN metrics, malicious caller) can't allocate hundreds of megabytes.
const MaxScrollbackCap = 100000
MaxScrollbackCap bounds ScrollbackCap so a malicious or mistaken Cfg.ScrollbackRows can't lead to multi-GB allocations as rows scroll. At MaxGridDim cols and ~17 B/cell this is roughly 1.7 GB worst case; callers should pick a value far below this.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Action ¶ added in v0.7.0
type Action string
Action names a rebindable Term-level keyboard action. Bindings for these live in a per-Term table seeded from Cfg.KeyBindings and mutated at runtime by Term.SetKeyBindings.
Workspace-level actions (tabs, panes, theme) are not Actions — they are gui.Commands in the workspace command registry and are rebound there.
const ( ActionCopy Action = "term.copy" ActionPaste Action = "term.paste" ActionFind Action = "term.find" ActionToggleRegex Action = "term.toggle-regex" ActionNextMatch Action = "term.next-match" ActionPrevMatch Action = "term.prev-match" ActionPrevPrompt Action = "term.prev-prompt" ActionNextPrompt Action = "term.next-prompt" ActionJumpFailure Action = "term.jump-failure" ActionSelectOutput Action = "term.select-output" ActionScrollPageUp Action = "term.scroll-page-up" ActionScrollPageDown Action = "term.scroll-page-down" ActionScrollTop Action = "term.scroll-top" ActionScrollBottom Action = "term.scroll-bottom" ActionFontInc Action = "term.font-inc" ActionFontDec Action = "term.font-dec" ActionFontReset Action = "term.font-reset" ActionCopyMode Action = "term.copy-mode" ActionHints Action = "term.hints" ActionHintsCopy Action = "term.hints-copy" )
Term-level rebindable actions. The "term." prefix keeps them distinct from workspace command IDs when both are named in one config file.
const ( ActionCopyModeExit Action = "term.copy-mode.exit" ActionCopyModeLeft Action = "term.copy-mode.left" ActionCopyModeDown Action = "term.copy-mode.down" ActionCopyModeUp Action = "term.copy-mode.up" ActionCopyModeRight Action = "term.copy-mode.right" ActionCopyModeWordFwd Action = "term.copy-mode.word-fwd" ActionCopyModeWordBack Action = "term.copy-mode.word-back" ActionCopyModeLineStart Action = "term.copy-mode.line-start" ActionCopyModeLineEnd Action = "term.copy-mode.line-end" ActionCopyModeTop Action = "term.copy-mode.top" ActionCopyModeBottom Action = "term.copy-mode.bottom" ActionCopyModeHalfPageUp Action = "term.copy-mode.half-page-up" ActionCopyModeHalfPageDown Action = "term.copy-mode.half-page-down" ActionCopyModePageUp Action = "term.copy-mode.page-up" ActionCopyModePageDown Action = "term.copy-mode.page-down" ActionCopyModeSelectChar Action = "term.copy-mode.select-char" ActionCopyModeSelectLine Action = "term.copy-mode.select-line" ActionCopyModeYank Action = "term.copy-mode.yank" ActionCopyModeSearchFwd Action = "term.copy-mode.search-fwd" ActionCopyModeSearchBack Action = "term.copy-mode.search-back" ActionCopyModeNextMatch Action = "term.copy-mode.next-match" ActionCopyModePrevMatch Action = "term.copy-mode.prev-match" ActionCopyModePrevMark Action = "term.copy-mode.prev-mark" ActionCopyModeNextMark Action = "term.copy-mode.next-mark" )
Copy-mode actions. These are only consulted while copy mode is active, so their chords are bare letters that would otherwise reach the child process. They live in the same binding table as every other Action — the mode gates *when* the table is consulted, not which table — so they stay rebindable through [keybindings] without a second matcher.
They are deliberately absent from actionOrder: the help overlay is a flat list, and twenty vim keys would swamp it. Copy mode shows its own key hints in its indicator bar, and docs/config.md lists the action names.
func ParseAction ¶ added in v0.7.0
ParseAction resolves an action name — the full "term."-prefixed form, e.g. "term.copy" — to an Action, reporting whether it names a real one.
Config-file parsers need this: KeyMap silently ignores unknown actions (so a map built in code can't panic), which would turn a typo in a user's config into a binding that mysteriously does nothing. Checking here lets the embedder log it instead. Matching is exact; no fuzzy resolution.
type ActivityKind ¶ added in v0.7.0
type ActivityKind int
ActivityKind labels what a Cfg.OnActivity callback observed. A bell outranks plain output: a read that both drew text and rang the bell reports ActivityBell, because that is the one a pane manager must surface.
const ( // ActivityOutput is child output that changed the screen. Output that // changes nothing — a query the parser answers, a no-op sequence — does // not count, so an idle full-screen app does not read as busy. ActivityOutput ActivityKind = iota // ActivityBell is a BEL the child emitted, whatever BellMode does with it. ActivityBell )
type BellMode ¶ added in v0.7.0
type BellMode int
BellMode selects how a BEL (0x07) is signalled to the user.
const ( // BellAuto plays the system alert sound where the platform has one // and falls back to the visual flash where it does not (mobile, // wasm, Linux without canberra-gtk-play). This is the zero value: // an audible bell matches what native terminals do, respects the // user's system alert-sound and mute settings, and does not disturb // what is on screen. BellAuto BellMode = iota // BellAudible plays the system alert sound only, with no visual // fallback — silent on platforms that cannot beep. BellAudible // BellVisual flashes the pane only, never plays a sound. BellVisual // BellBoth flashes and plays the alert sound. BellBoth // BellNone ignores BEL entirely. BellNone )
type Cfg ¶
type Cfg struct {
// OnTitle, if non-nil, receives OSC 0/1/2 window-title updates
// on the main goroutine. When nil, the widget calls
// win.SetTitle directly, which is appropriate for standalone
// single-Term windows. Embedders that manage their own title bar
// (or multiple Term instances) should set OnTitle to capture
// per-terminal titles.
OnTitle func(string)
// OnNotify, if non-nil, is called for OSC 9 / OSC 777 desktop
// notification requests. title may be empty (OSC 9). When nil,
// the widget fires a native OS notification via osascript (macOS),
// notify-send (Linux), or a WinRT toast (Windows). Called on a
// background goroutine — safe to block.
OnNotify func(title, body string)
// OnActivity, if non-nil, is called on the main thread when the child
// produces output that changed the screen, or rang the bell. A pane
// manager uses it to mark background tabs — see term/workspace, which
// derives its activity, bell, and silence indicators from this one hook.
//
// It fires at most once per PTY read, not once per cell, and is not a
// change feed: consecutive output collapses into a single call, and the
// kind reports what that read contained rather than everything since the
// last call. Callers that need the screen contents should read the grid
// on the next draw instead.
OnActivity func(kind ActivityKind)
// CursorBlink, if non-nil, overrides the application's DECSCUSR
// blink request. Use *true to force blinking on, *false to force
// steady. Leave nil to honor whatever the shell asks for (steady
// by default for a brand-new grid).
CursorBlink *bool
// OnExit, if non-nil, is called when the child process exits.
// Runs on the reader goroutine — fire a goroutine for any slow
// work (e.g. calling Term.Close on the main thread via QueueCommand).
OnExit func()
// OnClickFocus, if non-nil, is called when the user clicks on the
// terminal canvas. Multi-Term embedders use this to switch focus to
// the clicked pane. Runs synchronously during the click handler.
OnClickFocus func()
// OnInput, if non-nil, is called on the main thread with every byte
// sequence this pane sends to its child as a direct result of user
// input. It runs alongside the local write and cannot suppress it — it
// exists so a pane manager can mirror input to sibling panes (broadcast
// mode). Mouse reporting, focus reports and pty replies are deliberately
// excluded: those describe *this* pane's viewport and would be wrong
// anywhere else.
//
// p is owned by the widget and is only valid for the duration of the
// call; copy it if it must outlive the callback. Neither Term.Write nor
// Term.SendInput — the method that replays what this tap hands out —
// fires the hook, so a mirrored write cannot re-enter it.
OnInput func(p []byte, kind InputKind)
// Command overrides the shell command. When empty (default), $SHELL
// from the environment is used (with /bin/sh as fallback). Set this
// to spawn a custom binary in the pty instead of a shell.
Command string
// Themes, if non-empty, adds a right-click context menu for selecting
// a color theme at runtime. The first entry is used as the initial theme.
Themes []NamedTheme
// Args supplies arguments when Command is set. When Command is empty,
// Args are passed to the default shell (e.g. []string{"-c", "htop"}).
Args []string
// Env appends to the child process environment. When nil or empty,
// the child inherits os.Environ() plus TERM=xterm-256color, and — on
// unix, only when the inherited environment sets no LC_ALL/LC_CTYPE/LANG
// — a UTF-8 LANG so wide characters survive. Entries are appended after
// the inherited environment, so they override inherited values. Use
// "KEY=" (trailing equals) to unset.
Env []string
// Identity names this terminal to children via TERM_PROGRAM, replacing
// whatever emulator the host ran under (see setTerminalIdentity). Empty
// (default) advertises "go-term". Embedders that implement the same
// capability profile as a known emulator can set that name here so
// children that key their behavior off TERM_PROGRAM — yazi and superfile
// pick their image protocol from it — get the right one. cfg.Env is
// applied after, so an Env entry still wins.
Identity string
// TextStyle overrides the default monospace text style. When set to
// the zero value, the widget falls back to gui.CurrentTheme().M5.
// To use a custom style you must set at least one field (typically
// Size or Typeface) — a zero-value TextStyle is treated as "unset."
TextStyle gui.TextStyle
// ScrollbackRows caps the number of scrollback rows. The meaning
// depends on the sign:
//
// - Zero (the default): use defaultScrollbackRows (5000).
// - Positive: use this many rows, clamped to [1, MaxScrollbackCap].
// - Negative: disable scrollback entirely (ScrollbackCap = 0).
//
// Disabling scrollback saves memory for short-lived embedded
// widgets that never need history.
ScrollbackRows int
// BellMode selects how a BEL (0x07) is signalled to the user. The
// zero value plays the system alert sound, falling back to the
// visual flash only where no such sound exists.
BellMode BellMode
// BellFlashDuration overrides how long the visual-bell overlay stays
// visible. Zero (default) uses the built-in 100 ms. Negative disables
// the visual bell entirely. Only consulted when BellMode actually
// flashes.
BellFlashDuration time.Duration
// ScrollbarWidth overrides the pixel width of the scrollbar thumb.
// Zero (default) uses the built-in 4 px. Negative hides the scrollbar.
ScrollbarWidth float32
// NotifyAfter fires a desktop notification when a command that ran at
// least this long finishes while the user is looking elsewhere — the
// window is in the background, or (under a pane manager) this pane is not
// the active one. Zero (the default) or negative disables it; a positive
// value below one second is raised to one second.
//
// Commands are delimited by the OSC 133 marks a shell emits only once its
// integration hooks are installed (scripts/shell-integration/), so this
// does nothing under an unconfigured shell. Term.SetNotifyAfter changes
// it on a live terminal.
NotifyAfter time.Duration
// MinimumContrast is the WCAG contrast ratio (1.0–21.0) a cell's
// foreground is forced to reach against its background at render time. Any
// value at or below 1 (the default) disables the clamp.
//
// It exists because a truecolor SGR is not themeable: an app that emits
// colors chosen for a dark background — eza, starship, most `ls` themes —
// hands a light theme text at 1.5:1 that no palette setting can fix. The
// grid keeps the color the child sent, so copy, search and recording are
// unaffected; only what is painted changes. 3.0 is a reasonable setting,
// 4.5 is the WCAG floor for body text.
MinimumContrast float64
// MiddleClickPaste enables pasting with the middle mouse button: the X11
// PRIMARY selection where one exists, the clipboard otherwise. Off by
// default because it is a Unix convention rather than a universal one —
// term/workspace turns it on for Linux when the config file says nothing,
// keeping the platform policy out of the widget.
//
// Only consulted when the application has not enabled mouse reporting; a
// child that asked for mouse events always receives the middle button.
MiddleClickPaste bool
// AllowOSC52Write permits host applications to write the system clipboard
// via OSC 52. Disabled by default so untrusted terminal output cannot
// silently replace the user's clipboard.
AllowOSC52Write bool
// DisableGraphics, when true, skips Sixel, Kitty, and iTerm2 inline
// image decoding and rendering. Use to reduce memory/CPU in panes
// that don't need image support.
DisableGraphics bool
// NoWindowHandler, when true, prevents New from installing this Term
// as a handler on w.OnEvent. Set this when a pane manager or other
// container owns the window-level event dispatch and will route
// events to individual Terms via HandleWindowEvent. The standalone
// (false) default is correct for single-Term windows.
NoWindowHandler bool
// OnDownload receives OSC 1337 File= transfers that are not inline
// images (iTerm2's imgcat -d, it2dl). name is a sanitized bare filename,
// never a path; data is the decoded payload. Runs on a background
// goroutine, so it may block on disk or network. When nil and DownloadDir
// is set, the built-in writer saves to that directory instead.
//
// Leaving both unset disables file transfers entirely, which is the
// default: untrusted terminal output must not create files on its own
// authority.
OnDownload func(name string, data []byte)
// DownloadDir is where OSC 1337 File= transfers are saved when
// OnDownload is nil. Created on first use. Empty (default) disables the
// built-in writer. Files land with 0600 permissions and a " (N)" suffix
// on name collisions; a transfer never overwrites an existing file.
DownloadDir string
// Dir sets the working directory for the child process. When non-empty
// and the path exists on disk, the shell starts there. Empty inherits
// the process CWD.
Dir string
// RecordPath, when non-empty, starts a session recording at that path
// as soon as the terminal opens (see Term.StartRecording). The file is
// overwritten. A failure to open it is logged, not fatal — a terminal
// that refuses to start because a debug artefact could not be written
// would be a poor trade.
RecordPath string
// RecordInput adds keystrokes and pastes to session recordings as 'i'
// frames. Off by default: input capture records whatever the user
// types, including into a password prompt, so it must be asked for.
// Replay ignores 'i' frames; they are context for a human reader.
RecordInput bool
// KeyBindings overrides the default chords for Term-level actions (copy,
// paste, find, scrollback, font zoom). A nil or empty map leaves every
// built-in binding in place; entries override only the actions they name.
// A gui.Shortcut with Key == 0 unbinds its action so the key reaches the
// child process instead.
//
// This seeds the initial table only. Term.SetKeyBindings changes bindings
// on a live terminal — a settings UI or config reload must use that, since
// Cfg is never re-read after New.
KeyBindings KeyMap
}
Cfg configures a Term widget. All fields are optional.
Example ¶
package main
import (
"github.com/go-gui-org/go-term/term"
)
func main() {
cfg := term.Cfg{
ScrollbackRows: 10000,
AllowOSC52Write: true, // trusted environment
// Themes[0] seeds the grid and decides the child's COLORFGBG, so the
// theme to start in goes first; the rest are what the theme browser
// offers. term.BundledThemes returns every theme go-term ships.
Themes: append(
[]term.NamedTheme{{Name: "Default", Theme: term.DefaultTheme}},
term.BundledThemes()...,
),
}
_ = cfg // cfg is passed to term.New
}
Output:
type Fixture ¶
type Fixture struct {
Name string `json:"name"`
InputB64 string `json:"input_b64"`
WantTitle string `json:"want_title,omitempty"`
WantCwd string `json:"want_cwd,omitempty"`
WantLines []string `json:"want_lines"`
Rows int `json:"rows"`
Cols int `json:"cols"`
WantRow int `json:"want_row"`
WantCol int `json:"want_col"`
}
Fixture is a replay-test scenario used by the emulator conformance test harness and the script2fixture CLI tool. It is public so that external test packages (term_test) can use it, but it is not part of the widget's public API — embedders should not depend on it, and it carries no compatibility guarantee: it can change or move to term/termtest without a major-version bump.
Input bytes are base64-encoded so control characters survive any text editor round-trip.
func CaptureFixture ¶
CaptureFixture feeds raw terminal bytes through a fresh Grid+Parser and returns a Fixture representing the final state. This is test infrastructure — used by the script2fixture CLI tool and the fixture_capture test helper — and is not part of the widget's public API: no compatibility guarantee (see Fixture).
type InputKind ¶ added in v0.7.0
type InputKind int
InputKind labels the user-input path a Cfg.OnInput callback observed, and selects how Term.SendInput replays it. The two are distinguished because a paste cannot simply be copied to another pane: bracketed paste (DEC ?2004) is a mode each child enables for itself, so the markers have to be applied per receiver.
type KeyMap ¶ added in v0.7.0
KeyMap overrides the default chord for individual Actions. Actions absent from the map keep their defaults. An entry whose gui.Shortcut has Key == 0 (gui.KeyInvalid) unbinds the action entirely, so that key reaches the child process instead of being intercepted.
An override replaces the action's whole default chord list with the single given chord, but inherits the action's Shift tolerance — see binding.
type NamedTheme ¶
NamedTheme pairs a display name with a Theme for use in menus.
func BundledThemes ¶ added in v0.7.0
func BundledThemes() []NamedTheme
BundledThemes returns every color theme shipped with go-term, sorted case-insensitively by name. The table is decoded once on first call and cached; callers must not mutate the returned slice.
These are generated from the Ghostty-format schemes in mbadolato/iTerm2-Color-Schemes (MIT). See docs/themes.md for the full name list and attribution.
type ReplayCfg ¶ added in v0.7.0
type ReplayCfg struct {
// Path is the .gtr recording to play. Required.
Path string
// Speed multiplies playback rate: 2 plays twice as fast. Zero or
// negative means 1 (real time).
Speed float64
// IdleLimit caps any single gap between frames, so a session with a
// coffee break in the middle stays watchable. Zero means no cap.
IdleLimit time.Duration
// Loop restarts from the beginning at end of stream instead of holding
// on the final frame.
Loop bool
// Controls interprets keystrokes as playback commands rather than
// discarding them: space pauses/resumes, +/- change speed, . or Right
// steps one frame, 0 restarts.
Controls bool
}
ReplayCfg configures NewReplay.
type ShortcutInfo ¶ added in v0.4.0
type ShortcutInfo struct {
Label string
Keys string // human-readable, platform-formatted (macOS glyphs on darwin)
// Action identifies the entry so a caller can act on it — a command palette
// needs to invoke what it lists, not just print it. A pure cheatsheet can
// ignore this field.
Action Action
}
ShortcutInfo describes one Term-level keyboard shortcut for display in a help / cheatsheet overlay.
The Term handles these shortcuts imperatively in onKeyDown (see handleSearchKey, handleClipboardKey, scrollbackIntercept) because each needs conditional passthrough to the child process — e.g. plain Ctrl+C must still send SIGINT, and Cmd+C only copies when a selection exists. A declarative command registry can't own that dispatch. The binding table in this file owns only the *matching*, which is why it can be data; the conditional passthrough stays in the handlers.
func Shortcuts ¶ added in v0.4.0
func Shortcuts() []ShortcutInfo
Shortcuts returns the *default* Term-level keyboard shortcuts in display order. Embedders that let users rebind should call Term.Shortcuts instead, which reflects the overrides actually in effect.
Workspace-level shortcuts (tabs, panes, theme) live in the workspace command registry and are listed separately by the help overlay.
type Term ¶
type Term struct {
// contains filtered or unexported fields
}
Term is a terminal-emulator widget bound to a single pty-backed shell. Use New to construct, View to embed in a layout, Close to tear down.
func New ¶
New starts a shell in a pty and returns a Term widget. The reader goroutine and auxiliary loops (blink, auto-scroll, momentum) are spawned before New returns. Call Close to tear down.
Example ¶
package main
import (
"github.com/go-gui-org/go-gui/gui"
"github.com/go-gui-org/go-term/term"
)
func main() {
// In a real app, win comes from gui.NewWindow.
var win *gui.Window
t, err := term.New(win, term.Cfg{})
if err != nil {
panic(err)
}
defer func() { _ = t.Close() }()
win.UpdateView(t.View)
}
Output:
func NewReplay ¶ added in v0.7.0
NewReplay returns a Term that plays back a recorded session instead of spawning a shell. cfg is honored as for New except that no child process exists: Cfg.Command, Args, Env, and Dir are ignored.
The Term stays alive on the final frame rather than tearing down at end of stream, so the last screen remains on display; Close ends playback.
func (*Term) AdjustFontSize ¶ added in v0.5.0
AdjustFontSize shifts the terminal font size by delta points and triggers a full remeasure + redraw. Clamps the result to [4, 72] pt. Main-thread only (called from onKeyDown, which writes cellW/runeCache without grid.Mu — onDraw is the only concurrent reader and also runs on the main thread).
func (*Term) Alive ¶
Alive reports whether the child process is still running. Returns false after the PTY reader goroutine exits (process death or Close).
func (*Term) AvailableShortcuts ¶ added in v0.7.0
func (t *Term) AvailableShortcuts() []ShortcutInfo
AvailableShortcuts returns the Term-level shortcuts that would actually do something right now: the ordinary actions always, plus the copy-mode actions only while copy mode is active.
This is the list a command palette should show. Shortcuts is the wrong source for that — it is the flat cheatsheet, and it deliberately omits the copy-mode keys so the help overlay does not grow by twenty rows. The mode gating lives here rather than behind an exported "is copy mode on" query, because whether an action is live is this package's business, not the embedder's.
func (*Term) Close ¶
Close stops the shell, reader, and blink goroutine. Safe to call once; subsequent calls are no-ops. Must be called from the GUI main thread so that pending QueueCommand callbacks and resizeTimer fire on the same goroutine that owns them.
Example ¶
package main
import (
"github.com/go-gui-org/go-gui/gui"
"github.com/go-gui-org/go-term/term"
)
func main() {
var win *gui.Window
t, err := term.New(win, term.Cfg{})
if err != nil {
panic(err)
}
// Always close to clean up the PTY and goroutines.
_ = t.Close()
}
Output:
func (*Term) Cwd ¶
Cwd returns the most recent working directory reported via OSC 7, or "" if the shell has never emitted one. Typical payload format is "file://host/path"; embedders parse as needed.
Example ¶
package main
import (
"github.com/go-gui-org/go-gui/gui"
"github.com/go-gui-org/go-term/term"
)
func main() {
var win *gui.Window
t, _ := term.New(win, term.Cfg{})
// Cwd returns the shell's last-reported working directory.
cwd := t.Cwd()
_ = cwd
}
Output:
func (*Term) FocusID ¶ added in v0.4.0
FocusID returns the go-gui focus ID for this terminal.
Multi-Term contract: every Term has a unique, stable focus ID for the lifetime of its view tree. In a window hosting several Terms, the embedder calls SetFocused to route gui focus to the active pane and can read this ID after a click to learn which pane the user actually hit. The ID is unique per Term — never compare two Terms' IDs for equality to detect identity; use pointer equality instead. Only valid while the Term is alive and its View has been added to a window.
func (*Term) FontSize ¶ added in v0.7.0
FontSize returns the effective font size in points — the runtime zoom override when set, otherwise the configured TextStyle.Size. Main-thread only (reads style() without grid.Mu, like AdjustFontSize).
func (*Term) HandleWindowEvent ¶
HandleWindowEvent processes window-level events that the Term needs to see: momentum cancellation on mouse-down/trackpad-touch, and focus- reporting sequences (CSI I / CSI O) when the shell has enabled focus reporting (DECSET ?1004). A pane manager calls this on the focused Term when the window dispatches an event. When Cfg.NoWindowHandler is false (the standalone default), New installs a wrapper that calls this automatically via w.OnEvent chaining.
func (*Term) KeyBindings ¶ added in v0.7.0
KeyBindings returns the chord currently bound to each Term-level action.
Actions with several default chords (Copy answers to both Cmd+C and Ctrl+Shift+C) report the first, since a KeyMap holds one chord per action; use Term.Shortcuts for display, which renders every alternative. Unbound actions are present with a zero-value gui.Shortcut, so the result round-trips through SetKeyBindings unchanged.
func (*Term) Recording ¶ added in v0.7.0
Recording reports whether a session recording is currently running. Safe to call from any goroutine.
func (*Term) ResetFontSize ¶ added in v0.7.0
func (t *Term) ResetFontSize()
ResetFontSize clears any runtime zoom, restoring the configured TextStyle.Size (or the theme default when no TextStyle was set). Main-thread only, same constraints as AdjustFontSize. A no-op when already unzoomed. After reset t.fontSize is 0; AdjustFontSize re-seeds it from style() on the next zoom, so subsequent zooming still works.
func (*Term) RunAction ¶ added in v0.7.0
RunAction invokes a Term-level action by name, and reports whether it ran. This is what lets a command palette act on the entries AvailableShortcuts hands it.
Dispatch goes through the actionDispatch table directly, not through chord synthesis, so an action a user has unbound from the keyboard is still invocable here — the chord is only the keyboard's handle on the action. AvailableShortcuts still lists only bound actions (each entry shows its chord), so the palette lists what the keyboard does and can run anything else by name.
"Ran" means the action had an effect in the current state, mirroring the keyboard path's conditional-passthrough rules: a copy-mode action outside copy mode does not run, copy needs a selection, and the scrollback page keys refuse to run on the alt screen (where the keyboard requires holding Shift to pass them through — a direct dispatch has no Shift to hold).
Main-thread only.
func (*Term) SendInput ¶ added in v0.7.0
SendInput injects user input into this pane's child as if it had been typed or pasted here. It is the receiving counterpart of Cfg.OnInput: what the tap hands out, SendInput takes back in, which is how a pane manager mirrors input to sibling panes (term/workspace broadcast mode).
kind is not decoration. InputKey bytes are already encoded and go through verbatim; InputPaste text is re-wrapped according to *this* pane's own bracketed-paste (DEC ?2004) state, because that is a mode each child enables for itself — copying the source pane's wrapper would feed a literal ESC[200~ to a pane that has it off.
Both kinds snap this pane back to the live view first, exactly as local typing does. A pane the user had scrolled into its scrollback must not sit frozen while its shell runs what was just sent to it.
Main-thread only, unlike Write. It deliberately does not fire Cfg.OnInput, so a mirrored write cannot re-enter the tap and loop between panes. p is not retained past the call.
func (*Term) SetBellMode ¶ added in v0.7.0
SetBellMode changes how BEL is signalled on a live terminal. Safe to call from the main thread at any time; the reader goroutine reads it atomically.
func (*Term) SetFocused ¶
SetFocused sets whether this terminal has pane focus. The pane manager calls this when the user switches between panes. When focused, the container claims keyboard focus (so go-gui routes keystrokes here) and the cursor renders normally. When unfocused, the cursor is dimmed. New defaults to focused=true for standalone use.
func (*Term) SetFontSize ¶ added in v0.7.0
SetFontSize sets the runtime zoom to an absolute size in points, clamped to [minFontSize, maxFontSize]. A value <= 0 clears the override (equivalent to ResetFontSize). Unlike seeding cfg.TextStyle.Size, this leaves the configured default intact, so a later ResetFontSize still returns to that default — which is why restore/split apply their inherited size through here rather than through Cfg. Main-thread only, same constraints as AdjustFontSize.
func (*Term) SetKeyBindings ¶ added in v0.7.0
SetKeyBindings replaces this terminal's Term-level shortcut overrides.
Actions absent from km revert to their built-in chords — km is the complete override set, not a patch on the current one, so a config reload can simply pass whatever the file now says without tracking what it said before. An entry whose gui.Shortcut has Key == 0 unbinds its action, letting that key reach the child process. Unknown action names are ignored.
This is the live counterpart to Cfg.KeyBindings, which only seeds the table at construction. Both funnel through the same merge, so a terminal configured either way behaves identically.
Main-thread only: onKeyDown reads the table without a lock, and both run on the main thread.
func (*Term) SetMiddleClickPaste ¶ added in v0.7.0
SetMiddleClickPaste enables or disables middle-click paste on a live terminal, mirroring Cfg.MiddleClickPaste. Main-thread only; takes effect on the next click, so a config reload needs no redraw.
func (*Term) SetMinimumContrast ¶ added in v0.7.0
SetMinimumContrast changes the render-time contrast floor on a live terminal, mirroring Cfg.MinimumContrast. A ratio at or below 1 turns the clamp off; a non-finite value is ignored. Main-thread only.
Takes grid.Mu because the foreground pass reads the ratio and the memo it keys, and the memo has to be dropped in the same critical section — entries computed under the old ratio are wrong, not stale.
func (*Term) SetNotifyAfter ¶ added in v0.7.0
SetNotifyAfter changes the long-running-command notification threshold on a live terminal, mirroring Cfg.NotifyAfter: zero or negative disables it, and a positive value below minNotifyAfter is raised to it. Safe to call from any goroutine.
The notification requires a shell that emits OSC 133 — see scripts/shell-integration/. Without those marks no command is ever timed and this setting has no effect.
func (*Term) SetScrollbackRows ¶ added in v0.7.0
SetScrollbackRows changes the scrollback cap on a live terminal. The sign convention matches Cfg.ScrollbackRows: zero restores the built-in default, positive sets that many rows (clamped to [0, MaxScrollbackCap]), negative disables scrollback entirely.
Shrinking trims the stored history immediately — keeping the newest rows and discarding the oldest — rather than waiting for eviction to catch up, so lowering the cap actually returns the memory. Safe to call from the main thread at any time; takes grid.Mu.
func (*Term) SetScrollbarWidth ¶ added in v0.7.0
SetScrollbarWidth changes the scrollbar thumb width in pixels. Mirrors Cfg.ScrollbarWidth: zero restores the built-in default, negative hides the scrollbar. A non-finite value is ignored. Main-thread only.
func (*Term) SetTextStyle ¶ added in v0.7.0
SetTextStyle replaces the terminal's base text style — family, size, typeface — and forces a remeasure. Mirrors Cfg.TextStyle: the zero value means "fall back to gui.CurrentTheme().M5".
This also clears any runtime zoom, exactly as ResetFontSize does. t.fontSize is an *absolute* size derived from the previous base and wins over cfg.TextStyle.Size in style(), so a pane zoomed to 14 pt would otherwise ignore a new configured size of 12 pt until the user pressed Cmd+0.
func (*Term) SetTheme ¶
SetTheme replaces the active color theme and schedules a redraw. Safe to call from the main thread at any time.
A child that subscribed with DECSET ?2031 is told when the theme's light/dark character flips, which is what lets a running neovim or delta re-pick its syntax palette instead of staying unreadable until it is restarted. Only on a flip: cycling between two dark themes changes nothing the notification can describe, and one report per keystroke of Cmd+Shift+T is noise in the child's input stream.
func (*Term) Shortcuts ¶ added in v0.7.0
func (t *Term) Shortcuts() []ShortcutInfo
Shortcuts returns this terminal's effective Term-level shortcuts, including any overrides from Cfg.KeyBindings or SetKeyBindings, in display order.
Goes through bindingTable so a Term built as a bare struct literal reports the defaults, matching what its key handlers would actually do.
func (*Term) StartRecording ¶ added in v0.7.0
StartRecording begins a session recording at path, overwriting any existing file. The recording captures pty output with timing, plus grid resizes, and can be replayed with NewReplay or the gotermrec tool.
Keystrokes are recorded only when Cfg.RecordInput is set. Returns an error if a recording is already running or the file cannot be created. Call from the GUI main thread.
func (*Term) StopRecording ¶ added in v0.7.0
StopRecording finishes and closes the current recording. It is a no-op when nothing is being recorded. Call from the GUI main thread.
type Theme ¶
Theme holds the 16 ANSI base colors plus default fg/bg for a terminal color scheme. Indices 0–7 are standard ANSI; 8–15 are bright variants. The 240 extended colors (16–255) are computed and not themeable — a child app can still recolor any of the 256 entries at runtime via OSC 4, which lands in the grid's override layer (see palOverrides), not here.
var DefaultTheme Theme
DefaultTheme is the theme a new grid starts with and the one used when an embedder configures no themes at all. It is a VS Code Dark+ approximation, and it is the only theme defined in Go: every other shipped theme comes from the generated table behind BundledThemes.
It stays hand-written because it is load-bearing beyond being a choice — init() mirrors its ANSI entries into the 256-color table for resolve's legacy index fallback, so it must exist before any theme is selected.
Read-only after init(); do not mutate. To customize, copy the struct: custom := DefaultTheme; custom.DefaultFG = myColor.
func (Theme) IsDark ¶ added in v0.7.0
IsDark reports whether the theme reads as a dark color scheme, by the luma of its DefaultBG.
Exported because an embedder has the same question the emulator does — a host that themes its own chrome (window borders, tab bar) has to match the pane it wraps, and deriving that from a copy of the luma rule would let the chrome disagree with what DSR ?996 tells the child. This is a snapshot of the theme as declared; a child that repainted the background with OSC 11 changes what the *grid* reports, not this.
func (Theme) SelectionBG ¶ added in v0.7.0
SelectionBG returns the highlight background this theme gives ordinary selected text — a cell sitting on the theme's own default background.
Exported for an embedder drawing chrome that has to match what the pane paints: the theme browser's preview uses it to show a real selection rather than an approximation of one. Cells with a non-default background (reverse video, a colored run) resolve differently; that case stays internal.
Source Files
¶
- action_dispatch.go
- bidi.go
- doc.go
- eaw_wide.go
- fixture.go
- graphics.go
- grid.go
- grid_alt.go
- grid_command.go
- grid_cursor.go
- grid_edit.go
- grid_graphics.go
- grid_hints.go
- grid_mark.go
- grid_rect.go
- grid_reflow.go
- grid_reset.go
- grid_scroll.go
- grid_search.go
- grid_selection.go
- grid_urls.go
- grid_virtual.go
- grid_word.go
- keybind.go
- kgp_diacritics.go
- kgp_placeholder.go
- latency.go
- palette.go
- palette_contrast.go
- palette_overlay.go
- parser.go
- parser_apc.go
- parser_csi.go
- parser_dcs.go
- parser_feed.go
- parser_limits.go
- parser_osc.go
- pointer.go
- pty.go
- pty_unix.go
- replay.go
- scrollback.go
- settings.go
- shortcut_other.go
- shortcuts.go
- themes_bundled.go
- widget.go
- widget_bell.go
- widget_cfg.go
- widget_clipboard.go
- widget_command_notify.go
- widget_copymode.go
- widget_download.go
- widget_draw.go
- widget_draw_graphics.go
- widget_draw_overlay.go
- widget_draw_text.go
- widget_font.go
- widget_hints.go
- widget_keyboard.go
- widget_loops.go
- widget_mouse.go
- widget_notify.go
- widget_record.go
- widget_scroll.go
- widget_state.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Command genthemes converts the Ghostty-format theme files shipped by mbadolato/iTerm2-Color-Schemes into go-term's compact bundled-theme table (term/themes_bundled.txt) and the user-facing name list (docs/themes.md).
|
Command genthemes converts the Ghostty-format theme files shipped by mbadolato/iTerm2-Color-Schemes into go-term's compact bundled-theme table (term/themes_bundled.txt) and the user-facing name list (docs/themes.md). |
|
Command gotermrec inspects, plays, and converts go-term session recordings (.gtr files produced by falcon --record, Cfg.RecordPath, or Term.StartRecording).
|
Command gotermrec inspects, plays, and converts go-term session recordings (.gtr files produced by falcon --record, Cfg.RecordPath, or Term.StartRecording). |
|
Command script2fixture converts a typescript file (produced by the Unix `script` command) into a replay fixture for the go-term test suite.
|
Command script2fixture converts a typescript file (produced by the Unix `script` command) into a replay fixture for the go-term test suite. |
|
Package workspace manages multi-terminal workspaces with tabs and splits.
|
Package workspace manages multi-terminal workspaces with tabs and splits. |