terminal

package
v1.54.1 Latest Latest
Warning

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

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

View Source
const BellCooldown = 2 * time.Second

BellCooldown coalesces bell bursts: one event rings one bell, but nothing guarantees a redraw does not repeat it right after.

Variables

This section is empty.

Functions

func MapControlKey

func MapControlKey(raw string, controlKeys map[string]string) (string, bool)

func NewKey

func NewKey() (string, error)

NewKey returns a fresh UUID-shaped tmux session name for coder panes and shells.

func RunWatch

func RunWatch(interval time.Duration, alive func() map[string]string, start func(tmuxName, id string) (chan struct{}, error))

RunWatch reconciles a set of live tmux sessions with one watcher goroutine each: alive lists the current tmux session names mapped to their public identifiers, start spawns a watcher and returns its stop channel. Blocks; run it in a goroutine.

func SanitizeName

func SanitizeName(raw string) (string, error)

SanitizeName converts a user-supplied display name into a tmux-safe slug.

func SendInput

func SendInput(t Target, mapper ControlMapper, target string, item Input) error

SendInput dispatches one queued user action to a tmux target. Exactly one field of item is non-empty.

func ValidateDimensions

func ValidateDimensions(cfg config.Config, rawCols, rawRows string) (int, int, error)

func ValidateIdentifier

func ValidateIdentifier(raw string) (string, error)

ValidateIdentifier ensures raw matches the strict tmux-safe alphabet.

func WatchOutput

func WatchOutput(tmuxName string, scan func(out []byte, marks []string)) (chan struct{}, error)

WatchOutput attaches a read-only control-mode client to a tmux session and feeds every output chunk to scan: the OSC-filtered bytes plus the payloads of completed OSC sequences. It never resizes, so pane geometry stays untouched. The returned channel stops the watcher when closed.

Types

type Attachment

type Attachment struct {
	Session       string
	Offset        int64
	Generation    int64
	Snapshot      []byte
	Cols          int
	Rows          int
	MouseTracking bool // program has mouse reporting on (wheel -> mouse events)
	MouseSGR      bool // program uses SGR mouse encoding (mode 1006)
	AltScreen     bool // alternate screen active (wheel -> cursor keys)
	AppCursor     bool // application cursor keys mode (DECCKM)
}

Attachment is one active browser stream against a tmux session.

type ControlInput

type ControlInput struct {
	Ctl *tmux.Control
	CLI *tmux.Client
	// Gone is returned when a send fails on an exited control client, so each
	// caller reports its own flavor of "not running" to the browser.
	Gone error
}

ControlInput routes keystrokes through a session's persistent control-mode connection (no fork per key) and falls back to the forking CLI for buffer pastes, which control mode can't express on a single command line. A send that fails after the control client has exited is reported as a gone session so the caller still answers 410 instead of a generic error.

func (ControlInput) PaneForeground

func (c ControlInput) PaneForeground(name string) (tmux.PaneForeground, error)

func (ControlInput) PasteLiteral

func (c ControlInput) PasteLiteral(name, text string) error

func (ControlInput) SendKey

func (c ControlInput) SendKey(name, key string) error

func (ControlInput) SendLiteral

func (c ControlInput) SendLiteral(name, text string) error

func (ControlInput) SendRaw

func (c ControlInput) SendRaw(name string, data []byte) error

type ControlMapper

type ControlMapper interface {
	Map(raw string) (string, bool)
}

ControlMapper translates UI control IDs to tmux key names.

func DefaultControlMapper

func DefaultControlMapper() ControlMapper

type ForegroundReporter

type ForegroundReporter interface {
	PaneForeground(name string) (tmux.PaneForeground, error)
}

ForegroundReporter is the optional Target capability behind Shift+Enter: both transports report the pane's foreground process, the fork-free control connection and the CLI fallback.

type Hub

type Hub struct {
	// contains filtered or unexported fields
}

Hub tracks the active browser streams per tmux session and owns the control-mode client backing each one. All state is guarded by mu.

func NewHub

func NewHub(cfg config.Config) *Hub

func (*Hub) Attach

func (h *Hub) Attach(name, rawCols, rawRows string) (Attachment, error)

attach opens (or reuses) the control client and returns a fresh snapshot together with the stream offset that immediately follows it.

func (*Hub) Clear

func (h *Hub) Clear(name string)

clear drops the stream state and closes the control client (the session is gone).

func (*Hub) Control

func (h *Hub) Control(name string) *tmux.Control

control returns the live control client backing a stream, or nil when no browser is attached (or it has exited). Input uses it to send keystrokes over the persistent connection instead of forking the tmux CLI per key.

func (*Hub) Delta

func (h *Hub) Delta(name string, offset int64) ([]byte, int64, bool)

delta returns the buffered bytes after offset. reset is true when the caller must re-snapshot because offset fell out of the ring.

func (*Hub) Detach

func (h *Hub) Detach(name string)

detach releases one browser stream and closes the control client after the last one.

func (*Hub) Exited

func (h *Hub) Exited(name string) bool

exited reports whether the control client for a stream has ended.

func (*Hub) Modes

func (h *Hub) Modes(name string) (tmux.PaneModes, bool)

Modes reads the pane's current terminal modes. A program switches into its full screen UI while somebody is already watching, and the browser has no way to see that in the stream: what it receives is rendered content, not the mode sequences. Without this, a page attached before the switch keeps scrolling like a normal screen, which for a coder means not at all.

func (*Hub) Refresh

func (h *Hub) Refresh(name string, generation int64) (Attachment, bool)

refresh returns a new snapshot when another browser reset this stream.

func (*Hub) Resize

func (h *Hub) Resize(name string, cols, rows int) error

resize drives the rendered size of an actively streamed session and republishes a fresh snapshot at that size. The republish matters twice: the cached size feeds the terminal-size event of every later resync (a stale cache would shrink the browser back), and programs that do not repaint on SIGWINCH (a plain shell prompt) would otherwise leave the old, smaller frame on screen until some other resync happens. Same settle-then-capture dance as Attach: TUIs repaint in bursts, a silent shell just lets the wait run out.

func (*Hub) Resnapshot

func (h *Hub) Resnapshot(name string) (Attachment, bool)

resnapshot recaptures the screen when a browser has fallen out of the delta ring. It bumps the generation so other streams realign too.

func (*Hub) ResumeLive

func (h *Hub) ResumeLive(name string)

resumeLive returns a frozen history view to the live bottom. It is a no-op when the stream is already live, so it is cheap to call before every keystroke.

func (*Hub) Scroll

func (h *Hub) Scroll(name, action string) bool

scroll moves the stream's history view by one action and republishes the resulting frame to all connected browsers via a generation bump. Scrolling to the bottom returns to the live view and resumes deltas.

func (*Hub) Updated

func (h *Hub) Updated(name string) (<-chan struct{}, bool)

updated returns the wake channel for a stream and whether it is still live.

type Input

type Input struct {
	Prompt  string
	Control string
	Text    string
	Paste   string
	Raw     string
}

Input is one queued user action; exactly one of the payload fields is non-empty.

type Target

type Target interface {
	SendRaw(name string, data []byte) error
	SendKey(name, key string) error
	SendLiteral(name, text string) error
	PasteLiteral(name, text string) error
}

Target is the minimal tmux input surface SendInput needs. Both the forking CLI client (*tmux.Client) and the persistent control client satisfy it, so input can take the fork-free path when a stream is attached.

Jump to

Keyboard shortcuts

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