vt

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 29 Imported by: 0

README

vt

Go Reference

tuios.dev/vt is a terminal emulator in Go. It reads the bytes a program writes to a terminal and keeps the screen they draw: the cells, their colours and attributes, the cursor, the scrollback and the modes. It is the emulator of tuios, where it runs every pane.

Use it to:

  • run a program in a test and check what it drew,
  • show a terminal inside a Bubble Tea program or another TUI,
  • keep a pane's screen in a server and send it to a client that attaches later.

What it covers:

  • VT100 to xterm sequences, with a conformance corpus in its tests.
  • Scrollback with reflow on resize.
  • The alternate screen, scroll regions, left and right margins, tab stops, character sets and selective erase.
  • Mouse modes and key encoding, with the kitty keyboard protocol and modifyOtherKeys.
  • Kitty graphics and sixel, OSC 8 links, OSC 133 shell marks, OSC 52 clipboard, desktop notifications and OSC 9;4 progress.
  • OSC 7501, the Program Status Protocol.

The default build is pure Go and needs no cgo. With the ghostty build tag, New returns an emulator backed by libghostty-vt instead, through cgo.

Install

go get tuios.dev/vt

It needs Go 1.26 or later. The go command reads the import path from tuios.dev.

Example

package main

import (
	"fmt"

	"tuios.dev/vt"
)

func main() {
	term := vt.New(40, 5)
	defer term.Close()

	// What a program prints goes in.
	term.Write([]byte("hello \x1b[1mworld\x1b[0m\r\n$ "))

	// The screen comes out, as text or cell by cell.
	fmt.Println(term.String())
	fmt.Println(term.CellAt(6, 0).Content) // "w", drawn bold
	fmt.Println(term.CursorPosition())     // column 2, row 1
}

Some sequences ask the terminal a question, such as the cursor position. Read returns the replies, and the host writes them back to the program. With a pseudo-terminal, copy them in a goroutine:

go io.Copy(ptmx, term)

A host that reads the program's output on one goroutine can call TakeResponses after each Write instead. It returns the queued replies and never blocks.

The API

  • Screen is the small interface most users need: Write, Read, Resize, Width, Height, CellAt, CursorPosition, Render, String and Close.
  • Terminal is the full interface that tuios uses. It adds the scrollback, the modes, key and mouse encoding, graphics, and the state a snapshot carries.
  • New and NewWithScrollback return the backend the build selected. NewEmulator returns the pure Go *Emulator.
  • Callbacks reports what a program asks of the host: a new title, a bell, a working directory, a clipboard write, a notification, and private OSC sequences.

Sub-packages:

  • tuios.dev/vt/snapshot captures an emulator's state, packs it for a wire or a file, and brings another emulator to the same state. Replay turns a state into the bytes that repaint it on any xterm-compatible terminal.
  • tuios.dev/vt/vtgen generates terminal input from a grammar, for fuzzing an emulator. A failure reduces to a script of named sequences a person can read.

Stability

The module is at v0. The API can change between minor versions. A change is listed in the release notes of the version that makes it.

Licence

MIT. The package started as a copy of the vt package of charmbracelet/x. See LICENSE and NOTICE.

Report a problem in the tuios issue tracker.

Documentation

Overview

Package vt is a terminal emulator. It reads the bytes a program writes to a terminal and keeps the screen they draw: the cells, their colours and attributes, the cursor, the scrollback and the modes.

New returns an emulator. Write feeds it what the program printed, and CellAt, String and Render read the screen. Read returns the replies the emulator sends the program, such as the answer to a cursor position query. Screen is the interface with those methods. Terminal is the full interface tuios uses, with the scrollback, the modes, key and mouse encoding, graphics and the state a snapshot carries. Callbacks reports what the program asks of the host, such as a new title.

The default build is pure Go and returns an *Emulator. With the ghostty build tag, New returns an emulator backed by libghostty-vt through cgo.

The sub-package snapshot captures an emulator's state and brings another emulator to the same state, and vtgen generates terminal input for fuzzing an emulator.

Example

A program's output goes in, and the screen comes out.

package main

import (
	"fmt"

	"tuios.dev/vt"
)

func main() {
	term := vt.New(40, 5)
	defer term.Close()

	_, _ = term.Write([]byte("hello \x1b[1mworld\x1b[0m\r\n$ "))

	fmt.Println(term.String())
	fmt.Println(term.CellAt(6, 0).Content) // "w", drawn bold
	fmt.Println(term.CursorPosition())     // column 2, row 1
}

Index

Examples

Constants

View Source
const (
	FallbackCellWidth  = 10
	FallbackCellHeight = 20
)

The cell size in pixels an emulator assumes until the host sets one with SetCellSize.

A program reads the pane's size in pixels from XTWINOPS 14 and 16 and from the mode 2048 resize report, and an SGR-pixel mouse report (mode 1016) is in the same pixels. A program that divides by the pixel size quits on a zero, so a pane no host has measured still gets a cell size. A host that sets the kernel's pixel size (TIOCGWINSZ) for an unmeasured pane uses the same one, so the sizes agree.

View Source
const (
	ModShift = uv.ModShift
	ModAlt   = uv.ModAlt
	ModCtrl  = uv.ModCtrl
	ModMeta  = uv.ModMeta
	ModHyper = uv.ModHyper
	ModSuper = uv.ModSuper

	ModCapsLock = uv.ModCapsLock
	ModNumLock  = uv.ModNumLock
)

Modifier keys.

View Source
const (
	KeyExtended         = uv.KeyExtended
	KeyUp               = uv.KeyUp
	KeyDown             = uv.KeyDown
	KeyRight            = uv.KeyRight
	KeyLeft             = uv.KeyLeft
	KeyBegin            = uv.KeyBegin
	KeyFind             = uv.KeyFind
	KeyInsert           = uv.KeyInsert
	KeyDelete           = uv.KeyDelete
	KeySelect           = uv.KeySelect
	KeyPgUp             = uv.KeyPgUp
	KeyPgDown           = uv.KeyPgDown
	KeyHome             = uv.KeyHome
	KeyEnd              = uv.KeyEnd
	KeyKpEnter          = uv.KeyKpEnter
	KeyKpEqual          = uv.KeyKpEqual
	KeyKpMultiply       = uv.KeyKpMultiply
	KeyKpPlus           = uv.KeyKpPlus
	KeyKpComma          = uv.KeyKpComma
	KeyKpMinus          = uv.KeyKpMinus
	KeyKpDecimal        = uv.KeyKpDecimal
	KeyKpDivide         = uv.KeyKpDivide
	KeyKp0              = uv.KeyKp0
	KeyKp1              = uv.KeyKp1
	KeyKp2              = uv.KeyKp2
	KeyKp3              = uv.KeyKp3
	KeyKp4              = uv.KeyKp4
	KeyKp5              = uv.KeyKp5
	KeyKp6              = uv.KeyKp6
	KeyKp7              = uv.KeyKp7
	KeyKp8              = uv.KeyKp8
	KeyKp9              = uv.KeyKp9
	KeyKpSep            = uv.KeyKpSep
	KeyKpUp             = uv.KeyKpUp
	KeyKpDown           = uv.KeyKpDown
	KeyKpLeft           = uv.KeyKpLeft
	KeyKpRight          = uv.KeyKpRight
	KeyKpPgUp           = uv.KeyKpPgUp
	KeyKpPgDown         = uv.KeyKpPgDown
	KeyKpHome           = uv.KeyKpHome
	KeyKpEnd            = uv.KeyKpEnd
	KeyKpInsert         = uv.KeyKpInsert
	KeyKpDelete         = uv.KeyKpDelete
	KeyKpBegin          = uv.KeyKpBegin
	KeyF1               = uv.KeyF1
	KeyF2               = uv.KeyF2
	KeyF3               = uv.KeyF3
	KeyF4               = uv.KeyF4
	KeyF5               = uv.KeyF5
	KeyF6               = uv.KeyF6
	KeyF7               = uv.KeyF7
	KeyF8               = uv.KeyF8
	KeyF9               = uv.KeyF9
	KeyF10              = uv.KeyF10
	KeyF11              = uv.KeyF11
	KeyF12              = uv.KeyF12
	KeyF13              = uv.KeyF13
	KeyF14              = uv.KeyF14
	KeyF15              = uv.KeyF15
	KeyF16              = uv.KeyF16
	KeyF17              = uv.KeyF17
	KeyF18              = uv.KeyF18
	KeyF19              = uv.KeyF19
	KeyF20              = uv.KeyF20
	KeyF21              = uv.KeyF21
	KeyF22              = uv.KeyF22
	KeyF23              = uv.KeyF23
	KeyF24              = uv.KeyF24
	KeyF25              = uv.KeyF25
	KeyF26              = uv.KeyF26
	KeyF27              = uv.KeyF27
	KeyF28              = uv.KeyF28
	KeyF29              = uv.KeyF29
	KeyF30              = uv.KeyF30
	KeyF31              = uv.KeyF31
	KeyF32              = uv.KeyF32
	KeyF33              = uv.KeyF33
	KeyF34              = uv.KeyF34
	KeyF35              = uv.KeyF35
	KeyF36              = uv.KeyF36
	KeyF37              = uv.KeyF37
	KeyF38              = uv.KeyF38
	KeyF39              = uv.KeyF39
	KeyF40              = uv.KeyF40
	KeyF41              = uv.KeyF41
	KeyF42              = uv.KeyF42
	KeyF43              = uv.KeyF43
	KeyF44              = uv.KeyF44
	KeyF45              = uv.KeyF45
	KeyF46              = uv.KeyF46
	KeyF47              = uv.KeyF47
	KeyF48              = uv.KeyF48
	KeyF49              = uv.KeyF49
	KeyF50              = uv.KeyF50
	KeyF51              = uv.KeyF51
	KeyF52              = uv.KeyF52
	KeyF53              = uv.KeyF53
	KeyF54              = uv.KeyF54
	KeyF55              = uv.KeyF55
	KeyF56              = uv.KeyF56
	KeyF57              = uv.KeyF57
	KeyF58              = uv.KeyF58
	KeyF59              = uv.KeyF59
	KeyF60              = uv.KeyF60
	KeyF61              = uv.KeyF61
	KeyF62              = uv.KeyF62
	KeyF63              = uv.KeyF63
	KeyCapsLock         = uv.KeyCapsLock
	KeyScrollLock       = uv.KeyScrollLock
	KeyNumLock          = uv.KeyNumLock
	KeyPrintScreen      = uv.KeyPrintScreen
	KeyPause            = uv.KeyPause
	KeyMenu             = uv.KeyMenu
	KeyMediaPlay        = uv.KeyMediaPlay
	KeyMediaPause       = uv.KeyMediaPause
	KeyMediaPlayPause   = uv.KeyMediaPlayPause
	KeyMediaReverse     = uv.KeyMediaReverse
	KeyMediaStop        = uv.KeyMediaStop
	KeyMediaFastForward = uv.KeyMediaFastForward
	KeyMediaRewind      = uv.KeyMediaRewind
	KeyMediaNext        = uv.KeyMediaNext
	KeyMediaPrev        = uv.KeyMediaPrev
	KeyMediaRecord      = uv.KeyMediaRecord
	KeyLowerVol         = uv.KeyLowerVol
	KeyRaiseVol         = uv.KeyRaiseVol
	KeyMute             = uv.KeyMute
	KeyLeftShift        = uv.KeyLeftShift
	KeyLeftAlt          = uv.KeyLeftAlt
	KeyLeftCtrl         = uv.KeyLeftCtrl
	KeyLeftSuper        = uv.KeyLeftSuper
	KeyLeftHyper        = uv.KeyLeftHyper
	KeyLeftMeta         = uv.KeyLeftMeta
	KeyRightShift       = uv.KeyRightShift
	KeyRightAlt         = uv.KeyRightAlt
	KeyRightCtrl        = uv.KeyRightCtrl
	KeyRightSuper       = uv.KeyRightSuper
	KeyRightHyper       = uv.KeyRightHyper
	KeyRightMeta        = uv.KeyRightMeta
	KeyIsoLevel3Shift   = uv.KeyIsoLevel3Shift
	KeyIsoLevel5Shift   = uv.KeyIsoLevel5Shift
	KeyBackspace        = uv.KeyBackspace
	KeyTab              = uv.KeyTab
	KeyEnter            = uv.KeyEnter
	KeyReturn           = uv.KeyReturn
	KeyEscape           = uv.KeyEscape
	KeyEsc              = uv.KeyEsc
	KeySpace            = uv.KeySpace
)

Key codes.

View Source
const (
	MouseNone       = uv.MouseNone
	MouseLeft       = uv.MouseLeft
	MouseMiddle     = uv.MouseMiddle
	MouseRight      = uv.MouseRight
	MouseWheelUp    = uv.MouseWheelUp
	MouseWheelDown  = uv.MouseWheelDown
	MouseWheelLeft  = uv.MouseWheelLeft
	MouseWheelRight = uv.MouseWheelRight
	MouseBackward   = uv.MouseBackward
	MouseForward    = uv.MouseForward
	MouseButton10   = uv.MouseButton10
	MouseButton11   = uv.MouseButton11
)

Mouse event buttons

This is based on X11 mouse button codes.

1 = left button
2 = middle button (pressing the scroll wheel)
3 = right button
4 = turn scroll wheel up
5 = turn scroll wheel down
6 = push scroll wheel left
7 = push scroll wheel right
8 = 4th button (aka browser backward button)
9 = 5th button (aka browser forward button)
10
11

Other buttons are not supported.

View Source
const (

	// SixelMaxDimension bounds either side of a decoded image in pixels. It
	// is larger than any screen, so a real picture is never cut by it.
	SixelMaxDimension = 8192
	// SixelMaxPixels bounds the area, at two bytes a pixel: 32 MiB.
	SixelMaxPixels = 16 << 20
)

Sixel limits. A guest controls every one of these numbers, so each is bounded before anything is allocated.

View Source
const Backend = "pure-Go"

Backend names the emulator implementation compiled into this binary. Both builds install under the same `tuios` name, so the binary has to be able to say which one it is; deriving it from the build tag keeps it honest, where a string injected at link time can be forgotten or set wrong.

View Source
const DefaultScrollbackSize = 10000

DefaultScrollbackSize is the default number of lines to keep in the scrollback buffer.

View Source
const DefaultTerminalName = "vt"

DefaultTerminalName is the program name XTVERSION reports until SetTerminalName sets another.

View Source
const KittyAnimationRefusal = "ENOTSUPPORTED:host terminal does not support animation"

KittyAnimationRefusal is the answer to a frame edit the host cannot make. A guest that gets it falls back to sending whole frames.

View Source
const KittyTempMarker = "tty-graphics-protocol"

KittyTempMarker is the text the kitty spec asks for in a t=t file name. It is for a host that reads such files itself.

View Source
const MaxHostLinkURI = 2083

MaxHostLinkURI is the longest address written to the host in an OSC 8, in bytes as written. It is VTE's limit, and the one the scrollback ring keeps links to. A longer link is drawn as plain text: the frame writes the address again each time the link starts on a row, and an OSC payload can be 4 MiB.

View Source
const MaxPendingInput = maxSequenceData + 4096

MaxPendingInput bounds PendingInput: the longest payload the emulator keeps of one sequence, and room for its introducer and parameters. The parser cuts a longer payload at the same length, so input cut there replays to the same state.

View Source
const SixelMarkerLead = "\xf4\x8e\xbb\xad"

SixelMarkerLead is the UTF-8 encoding of sixelMarkerRune, for a byte compare on the hot path.

View Source
const SixelMaxCells = sixelDigits - 1

SixelMaxCells bounds an image's rows and columns: a marker states them in one mark each.

View Source
const SixelMaxID = sixelDigits*sixelDigits - 1

SixelMaxID is the largest image id a marker can carry. Id 0 names no image: the cells are reserved and the compositor draws them blank.

View Source
const SixelMaxRegisters = 256

SixelMaxRegisters is the number of colour registers a pane is told it has (XTSMGRAPHICS), and the most a decoded image may use.

View Source
const SyncMaxHold = syncMaxHold

SyncMaxHold is how long a synchronized update is honored. It is for a host that holds a program's output during an update, as the tuios kitty passthrough holds a guest's graphics, so it waits no longer than this.

Variables

This section is empty.

Functions

func BlankSixelCell

func BlankSixelCell(c *uv.Cell) bool

BlankSixelCell turns an image cell into a blank that keeps its background. It reports whether the cell was one. It is for a host that keeps or copies cells without the image, such as a saved history.

func BuildKittyResponse

func BuildKittyResponse(ok bool, imageID uint32, message string) []byte

BuildKittyResponse returns a kitty graphics reply for imageID: OK when ok is true, otherwise message, or ENOENT when message is empty. An imageID of 0 leaves the i key out.

func CellText

func CellText(content string) string

CellText is a cell's content as text: a space for a sixel image cell, the content otherwise. Text that leaves the grid (a capture, a copy, a search, a saved history) reads cells through it, so no marker escapes as text.

func ClipHistoryRow

func ClipHistoryRow(line uv.Line, width int) uv.Line

ClipHistoryRow is a scrollback line as it may be drawn in width columns.

History keeps the width it was written at, deliberately: a resize reflows only the screen and the history lines it takes back (reflow.go), so that a resize costs what the screen holds and not what the history holds. A pane that narrowed since can then hold a double-width rune whose lead is in its last column. Drawn whole, that rune makes the row one column wider than the pane, and the compositor puts the extra column over the pane next door.

The fix belongs where the row is drawn and not in the history. Blanking the rune in the stored line, which a resize once did, lost it for good: a pane that narrowed and widened again showed a space where the character was, and so did every capture of it. So the stored line keeps the rune, and a reader that puts a history row into a grid of the pane's width passes it through here first. The screenshot grid is one, and the client's pane renderer is another. The renderer needs it too: the frame does cut an overlong row at the pane's border, but that cut drops the whole wide cell, so the last column lost its background, the copy cursor and any selection. The cut cell becomes a blank that keeps its style, so a run of coloured background does not gain a notch.

The line is returned as it is when nothing straddles the edge. Otherwise it is a copy, because the line can be the scrollback cache's own slice.

func DecodeKittyPayload

func DecodeKittyPayload(payload []byte) ([]byte, error)

DecodeKittyPayload decodes a kitty graphics payload, padded or not.

The protocol says the payload is base64 and leaves padding to the sender. kitten icat sends none: its Go encoder is RawStdEncoding, so the final chunk of a stream, and any file path whose length is not a multiple of three, has no '=' at the end. Only a chunk that is not the last has to be a multiple of four characters. Other senders (chafa, timg, mpv) pad. Both are accepted, and so is a payload built by joining padded groups, which is what a sender that pads every chunk produces if two chunks are ever sent as one.

Each run of '=' ends one group. The text before it is decoded without padding, which accepts a group with its padding stripped and rejects one that was cut short (a single character left over), and the rest of the payload is decoded the same way.

func DeviceAttributes

func DeviceAttributes(sixel bool) []int

DeviceAttributes is the DA1 attribute list both backends answer with: a VT220-class terminal (62) with ANSI colour (22), and sixel graphics (4) only when the pane's images will be shown. chafa, img2sixel's callers, lsix, timg, yazi, notcurses and matplotlib's sixel backends decide between sixel and a text fallback on that one attribute, so listing it when the picture would be dropped trades their fallback for a blank.

Every attribute listed is one a guest may act on, so only what is implemented is listed. 132 columns (1), selective erase (6), national replacement character sets (9), technical characters (15) and user windows (18) are left out, because none of them exists here: a pane cannot change its own width, no cell can be protected, and only the UK and DEC special graphics sets are designated. The class is 62, which is what kitty, ghostty and foot answer, so a program that reads the class to decide it is on a VT220 or later (vim, neovim, notcurses, tmux) finds one.

func EncodeKeyCSIu

func EncodeKeyCSIu(key KeyPressEvent, flags int) string

EncodeKeyCSIu encodes a key event in the CSI u format used by the kitty keyboard protocol. Returns the encoded sequence, or empty string if the key should use legacy encoding.

func EncodeKeyReleaseCSIu

func EncodeKeyReleaseCSIu(key KeyPressEvent, flags int) string

EncodeKeyReleaseCSIu encodes a key release for a pane that asked to be told about them, and returns "" for one that did not.

Only the event-type flag makes a release reportable, and it is the flag a compositor running in a pane cannot do without: a Wayland client is told a key is down and waits to be told it came up, so a dropped release leaves the key held and xkb repeating it forever. The press form is unchanged by the flag (kitty sends a bare \x1b[97u for the press and \x1b[97;1:3u for its release), so the release always carries the modifier field, even when empty, because the event type rides on it as a subparameter.

func EncodeModifyOtherKeys

func EncodeModifyOtherKeys(key KeyPressEvent, level int) string

EncodeModifyOtherKeys encodes a key press the way xterm does under modifyOtherKeys, as CSI 27 ; modifier ; code ~, or returns "" when the key keeps its ordinary encoding at that level. Only the "other" keys take part: characters, Space, Tab, Enter, Backspace and Escape. Cursor, editing, keypad and function keys already carry their modifiers in their own sequences.

Level 2 encodes every modified key whose ordinary form would lose the modifier, which is every one but a shifted character, and Shift+Tab, which has CSI Z. Level 1 leaves the keys with well-known behaviour alone: a Ctrl or Shift chord that makes a control character (Ctrl+A is 0x01), Alt with a character (ESC prefix), and Backspace.

The kitty keyboard protocol is the richer of the two, so a pane with kitty flags set does not reach this encoder.

func EncodePaneKey

func EncodePaneKey(key KeyPressEvent, kittyFlags, modifyOtherKeys int) string

EncodePaneKey encodes a key press in the keyboard mode a pane asked for, or returns "" when the key keeps its legacy encoding in that mode. kittyFlags is the pane's kitty keyboard flags and modifyOtherKeys its XTMODKEYS level.

The kitty flags win when a pane set both: the protocol says so, and a pane with flags set has chosen CSI u. modifyOtherKeys is xterm's older way to ask for keys the legacy encoding cannot tell apart.

Every route that writes a key press to a pane goes through here, so a key a person types and the same key sent with send-keys reach the pane as the same bytes.

func EncodeSixel

func EncodeSixel(img *SixelImage, src image.Rectangle, dstW, dstH int) []byte

EncodeSixel writes the part of img inside src as a complete sixel DCS sequence (ESC P ... ST), scaled to dstW by dstH pixels by nearest neighbour.

This is how a pane's picture is clipped. Sixel has no crop and no delete: whatever is sent is painted, from the cursor down and to the right. So when only part of an image is visible, because the pane is scrolled, covered by a popup or runs off the screen, tuios sends a new image holding just that part. The scale covers a host whose cells are a different size from the ones the guest drew for, which happens when several terminals share a session.

The palette is the image's own, renumbered to the registers the crop uses, so nothing is re-quantised. Unpainted pixels stay transparent (P2=1).

func IsKittyAnimationAction

func IsKittyAnimationAction(a KittyGraphicsAction) bool

IsKittyAnimationAction reports whether a is one of the frame edits: a=f, a=a and a=c. A host either makes them or refuses them.

func IsKittyEchoedResponse

func IsKittyEchoedResponse(cmd *KittyCommand) bool

IsKittyEchoedResponse reports whether a parsed graphics command is a terminal's reply coming back as input rather than a command from a guest.

The payload shape alone is not enough. A chunk of real image data can be all capital letters behind a leading E: a run of dark pixels encodes to "EAAAAAAA", and the last chunk of a chunked transmission is often short enough to pass the length cap. Dropping it as an echo left the transmission without its m=0, so the image never appeared. A reply carries no key but the ids (i=, I=, p=), and every transmission carries at least one other key (a=, f=, s=, v=, t= on the first chunk, m= on every later one), so a command is an echo only when it has the reply's keys and the reply's payload.

func IsKittyPlaceholder

func IsKittyPlaceholder(content string) bool

IsKittyPlaceholder reports whether a cell's content is a placeholder cell.

This is asked of every cell the emulator prints and of every style run the dim blends, so it leaves the hot path on a byte compare: U+10EEEE is F4 8E BB AE in UTF-8, and no ordinary character starts with F4.

func IsKittyResponsePayload

func IsKittyResponsePayload(payload string) bool

IsKittyResponsePayload reports whether a graphics payload looks like an echoed kitty protocol response rather than image data.

It is matched against the raw wire payload (the base64 text between ';' and the APC terminator), not the decoded bytes. A real transmit payload is a base64 string; an echoed response is a short status token: "OK", or a POSIX error name optionally followed by a ":message" (e.g. "ENOENT", "EINVAL:bad params"). Matching the decoded bytes instead let arbitrary binary chunks (a chafa or mpv direct stream) collide with the 'E'+A-Z shape about 0.04% of the time and silently drop a chunk, corrupting the image.

The shape required is ^(OK|E[A-Z]+(:.*)?)$ with a hard length cap so that a legitimate (necessarily longer, mixed-case) base64 payload cannot match.

func IsSixelMarker

func IsSixelMarker(content string) bool

IsSixelMarker reports whether a cell's content is a sixel image cell. It is a byte compare, cheap enough for every cell of every frame.

func KittyInTempDir

func KittyInTempDir(path string) bool

KittyInTempDir reports whether path lies in a temporary directory: /tmp, /var/tmp, /dev/shm, or the one TMPDIR names.

func KittyMediumIsFrame

func KittyMediumIsFrame(cmd *KittyCommand, info os.FileInfo) bool

KittyMediumIsFrame reports whether info describes the object that cmd, a shared memory (t=s) or temp file (t=t) transmission, hands to the terminal. Only then may a reader that did not create the object delete it.

The name in a transmission is text the pane printed. Any program in the pane can print a name, including the name of an object another program still uses. So a name alone is no proof, and a delete needs all of these:

  • the object is a regular file;
  • this user owns it;
  • its size is the size the command describes: O+S when S is given, or O+s*v*3 for f=24 and O+s*v*4 for f=32 when it is not.

A compressed (o=z) or PNG (f=100) frame without S has no size to compare, so it is never deleted.

func KittyPayloadErrorResponse

func KittyPayloadErrorResponse(cmd *KittyCommand) []byte

KittyPayloadErrorResponse is the reply owed to a guest whose command carried a payload that could not be decoded, or nil when none is owed.

kitty answers an error unless the guest asked for silence with q=2, and only when the command names its image with i= or I=, because a reply without an id cannot be matched to anything. A query is the exception: it is answered with or without an id, the way tuios has always answered it, because a probing guest waits for that reply.

A payload shaped like a reply ("EINVAL:...") is a guest echoing one back, usually a shell that received it as input. Answering that would echo again, forever, so it gets nothing.

func KittyPlaceholderImageID

func KittyPlaceholderImageID(content string, fg color.Color) (uint32, bool)

KittyPlaceholderImageID returns the image id a placeholder cell names. Tests outside this package read cells through it.

func KittySensitivePath

func KittySensitivePath(path string) bool

KittySensitivePath reports whether path lies in a place no file medium may name.

func KittyTempDirs

func KittyTempDirs() []string

KittyTempDirs lists the temporary directories: the fixed ones and TMPDIR. TMPDIR is ignored when it is /, the home directory or a parent of it, since that would make every file of the user a temporary one. Inside the home directory it counts only under ~/tmp or ~/.tmp.

func LinkParams

func LinkParams(s string) string

LinkParams is a link's parameters made safe the same way. A byte outside printable ASCII, and ';', which would end them, is percent-encoded rather than dropped, so id=链 and id=接 stay two ids.

func LinkURI

func LinkURI(s string) string

LinkURI is a link's address as tuios keeps it in a cell and writes it to the host: without control bytes, and with every other byte outside printable ASCII percent-encoded, which a browser reads as the same address.

The OSC 8 spec allows only printable ASCII in a link's address. A raw UTF-8 address is not safe even with every control rune stripped: the continuation bytes of many runes are 0x80-0x9f, and a parser that reads 8-bit controls (charmbracelet/x/ansi, tmux, and the terminals that do the same) takes them as C1. 0x9c is ST, so the sequence ends in the middle of the address and the rest of it is printed as text. "术" is E6 9C AF. The row is then wider than the pane, and everything after it on screen is drawn in the wrong place. The cell keeps the encoded form, so every renderer that writes the cell back out, and a frame read back in, agree on the address.

func LinkURIDecodedLen

func LinkURIDecodedLen(s string) int

LinkURIDecodedLen is the length in bytes of a LinkURI address with its percent escapes decoded: the length of the address the program wrote.

func ParseSixelMarker

func ParseSixelMarker(content string) (id uint32, row, col int, ok bool)

ParseSixelMarker reads a marker cell back. It reports false for content that is not a complete marker, which the compositor then draws blank.

func SanitizePaste

func SanitizePaste(text string) string

SanitizePaste removes from text every character that could act as a terminal control rather than as pasted text: ESC, the other C0 controls except tab, line feed and carriage return, DEL, the C1 controls, and bytes that are not valid UTF-8.

The ESC is the one that matters. Text holding ESC[201~ ends a bracketed paste early, and whatever follows reaches the application as typed input, so a shell runs it. The text can come from anywhere a pane can reach: an OSC 52 write, a hint match, a line of scrollback. xterm and kitty strip the same characters from a paste for the same reason. The rest go too because a paste is text, and a lone BEL, NUL or C1 CSI in it is never what the person meant to type.

func SetBuildVersion

func SetBuildVersion(v string)

SetBuildVersion records the version XTVERSION reports after the program name. Call it once, before the first pane starts.

func SetDebugLogger

func SetDebugLogger(l Logger)

SetDebugLogger sets a process-wide logger for diagnostic lines that no single emulator owns, such as every XTWINOPS request a program sends. It is nil by default, and then nothing is formatted. Each line is one message without a trailing newline. Call it once at startup, before the first emulator exists.

func SetHostHyperlink(url, params string) string

SetHostHyperlink returns the OSC 8 that opens a link in a frame written to the host, with LinkURI and LinkParams applied, or "" for an address longer than MaxHostLinkURI. A cell the vt emulator filled is already encoded. A bare URL tuios finds in the text, and a cell from another backend, may not be. It is for a host that writes the cells to its own terminal.

func SetTerminalName

func SetTerminalName(name string)

SetTerminalName sets the program name XTVERSION reports. An empty name restores DefaultTerminalName. Call it once, before the first pane starts.

func SixelCells

func SixelCells(cmd *SixelCommand, cellW, cellH int) (rows, cols int)

SixelCells returns the rows and columns an image covers at the given cell size, bounded so a marker can state every one of them.

func SixelMarker

func SixelMarker(id uint32, row, col int) string

SixelMarker is the cell content for row and column of image id. The sixel marker functions are the cell format of a sixel image, for a host that draws the cells.

func StripControls

func StripControls(s string) string

StripControls returns s without C0 controls, DEL, C1 controls (as raw bytes or UTF-8 encoded) and bytes that are not valid UTF-8.

A link's address and parameters are written back out to the host terminal inside its own OSC 8 when the frame is drawn. The parser already ends the sequence at ESC and BEL, but a raw 0x9c is ST to a terminal that reads 8-bit controls, and none of these belong in a link.

func StripKittyPlaceholders

func StripKittyPlaceholders(s string) string

StripKittyPlaceholders returns s with each placeholder cell, U+10EEEE and the row, column and id marks after it, written as one space. A placeholder is a piece of a picture, and text that leaves the grid (a capture) has no use for it. s is returned as it is when it holds none.

func StripSixelMarkers

func StripSixelMarkers(s string) string

StripSixelMarkers replaces every sixel marker in s with a space, for text that leaves the grid as text: a copy, a search, a capture.

func XTVersionName

func XTVersionName() string

XTVersionName is the text an XTVERSION reply carries: the program name, followed by the build version when one was set. Both backends answer with it, so a guest that picks its features by terminal name sees the same name on either.

Types

type ApcHandler

type ApcHandler func(data []byte) bool

ApcHandler is a function that handles an APC escape sequence.

type Callbacks

type Callbacks struct {
	// Bell callback. When set, this function is called when a bell character is
	// received.
	Bell func()

	// Title callback. When set, this function is called when the terminal title
	// changes.
	Title func(string)

	// IconName callback. When set, this function is called when the terminal
	// icon name changes.
	IconName func(string)

	// AltScreen callback. When set, this function is called when the alternate
	// screen is activated or deactivated.
	AltScreen func(bool)

	// CursorPosition callback. When set, this function is called when the cursor
	// position changes.
	CursorPosition func(old, new uv.Position) //nolint:predeclared,revive

	// CursorVisibility callback. When set, this function is called when the
	// cursor visibility changes.
	CursorVisibility func(visible bool)

	// CursorColor callback. When set, this function is called when the cursor
	// color changes. Nil indicates the default terminal color.
	CursorColor func(color color.Color)

	// BackgroundColor callback. When set, this function is called when the
	// background color changes. Nil indicates the default terminal color.
	BackgroundColor func(color color.Color)

	// ForegroundColor callback. When set, this function is called when the
	// foreground color changes. Nil indicates the default terminal color.
	ForegroundColor func(color color.Color)

	// WorkingDirectory callback. When set, this function is called when the
	// current working directory changes.
	WorkingDirectory func(string)

	// EnableMode callback. When set, this function is called when a mode is
	// enabled.
	EnableMode func(mode ansi.Mode)

	// DisableMode callback. When set, this function is called when a mode is
	// disabled.
	DisableMode func(mode ansi.Mode)

	// ScreenClear callback. When set, this function is called when the screen
	// is cleared (ED 2 or ED 3).
	ScreenClear func()

	// ClipboardSet callback. Called when a guest app sets clipboard via OSC 52.
	ClipboardSet func(selection, content string)

	// ClipboardQuery callback. Called when a guest app queries clipboard via OSC 52.
	// Returns the current clipboard content for the given selection.
	ClipboardQuery func(selection string) string

	// Notify callback. Called when a guest app requests a desktop notification
	// via OSC 9, OSC 777, or OSC 99.
	Notify func(title, body string)

	// Progress callback. Called when a guest app reports its progress via the
	// OSC 9;4 sequence. percent is 0 for the states that carry no percentage.
	Progress func(state ProgressState, percent int)

	// ProgramStatus callback. Called for every OSC 7501 report that passed
	// every check of the Program Status Protocol, and with Reset set on a full
	// reset (RIS), which removes every record. The feature detection query is
	// answered by the emulator and never reaches it. Like SemanticMark it fires
	// with the emulator's lock held on backends that have one, so it must only
	// record.
	ProgramStatus func(ev progstatus.Event)

	// SemanticMark callback. Called for every OSC 133 mark a shell sends (A
	// prompt start, B input start, C command executed, D command finished),
	// after the mark is recorded in SemanticMarkers. A C mark carries the
	// command line read off the screen and a D mark its exit code, -1 when the
	// shell sent none. It fires with the emulator's lock held on backends that
	// have one, so it must only record and never call back into the terminal.
	SemanticMark func(mark SemanticMarker)

	// PrivateOSC callback. Called for an OSC sequence whose number the
	// emulator does not interpret, so a host can give meaning to a private
	// number of its own. cmd is the OSC number and data the whole body,
	// number included, as an [OscHandler] receives it. data is only valid for
	// the call. A sequence with no valid number, such as ESC ] foo BEL, is
	// not passed on. Both backends call it for the same numbers.
	PrivateOSC func(cmd int, data []byte)
}

Callbacks represents a set of callbacks for a terminal.

type CcHandler

type CcHandler func() bool

CcHandler is a function that handles a control character.

type CellRun

type CellRun struct {
	X, Y, N int // start column, row, and number of cells
}

CellRun is N cells of row Y from column X.

type CharSet

type CharSet map[byte]string

CharSet represents a character set designator. This can be used to select a character set for G0 or G1 and others.

type CsiHandler

type CsiHandler func(params ansi.Params) bool

CsiHandler is a function that handles a CSI escape sequence.

type Cursor

type Cursor struct {
	Pen  uv.Style // style of the next printed character
	Link uv.Link  // hyperlink of the next printed character

	uv.Position

	Hidden bool // whether the guest hid the cursor (DECTCEM)
	// Protected says DECSCA protects what is printed next from a selective
	// erase. DECSC saves it with the rest of the cursor.
	Protected bool
}

Cursor represents a cursor in a terminal.

type CursorStyle

type CursorStyle int

CursorStyle represents a cursor style.

const (
	CursorBlock CursorStyle = iota
	CursorUnderline
	CursorBar
)

Cursor styles.

type DcsHandler

type DcsHandler func(params ansi.Params, data []byte) bool

DcsHandler is a function that handles a DCS escape sequence.

type Emulator

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

Emulator represents a virtual terminal emulator.

func NewEmulator

func NewEmulator(w, h int) *Emulator

NewEmulator creates a new virtual terminal emulator.

func (*Emulator) ANSIModes

func (e *Emulator) ANSIModes() map[int]bool

ANSIModes reports insert mode (4) and newline mode (20).

func (*Emulator) ActiveScreenIsAlt

func (e *Emulator) ActiveScreenIsAlt() bool

ActiveScreenIsAlt reports whether the active screen pointer currently addresses the alternate buffer. This is a diagnostic accessor: it exists so the render trace can distinguish the buffer actually being read from the mode bits reported by IsAltScreen, which RestoreAltScreenMode deliberately leaves untouched. It is not part of the emulator's behavioural contract, so do not build rendering or input logic on it.

func (*Emulator) AppendScrollbackText

func (e *Emulator) AppendScrollbackText(buf *strings.Builder)

AppendScrollbackText writes the main screen's scrollback to buf as plain text, oldest line first, each line followed by a newline. The bytes are the same as ScrollbackLine(i).String() plus "\n" for every line, but no line is decoded into cells: a cell is 112 bytes, so decoding a full 10000-line ring to read its text allocated about 100 MB at 80 columns.

It reads the ring and its intern tables and writes nothing to them, so it is safe under the same read lock ScrollbackLine is.

func (*Emulator) ApplicationCursorKeys

func (e *Emulator) ApplicationCursorKeys() bool

ApplicationCursorKeys returns true if DECCKM (application cursor keys mode) is enabled. When this mode is set, cursor keys send SS3 sequences (ESC O A) instead of CSI sequences (ESC [ A).

func (*Emulator) AtGround

func (e *Emulator) AtGround() bool

AtGround reports whether the parser is between sequences: no escape sequence, string or character is half read.

func (*Emulator) BackgroundColor

func (e *Emulator) BackgroundColor() color.Color

BackgroundColor returns the terminal's background color. This returns nil if the background color is not set which means the outer terminal color is used.

func (*Emulator) Blur

func (e *Emulator) Blur()

Blur sends the terminal a blur event if focus events mode is enabled. This is the opposite of [Focus].

func (*Emulator) Bounds

func (e *Emulator) Bounds() uv.Rectangle

Bounds returns the bounds of the terminal.

func (*Emulator) BracketedPasteEnabled

func (e *Emulator) BracketedPasteEnabled() bool

BracketedPasteEnabled returns true if bracketed paste mode (?2004) is enabled. When enabled, pasted text should be wrapped with escape sequences.

func (*Emulator) CellAt

func (e *Emulator) CellAt(x, y int) *uv.Cell

CellAt returns the current focused screen cell at the given x, y position. It returns nil if the cell is out of bounds.

func (*Emulator) CellSize

func (e *Emulator) CellSize() (width, height int)

CellSize returns the pixel dimensions of a single character cell, or the fallback cell when none was set. It is never zero.

func (*Emulator) Charsets

func (e *Emulator) Charsets() (ids [4]byte, gl, gr int)

Charsets returns the designator byte of the character set selected into each of G0 to G3, and which of them GL and GR are pointing at.

func (*Emulator) ClearScrollback

func (e *Emulator) ClearScrollback()

ClearScrollback clears the scrollback buffer of the main screen.

func (*Emulator) Close

func (e *Emulator) Close() error

Close closes the terminal.

func (*Emulator) CopyScrollback

func (e *Emulator) CopyScrollback(from, end int) *ScrollbackCopy

CopyScrollback copies the main screen history lines from index from to end-1. See Terminal.CopyScrollback.

func (*Emulator) CursorColor

func (e *Emulator) CursorColor() color.Color

CursorColor returns the terminal's cursor color. This returns nil if the cursor color is not set which means the outer terminal color is used.

func (*Emulator) CursorPen

func (e *Emulator) CursorPen() (uv.Style, uv.Link)

CursorPen returns the graphic rendition in force: the style and hyperlink everything written next will be painted with. A guest sets it once with an SGR sequence and every character until the next one inherits it, so it is state a snapshot has to carry and not something the cells can be read back from.

func (*Emulator) CursorPendingWrap

func (e *Emulator) CursorPendingWrap() bool

CursorPendingWrap reports whether a wrap is pending at the cursor.

func (*Emulator) CursorPosition

func (e *Emulator) CursorPosition() uv.Position

CursorPosition returns the terminal's cursor position.

func (*Emulator) CursorProtected

func (e *Emulator) CursorProtected() bool

CursorProtected reports whether DECSCA protects what is printed next.

func (*Emulator) CursorStyle

func (e *Emulator) CursorStyle() (CursorStyle, bool)

CursorStyle returns the shape DECSCUSR last asked for, and whether it is steady (not blinking). It reads the terminal-level copy rather than the active screen's, because DECSCUSR is a property of the terminal: a guest that asks for a bar and then enters the alternate screen still wants a bar. The per-screen Cursor.Style is left alone so DECSC/DECRC keep behaving as they did.

func (*Emulator) DisableKittyKeyboardProtocol

func (e *Emulator) DisableKittyKeyboardProtocol()

DisableKittyKeyboardProtocol makes the emulator stop offering the kitty keyboard protocol. Pushes, pops and sets change nothing, a CSI ? u query goes unanswered, and a saved stack is not restored.

It is for a pane whose PTY is a Windows ConPTY. conhost before 1.22 drops the input CSIs it does not recognise, so the CSI u bytes for Escape, Ctrl+letters and modified Enter or Backspace never reach the guest. Per the kitty spec an unanswered query means the protocol is not supported, so a guest that queries first (pi, neovim) falls back to legacy keys on its own. Every encoder reads the flags, which stay at 0, so client key encoding, send-keys and key releases all agree.

The daemon calls it before the pane's output starts. A client calls it from a snapshot that says the pane is a ConPTY one (see snapshot.State.KittyKbdUnavailable), under the lock that guards the emulator's writes. There is no way back: a pane keeps its PTY.

func (*Emulator) DiscardScrollback

func (e *Emulator) DiscardScrollback()

DiscardScrollback makes the main screen drop the lines that scroll off its top instead of keeping them. See Scrollback.Discard.

func (*Emulator) EncodeMouseEvent

func (e *Emulator) EncodeMouseEvent(m Mouse) string

EncodeMouseEvent encodes a mouse event as an escape sequence string. Returns empty string if no mouse mode is enabled. This is used for daemon mode where mouse events need to be sent through the PTY.

func (*Emulator) EncodeMouseEventAt

func (e *Emulator) EncodeMouseEventAt(m Mouse, at MousePixel) string

EncodeMouseEventAt is EncodeMouseEvent with the pointer's pixel position inside the pane, which a guest in SGR-pixel mode is told instead of the cell centre.

func (*Emulator) Focus

func (e *Emulator) Focus()

Focus sends the terminal a focus event if focus events mode is enabled. This is the opposite of [Blur].

func (*Emulator) FocusReportingEnabled

func (e *Emulator) FocusReportingEnabled() bool

FocusReportingEnabled reports whether the guest has focus event reporting (DECSET 1004) on.

func (*Emulator) ForegroundColor

func (e *Emulator) ForegroundColor() color.Color

ForegroundColor returns the terminal's foreground color. This returns nil if the foreground color is not set which means the outer terminal color is used.

func (*Emulator) GetCallbacks

func (e *Emulator) GetCallbacks() Callbacks

GetCallbacks returns the terminal's current callbacks.

func (*Emulator) GetModes

func (e *Emulator) GetModes() map[int]bool

GetModes returns a copy of the current terminal DEC private modes. This is used for session state serialization to preserve terminal modes across reconnections (mouse tracking, bracketed paste, etc.).

It captures every DEC mode the emulator tracks rather than a hand-picked list: a guest sets a sticky mode once at startup (a browser enables 1003/1006/1016 and never repeats them), and any mode missing here is silently lost on reattach once the enable sequence has scrolled out of the daemon's bounded output buffer.

func (*Emulator) GuestColors

func (e *Emulator) GuestColors() GuestColors

GuestColors is what the guest set with OSC 4, 10, 11 and 12.

func (*Emulator) GuestCursorColor

func (e *Emulator) GuestCursorColor() color.Color

GuestCursorColor is the cursor colour the guest set with OSC 12, or nil when it set none or reset it with OSC 112.

func (*Emulator) HasAllMotionMode

func (e *Emulator) HasAllMotionMode() bool

HasAllMotionMode returns true only if the child app requested mode 1003. Thread-safe: reads from an atomic cache updated on mode set/reset.

func (*Emulator) HasCellMotionMode

func (e *Emulator) HasCellMotionMode() bool

HasCellMotionMode returns true if the child app requested mode 1002 (button-event tracking), which reports motion while a button is pressed.

func (*Emulator) HasMouseMode

func (e *Emulator) HasMouseMode() bool

HasMouseMode returns true if any mouse tracking mode is enabled. HasMouseMode returns true if any mouse tracking mode is enabled. Thread-safe: reads from an atomic cache updated on mode set/reset.

func (*Emulator) HasPixelMouseMode

func (e *Emulator) HasPixelMouseMode() bool

HasPixelMouseMode reports whether the guest tracks the mouse and asked for SGR-pixel reports (DEC 1016). Thread-safe: reads the atomic cache.

func (*Emulator) Height

func (e *Emulator) Height() int

Height returns the height of the terminal.

func (*Emulator) IndexedColor

func (e *Emulator) IndexedColor(i int) color.Color

IndexedColor returns a terminal's indexed color. An indexed color is a color between 0 and 255.

func (*Emulator) InputPipe

func (e *Emulator) InputPipe() io.Writer

InputPipe returns the terminal's input pipe. This can be used to send input to the terminal.

func (*Emulator) IsAltScreen

func (e *Emulator) IsAltScreen() bool

IsAltScreen returns whether the terminal is currently using the alternate screen buffer. The alternate screen is used by full-screen applications like vim, less, htop, btop, etc. This is important for mouse event forwarding: mouse events should only be forwarded to applications when they are in alternate screen mode.

func (*Emulator) IsCursorHidden

func (e *Emulator) IsCursorHidden() bool

IsCursorHidden returns whether the cursor is currently hidden. Applications can hide the cursor using ANSI escape sequences (DECTCEM mode).

func (*Emulator) IsSyncActive

func (e *Emulator) IsSyncActive() bool

IsSyncActive reports whether the guest has an open synchronized update (DEC private mode 2026): it has begun drawing a frame and does not want it presented until it resets the mode. Thread-safe: reads from atomics updated on mode set/reset. Returns false once the update has been open past syncMaxHold.

func (*Emulator) KittyAltState

func (e *Emulator) KittyAltState() *KittyState

KittyAltState returns the kitty image state of the alternate screen.

func (*Emulator) KittyGuestImagesState

func (e *Emulator) KittyGuestImagesState() *KittyGuestImagesState

KittyGuestImagesState returns the ids given to the guest's image numbers, for a client that attaches. Nil when there are none.

func (*Emulator) KittyKeyboardFlags

func (e *Emulator) KittyKeyboardFlags() int

KittyKeyboardFlags returns the current kitty keyboard protocol flags. Thread-safe: reads from an atomic cache updated on push/pop/set/reset.

func (*Emulator) KittyKeyboardMainStack

func (e *Emulator) KittyKeyboardMainStack() []int

KittyKeyboardMainStack returns a copy of the main screen's kitty keyboard flag stack while the alternate screen is in use, and nil otherwise. A snapshot carries it with KittyKeyboardStack: a client that restores only the alternate screen's stack has the main one empty when the program quits, and encodes keys in legacy form for a shell that negotiated the protocol.

func (*Emulator) KittyKeyboardStack

func (e *Emulator) KittyKeyboardStack() []int

KittyKeyboardStack returns a copy of the kitty keyboard flag stack of the screen in use, base entry first. It exists for daemon state sync: a guest negotiates the protocol once (CSI > u push or CSI = u set) and never repeats it, so a reattaching client must be handed the stack rather than rediscover it from the output buffer. Call from the goroutine that feeds the emulator, or with the same lock that serializes writes to it.

func (*Emulator) KittyKeyboardUnavailable

func (e *Emulator) KittyKeyboardUnavailable() bool

KittyKeyboardUnavailable reports whether DisableKittyKeyboardProtocol was called.

func (*Emulator) KittyMainState

func (e *Emulator) KittyMainState() *KittyState

KittyMainState returns the kitty image state of the main screen.

func (*Emulator) KittyState

func (e *Emulator) KittyState() *KittyState

KittyState returns the kitty image state of the active screen.

func (*Emulator) LastPrinted

func (e *Emulator) LastPrinted() string

LastPrinted is the cluster REP repeats.

func (*Emulator) MainCellAt

func (e *Emulator) MainCellAt(x, y int) *uv.Cell

MainCellAt reads a cell from the normal screen whether or not the alternate one is active. It is what the guest is not looking at while a full-screen program is running, and what quitting that program reveals.

func (*Emulator) MainRowTail

func (e *Emulator) MainRowTail(y int) uv.Line

MainRowTail returns the cells of main screen row y past the width that a reflow held for an open prompt (see freezePrompt), or nil. A reader that keeps a row whole, such as a saved history, appends them.

func (*Emulator) ModifyOtherKeys

func (e *Emulator) ModifyOtherKeys() int

ModifyOtherKeys returns the modifyOtherKeys level the guest set with XTMODKEYS: 0 off, 1 or 2. Thread-safe.

func (*Emulator) PaletteColor

func (e *Emulator) PaletteColor(i int) color.Color

PaletteColor resolves one of the sixteen ANSI palette slots the way handleSgr resolves SGR 30-37 and 90-97: through the user's theme when one is set, and as a plain palette entry otherwise.

A cell rebuilt from a snapshot has to be coloured by the same rule as a cell the guest writes live, or a pane comes back in one palette and carries on in another.

func (*Emulator) PendingInput

func (e *Emulator) PendingInput() []byte

PendingInput is the input since the parser last left its ground state, with the controls it carried out inside the sequence left out. Inside a CSI or an escape sequence a C0 control is carried out where it is and the sequence goes on, so a replay that sent it again would move the cursor twice. Inside a string (OSC, DCS, SOS, PM, APC) a control is ignored or is payload, and is kept.

func (*Emulator) ProtectedCells

func (e *Emulator) ProtectedCells(main bool) []CellRun

ProtectedCells lists the cells DECSCA protected, on the active screen or with main set on the main screen.

func (*Emulator) PushScrollbackLine

func (e *Emulator) PushScrollbackLine(line uv.Line)

PushScrollbackLine appends a line to the main screen's scrollback. It exists for snapshot restore, where history arrives as decoded lines rather than as a byte stream.

func (*Emulator) Read

func (e *Emulator) Read(p []byte) (n int, err error)

Read reads data from the terminal input buffer.

Example

A sequence that asks a question gets its answer through Read. A host copies the answers back to the program, usually in a goroutine.

package main

import (
	"fmt"

	"tuios.dev/vt"
)

func main() {
	term := vt.NewEmulator(80, 24)
	defer term.Close()

	_, _ = term.Write([]byte("\x1b[3;5H\x1b[6n")) // move, then ask where the cursor is
	reply := make([]byte, 32)
	n, _ := term.Read(reply)
	fmt.Printf("%q\n", reply[:n]) // "\x1b[3;5R"
}

func (*Emulator) RegisterApcHandler

func (h *Emulator) RegisterApcHandler(handler ApcHandler)

RegisterApcHandler registers an APC escape sequence handler.

func (*Emulator) RegisterCsiHandler

func (h *Emulator) RegisterCsiHandler(cmd int, handler CsiHandler)

RegisterCsiHandler registers a CSI escape sequence handler.

func (*Emulator) RegisterDcsHandler

func (h *Emulator) RegisterDcsHandler(cmd int, handler DcsHandler)

RegisterDcsHandler registers a DCS escape sequence handler.

func (*Emulator) RegisterEscHandler

func (h *Emulator) RegisterEscHandler(cmd int, handler EscHandler)

RegisterEscHandler registers an ESC escape sequence handler.

func (*Emulator) RegisterOscHandler

func (h *Emulator) RegisterOscHandler(cmd int, handler OscHandler)

RegisterOscHandler registers an OSC escape sequence handler.

func (*Emulator) RegisterPmHandler

func (h *Emulator) RegisterPmHandler(handler PmHandler)

RegisterPmHandler registers a PM escape sequence handler.

func (*Emulator) RegisterSosHandler

func (h *Emulator) RegisterSosHandler(handler SosHandler)

RegisterSosHandler registers an SOS escape sequence handler.

func (*Emulator) ReleaseAltScreen

func (e *Emulator) ReleaseAltScreen()

ReleaseAltScreen drops the alternate screen's cells while the main screen is shown. A pane that has run one full-screen program keeps that grid otherwise, 1.7 MB at 171x83, and nothing reads it: every switch onto the alternate screen clears it first. The screen keeps its size, and a row nothing has written reads as blank, so the next switch finds what the clear would leave. Dropping the cells at the switch back to the main screen instead would make a pager launched over and over allocate its grid each time.

func (*Emulator) ReleaseReflowScratch

func (e *Emulator) ReleaseReflowScratch()

ReleaseReflowScratch drops the buffers the main screen keeps from one reflow to the next. They make a drag cheap and are worth nothing to a pane that is not being resized, yet after two reflows they hold a spare block the size of the last layout and the history rows that layout decoded: 1.7 MB at 171x83. The next reflow allocates them again. The rows on screen keep the block they are in alive on their own, and a remap handed out by the last reflow keeps the tables it reads, so only what nothing reads is freed.

func (*Emulator) Render

func (e *Emulator) Render() string

Render renders a snapshot of the terminal screen as a string with styles and links encoded as ANSI escape codes.

The frame must redraw the screen when replayed, and concatenation alone cannot: a lone regional indicator in one cell and another in the next are two characters on the grid but one flag to any parser reading them back. A cluster break separates such neighbours.

func (*Emulator) ReserveImageSpace

func (e *Emulator) ReserveImageSpace(rows, cols int)

ReserveImageSpace reserves space for an image by moving cursor and outputting placeholders. This ensures subsequent output appears below the image rather than on top of it.

func (*Emulator) ResetScrollRegion

func (e *Emulator) ResetScrollRegion()

ResetScrollRegion puts scrolling back to the whole screen, which is where a pane whose guest has set no margins scrolls.

func (*Emulator) Resize

func (e *Emulator) Resize(width int, height int)

Resize resizes the terminal.

func (*Emulator) RestoreANSIModes

func (e *Emulator) RestoreANSIModes(modes map[int]bool)

RestoreANSIModes sets the ANSI modes given. It goes through setMode, which also sets the flags the print and line feed paths read.

func (*Emulator) RestoreAltScreenMode

func (e *Emulator) RestoreAltScreenMode(enabled bool)

RestoreAltScreenMode restores the alternate screen mode state. This is used when reconnecting to a daemon session to restore the emulator state without re-sending the escape sequences that would trigger the mode change. This method ONLY switches the screen buffer pointer. It does NOT modify the modes map to avoid concurrent map access issues.

func (*Emulator) RestoreCharsets

func (e *Emulator) RestoreCharsets(ids [4]byte, gl, gr int)

RestoreCharsets puts back a character set selection. A program that draws boxes selects the DEC line-drawing set once and then sends the box characters as plain letters, so a client that comes back with G0 at US ASCII draws qqqq where the guest drew a horizontal rule.

func (*Emulator) RestoreCursorPen

func (e *Emulator) RestoreCursorPen(pen uv.Style, link uv.Link)

RestoreCursorPen puts back the rendition a snapshot was taken under, so the output that arrives after the snapshot is painted the colour the guest set rather than whatever this emulator was left in.

func (*Emulator) RestoreCursorPendingWrap

func (e *Emulator) RestoreCursorPendingWrap(pending bool)

RestoreCursorPendingWrap arms or clears the pending wrap a restored snapshot had at the cursor. Call it after RestoreCursorPosition, which clears it.

The cursor is also recorded as standing on the cell it was printed into, as the print that armed the wrap left it, so a combining mark that arrives next joins that cell rather than the one after it.

func (*Emulator) RestoreCursorPosition

func (e *Emulator) RestoreCursorPosition(x, y int)

RestoreCursorPosition puts the cursor back where a restored snapshot had it. It is the counterpart of CursorPosition and, like RestoreAltScreenMode, it exists so reconnecting does not have to re-send escape sequences whose side effects would undo the restore.

func (*Emulator) RestoreCursorProtected

func (e *Emulator) RestoreCursorProtected(on bool)

RestoreCursorProtected puts back the pen's DECSCA protection.

func (*Emulator) RestoreCursorStyle

func (e *Emulator) RestoreCursorStyle(style CursorStyle, steady bool)

RestoreCursorStyle puts back the shape a snapshot was taken under. A pane the client is rebuilding from the daemon has emitted its DECSCUSR long ago, so without this the pane comes back as a block whatever the guest asked for.

func (*Emulator) RestoreGuestColors

func (e *Emulator) RestoreGuestColors(c GuestColors)

RestoreGuestColors replaces what the guest set with OSC 4, 10, 11 and 12. A nil default colour is one the guest has not set, which the theme's default answers for.

func (*Emulator) RestoreKittyGuestImages

func (e *Emulator) RestoreKittyGuestImages(s *KittyGuestImagesState)

RestoreKittyGuestImages takes the daemon's ids for the guest's image numbers. Nil leaves them as they are.

func (*Emulator) RestoreKittyKeyboardMainStack

func (e *Emulator) RestoreKittyKeyboardMainStack(stack []int)

RestoreKittyKeyboardMainStack replaces the main screen's flag stack from a saved state. A nil or empty stack is a no-op.

func (*Emulator) RestoreKittyKeyboardState

func (e *Emulator) RestoreKittyKeyboardState(stack []int)

RestoreKittyKeyboardState replaces the kitty keyboard flag stack from a saved state and refreshes the cache KittyKeyboardFlags reads. Used when reconnecting to a daemon session; a nil or empty stack is a no-op so state from an older daemon leaves the default (empty) state untouched. The stack goes to the screen in use, so restore the alternate screen first.

func (*Emulator) RestoreLastPrinted

func (e *Emulator) RestoreLastPrinted(cluster string)

RestoreLastPrinted puts back the cluster REP repeats. Its width is not needed: REP prints the cluster again, which measures it.

func (*Emulator) RestoreModes

func (e *Emulator) RestoreModes(modes map[int]bool)

RestoreModes restores terminal modes from a saved state. This is used when reconnecting to a daemon session to restore mouse tracking and other terminal modes without triggering mode change side effects.

func (*Emulator) RestoreModifyOtherKeys

func (e *Emulator) RestoreModifyOtherKeys(level int)

RestoreModifyOtherKeys puts back a level saved from another emulator, for a client that reattaches after the guest set it.

func (*Emulator) RestorePads

func (e *Emulator) RestorePads(screen, history []bool)

RestorePads sets the padding flags a snapshot carries. See Terminal.RestorePads.

func (*Emulator) RestorePendingInput

func (e *Emulator) RestorePendingInput(p []byte)

RestorePendingInput drops the sequence the parser is in, and any character cluster left open across the last Write, and then reads p.

func (*Emulator) RestoreProtectedCells

func (e *Emulator) RestoreProtectedCells(main bool, runs []CellRun)

RestoreProtectedCells replaces the protection of the active screen, or with main set of the main screen, with runs.

func (*Emulator) RestoreSavedCursor

func (e *Emulator) RestoreSavedCursor(main bool, c SavedCursor)

RestoreSavedCursor puts back what DECSC saved on the active screen, or with main set on the main screen.

func (*Emulator) RestoreScrollRegion

func (e *Emulator) RestoreScrollRegion(r uv.Rectangle)

RestoreScrollRegion puts back the margins a guest set with DECSTBM or DECSLRM. A guest sets them once to hold a header or a status line out of the scrolling part of the screen, so a client that comes back without them scrolls the whole screen and takes the fixed rows with it.

func (*Emulator) RestoreSoftWraps

func (e *Emulator) RestoreSoftWraps(screen, history []bool)

RestoreSoftWraps sets the soft-wrap flags a snapshot carries. See Terminal.RestoreSoftWraps.

func (*Emulator) RestoreTabStops

func (e *Emulator) RestoreTabStops(cols []int)

RestoreTabStops replaces the tab stops with cols. A column off the screen is dropped.

func (*Emulator) RestoreTitles

func (e *Emulator) RestoreTitles(t Titles)

RestoreTitles puts back the titles and the newest entries of the stack, as many as XTWINOPS 22 keeps.

func (*Emulator) RowPadded

func (e *Emulator) RowPadded(y int) bool

RowPadded reports whether row y of the active screen wrapped a column early before a wide character. See Terminal.RowPadded.

func (*Emulator) RowSoftWrapped

func (e *Emulator) RowSoftWrapped(y int) (wrapped, known bool)

RowSoftWrapped reports whether row y of the active screen carries on to row y+1 because autowrap moved the text there, rather than because the program wrote a newline. known is always true for this backend.

func (*Emulator) SavedCursor

func (e *Emulator) SavedCursor(main bool) SavedCursor

SavedCursor is what DECSC saved on the active screen, or with main set on the main screen.

func (*Emulator) ScrollRegion

func (e *Emulator) ScrollRegion() uv.Rectangle

ScrollRegion returns the margins scrolling is confined to, as the rectangle of the active screen they cover.

func (*Emulator) Scrollback

func (e *Emulator) Scrollback() *Scrollback

Scrollback returns the scrollback buffer of the main screen. Note: The alternate screen does not maintain scrollback.

func (*Emulator) ScrollbackGeneration

func (e *Emulator) ScrollbackGeneration() uint64

ScrollbackGeneration is a number that changes whenever the main screen's history does: a line pushed, the ring trimmed, cleared or resized. A reader that derived something from the history can keep it for as long as the number stays the same.

func (*Emulator) ScrollbackLen

func (e *Emulator) ScrollbackLen() int

ScrollbackLen returns the number of lines in the scrollback buffer.

func (*Emulator) ScrollbackLine

func (e *Emulator) ScrollbackLine(index int) uv.Line

ScrollbackLine returns a line from the scrollback buffer at the given index. Index 0 is the oldest line. Returns nil if index is out of bounds.

func (*Emulator) ScrollbackPadded

func (e *Emulator) ScrollbackPadded(index int) bool

ScrollbackPadded is RowPadded for a history line, oldest first.

func (*Emulator) ScrollbackRows

func (e *Emulator) ScrollbackRows(from, end int, fn func(index int, line uv.Line) bool)

ScrollbackRows calls fn with each main screen history line from index from to end-1, oldest first, decoded into a buffer reused from line to line. See Terminal.ScrollbackRows.

func (*Emulator) ScrollbackSoftWrapped

func (e *Emulator) ScrollbackSoftWrapped(index int) (wrapped, known bool)

ScrollbackSoftWrapped reports whether scrollback line index (oldest first) carries on to the next line by autowrap. The newest line carries on to the screen's first row. known is always true for this backend.

func (*Emulator) ScrollbackText

func (e *Emulator) ScrollbackText(from, end int, fn func(index, width int, cells []TextCell) bool)

ScrollbackText calls fn with each main screen history line from index from to end-1 as text cells. See Terminal.ScrollbackText.

func (*Emulator) SemanticMarkers

func (e *Emulator) SemanticMarkers() *SemanticMarkerList

SemanticMarkers returns the list of OSC 133 semantic zone markers.

func (*Emulator) SendMouse

func (e *Emulator) SendMouse(m Mouse)

SendMouse sends a mouse event to the terminal. This can be any kind of mouse events such as MouseClick, MouseRelease, MouseWheel, or MouseMotion.

func (*Emulator) SendMouseAt

func (e *Emulator) SendMouseAt(m Mouse, at MousePixel)

SendMouseAt is SendMouse with the pointer's pixel position inside the pane, which a guest in SGR-pixel mode is told instead of the cell centre.

func (*Emulator) SetBackgroundColor

func (e *Emulator) SetBackgroundColor(c color.Color)

SetBackgroundColor sets the terminal's background color.

func (*Emulator) SetCallbacks

func (e *Emulator) SetCallbacks(cb Callbacks)

SetCallbacks sets the terminal's callbacks.

Example

The emulator tells the host what the program asks of it through Callbacks.

package main

import (
	"fmt"

	"tuios.dev/vt"
)

func main() {
	term := vt.NewEmulator(80, 24)
	defer term.Close()

	term.SetCallbacks(vt.Callbacks{
		Title: func(title string) { fmt.Println("title:", title) },
		Bell:  func() { fmt.Println("bell") },
	})
	_, _ = term.Write([]byte("\x1b]2;build\x07\a"))
}

func (*Emulator) SetCell

func (e *Emulator) SetCell(x, y int, c *uv.Cell)

SetCell sets the current focused screen cell at the given x, y position.

func (*Emulator) SetCellSize

func (e *Emulator) SetCellSize(width, height int)

SetCellSize sets the pixel dimensions of a single character cell. Used for XTWINOPS terminal size reporting.

A guest with in-band resize reports on (mode 2048) is sent a new report when the size in pixels changes, as it is on a resize: it scales SGR-pixel mouse reports by the size it was last told.

func (*Emulator) SetCursorColor

func (e *Emulator) SetCursorColor(c color.Color)

SetCursorColor sets the terminal's cursor color.

func (*Emulator) SetDefaultBackgroundColor

func (e *Emulator) SetDefaultBackgroundColor(c color.Color)

SetDefaultBackgroundColor sets the terminal's default background color.

func (*Emulator) SetDefaultCursorColor

func (e *Emulator) SetDefaultCursorColor(c color.Color)

SetDefaultCursorColor sets the terminal's default cursor color.

func (*Emulator) SetDefaultForegroundColor

func (e *Emulator) SetDefaultForegroundColor(c color.Color)

SetDefaultForegroundColor sets the terminal's default foreground color.

func (*Emulator) SetForegroundColor

func (e *Emulator) SetForegroundColor(c color.Color)

SetForegroundColor sets the terminal's foreground color.

func (*Emulator) SetIndexedColor

func (e *Emulator) SetIndexedColor(i int, c color.Color)

SetIndexedColor sets a terminal's indexed color. The index must be between 0 and 255.

func (*Emulator) SetKittyFilesElsewhere

func (e *Emulator) SetKittyFilesElsewhere(on bool)

SetKittyFilesElsewhere says the pane runs on another machine. See KittyGuestImages.SetFilesElsewhere.

func (*Emulator) SetKittyHeaderOnly

func (e *Emulator) SetKittyHeaderOnly(on bool)

SetKittyHeaderOnly says whether the passthrough acts on the control keys alone. When it does, commands are parsed with ParseKittyHeader and the passthrough gets a nil rawData.

func (*Emulator) SetKittyImageIDTranslator

func (e *Emulator) SetKittyImageIDTranslator(fn KittyImageIDTranslator)

SetKittyImageIDTranslator installs the guest-to-host image id mapping used for kitty Unicode placeholder cells. Nil leaves every cell as the guest wrote it.

func (*Emulator) SetKittyPassthroughFunc

func (e *Emulator) SetKittyPassthroughFunc(fn func(cmd *KittyCommand, rawData []byte))

SetKittyPassthroughFunc installs the reader of every graphics command. fn must not write to rawData: cmd.RawPayload shares its bytes.

func (*Emulator) SetKittyPlaceholderMode

func (e *Emulator) SetKittyPlaceholderMode(m KittyPlaceholderMode)

SetKittyPlaceholderMode says whether placeholder cells are kept or dropped.

func (*Emulator) SetKittyUploadAnswers

func (e *Emulator) SetKittyUploadAnswers(on bool)

SetKittyUploadAnswers says whether this emulator answers kitty uploads and placements. See KittyGuestImages.

func (*Emulator) SetLogger

func (e *Emulator) SetLogger(l Logger)

SetLogger sets the terminal's logger.

func (*Emulator) SetMainCell

func (e *Emulator) SetMainCell(x, y int, c *uv.Cell)

SetMainCell writes a cell into the normal screen whether or not the alternate one is active.

func (*Emulator) SetReflowFunc

func (e *Emulator) SetReflowFunc(fn func(remap func(absLine int) int))

SetReflowFunc sets the function a reflow calls with where rows went. See Terminal.SetReflowFunc.

func (*Emulator) SetReportColors

func (e *Emulator) SetReportColors(fg, bg color.Color)

SetReportColors sets the colours an OSC 10 and OSC 11 query is answered with while the guest has not set its own. A nil colour keeps the default answer.

func (*Emulator) SetReportPalette

func (e *Emulator) SetReportPalette(pal [16]color.Color)

SetReportPalette sets the colours an OSC 4 query for one of the sixteen ANSI slots is answered with while neither the guest nor a theme has set the slot. A nil entry keeps the default answer.

func (*Emulator) SetScreenClearFunc

func (e *Emulator) SetScreenClearFunc(f func())

SetScreenClearFunc sets the ScreenClear callback without replacing other callbacks.

func (*Emulator) SetScrollbackMaxLines

func (e *Emulator) SetScrollbackMaxLines(maxLines int)

SetScrollbackMaxLines sets the maximum number of lines for the scrollback buffer.

func (*Emulator) SetSixelAdvertised

func (e *Emulator) SetSixelAdvertised(fn func() bool)

SetSixelAdvertised installs the function that decides whether DA1 lists sixel and XTSMGRAPHICS answers. Nil advertises nothing.

func (*Emulator) SetSixelPassthroughFunc

func (e *Emulator) SetSixelPassthroughFunc(fn SixelPassthroughFunc)

SetSixelPassthroughFunc installs the function that decodes a guest's sixel image and returns the id its marker cells carry. See sixel_marker.go.

func (*Emulator) SetTextSizingFunc

func (e *Emulator) SetTextSizingFunc(fn func(rawOSC []byte, cursorX, cursorY, scale, textLen int))

SetTextSizingFunc installs the function that takes each OSC 66 text sizing sequence, rebuilt for the host terminal, with the cursor position, the scale and the length of the text in characters.

func (*Emulator) SetThemeColors

func (e *Emulator) SetThemeColors(fg, bg, cur color.Color, ansiPalette [16]color.Color)

SetThemeColors sets the terminal's color palette from a theme. This sets the default foreground, background, cursor colors and the first 16 ANSI colors (0-15) which are used by terminal applications.

A nil fg and bg mean no theme is active. That has to put the sixteen back the way they were, not merely stop writing them: a theme the user has turned off that stays in the color table goes on painting every pane in its own red and blue, which is the "going back to none messes up the ANSI 16" report.

func (*Emulator) String

func (e *Emulator) String() string

String returns a string representation of the underlying screen buffer.

func (*Emulator) SupportsMotionEvents

func (e *Emulator) SupportsMotionEvents() bool

SupportsMotionEvents returns true if the child app's mouse mode supports motion events (modes 1002 or 1003). Modes 1000/1001 only support click/release.

func (*Emulator) SyncUpdate

func (e *Emulator) SyncUpdate() (open bool, serial uint64)

SyncUpdate reports whether the guest has an open synchronized update, as IsSyncActive does, and a serial that names that update. Two calls that both report open with the same serial saw the same update; a different serial means the one seen before has been closed and a new one opened. Thread-safe.

func (*Emulator) TabStops

func (e *Emulator) TabStops() []int

TabStops lists the columns that hold a tab stop.

func (*Emulator) TailText

func (e *Emulator) TailText(n int) []string

TailText returns the last n rows of the active screen that carry text, in reading order.

Blank rows are skipped rather than counted. An agent draws its live state in a box at the bottom of the pane and pads below it, so counting the padding would push the box out of the window a rule can see.

It reads the active screen, so a harness drawing in the alternate screen is still readable. Reading further up than a handful of rows finds transcript history, which says what the agent did rather than what it is doing.

NOT REENTRANT. The caller holds the terminal lock, the same as GetTerminalState.

func (*Emulator) TakeResponses

func (e *Emulator) TakeResponses() []byte

TakeResponses removes and returns the replies queued for the program, or nil when there are none. Unlike Read it never blocks, so a host can drain the replies after each Write on the same goroutine. It returns nil after Close.

Example

A host that reads the program's output on one goroutine can drain the answers right after each Write instead. TakeResponses never blocks.

package main

import (
	"fmt"

	"tuios.dev/vt"
)

func main() {
	term := vt.NewEmulator(80, 24)
	defer term.Close()

	_, _ = term.Write([]byte("\x1b[3;5H\x1b[6n"))
	fmt.Printf("%q\n", term.TakeResponses()) // "\x1b[3;5R"
	fmt.Printf("%q\n", term.TakeResponses()) // "" (nothing is left)
}

func (*Emulator) Titles

func (e *Emulator) Titles() Titles

Titles is the window title, the icon name and the title stack.

func (*Emulator) Width

func (e *Emulator) Width() int

Width returns the width of the terminal.

func (*Emulator) WidthMethod

func (e *Emulator) WidthMethod() uv.WidthMethod

WidthMethod returns the width method used by the terminal.

It is always grapheme width, because that is what handleGrapheme measures every printed cluster with, whatever DEC mode 2027 says. This is not a free choice: ultraviolet asks a uv.Screen which method it uses before building a cell to write into it, so answering wcwidth here while placing by grapheme width had ultraviolet build a cell one column narrower than the emulator would have written for the same text. That happens for exactly two classes, a base with an emoji presentation selector and a regional indicator pair, and one column is the whole bug: everything after the cluster shifts along the row, and in a multiplexer it shifts into the pane next door.

Reporting the method actually in use is the fix. Honouring mode 2027 would mean changing placement to match, which is a different and much larger change than making the answer true. For the same reason 2027 is permanently set: DECRQM answers 3, and a guest that resets it is ignored, so the answer stays true after the guest asks to change it. The ghostty backend does honour a reset of 2027, and its DECRQM answer says so.

func (*Emulator) Write

func (e *Emulator) Write(p []byte) (n int, err error)

Write writes data to the terminal output buffer.

func (*Emulator) WriteResponse

func (e *Emulator) WriteResponse(data []byte)

WriteResponse writes data to the emulator's response pipe. This allows external code (e.g., daemon-side Kitty query handlers) to inject responses that will be forwarded to the PTY.

func (*Emulator) WriteString

func (e *Emulator) WriteString(s string) (n int, err error)

WriteString writes a string to the terminal output buffer.

type EscHandler

type EscHandler func() bool

EscHandler is a function that handles an ESC escape sequence.

type GuestColors

type GuestColors struct {
	Palette        [256]color.Color // OSC 4 colours by slot
	Fg, Bg, Cursor color.Color      // OSC 10, 11 and 12 colours
}

GuestColors is what a guest set with OSC 4 (Palette, by slot) and with OSC 10, 11 and 12 (the default foreground, background and cursor colours). A nil entry is one the guest has not set, or has reset.

type KeyMod

type KeyMod = uv.KeyMod

KeyMod represents a key modifier.

type KeyPressEvent

type KeyPressEvent = uv.KeyPressEvent

KeyPressEvent represents a key press event.

type KittyCommand

type KittyCommand struct {
	Action       KittyGraphicsAction      // a, what the command asks for
	Quiet        int                      // q, 1 drops OK replies and 2 drops every reply
	ImageID      uint32                   // i, the image id
	ImageNumber  uint32                   // I, the image number the terminal maps to an id
	PlacementID  uint32                   // p, the placement id
	Format       KittyGraphicsFormat      // f, the pixel format
	Medium       KittyGraphicsMedium      // t, how the image is carried
	Compression  KittyGraphicsCompression // o, the payload compression
	Width        int                      // s, the image width in pixels
	Height       int                      // v, the image height in pixels
	Size         int                      // S, how many bytes to read from a file
	Offset       int                      // O, where in a file to start reading
	More         bool                     // m=1, more chunks of this upload follow
	Delete       KittyDeleteTarget        // d, what a delete takes down
	XOffset      int                      // X, pixel offset inside the first cell
	YOffset      int                      // Y, pixel offset inside the first cell
	SourceX      int                      // x, left edge of the source rectangle in pixels
	SourceY      int                      // y, top edge of the source rectangle in pixels
	SourceWidth  int                      // w, width of the source rectangle in pixels
	SourceHeight int                      // h, height of the source rectangle in pixels
	Columns      int                      // c, columns the placement spans
	Rows         int                      // r, rows the placement spans
	ZIndex       int32                    // z, stacking order against text and other images
	CursorMove   int                      // C=1 leaves the cursor where it is
	Virtual      bool                     // U=1, a virtual placement for Unicode placeholders
	Data         []byte                   // decoded payload when the medium is direct
	RawPayload   string                   // Original base64 payload (preserved for passthrough without re-encoding)
	FilePath     string                   // decoded payload when the medium names a file

	// PayloadErr is set when the payload could not be decoded as base64. Data
	// and FilePath are then empty: the undecoded text is never image data.
	PayloadErr error

	// BackgroundColor is the Y key read as a 32-bit RGBA colour, which is what
	// a=f means by it. YOffset holds the same key read as a placement offset;
	// the two never apply to the same command, and a colour overflows int on a
	// 32-bit build, so it needs its own width.
	BackgroundColor uint32
	// contains filtered or unexported fields
}

KittyCommand is one parsed kitty graphics command (APC G). Each field holds one control key. A key the command does not carry leaves its zero value.

func ParseKittyCommand

func ParseKittyCommand(data []byte) (*KittyCommand, error)

ParseKittyCommand parses the body of a kitty graphics APC, the bytes after the leading 'G'. A payload that is not valid base64 is not an error here: the command is returned with PayloadErr set and no Data or FilePath, so the caller can still answer the guest and drop the transmission it was part of.

func ParseKittyHeader

func ParseKittyHeader(data []byte) (*KittyCommand, error)

ParseKittyHeader parses the body of a kitty graphics APC like ParseKittyCommand, but leaves the image data undecoded: Data stays empty, and RawPayload is kept only when it is short enough to be an echoed reply (see IsKittyResponsePayload). The payload of a shared memory (t=s) or temp file (t=t) transmission is decoded into FilePath, because it is only a name and the daemon deletes the objects no client reads.

It is for a reader that acts on the control keys alone, such as the daemon, which answers queries and refuses animation and never draws. Decoding a 1.5 MB frame there only to throw it away cost more than parsing it.

The payload is still decoded when an EINVAL reply would be owed for it (see KittyPayloadErrorResponse), so PayloadErr is set whenever it decides a reply. That is the first chunk of a transmission with an id and without q=2, or a query. The later chunks of a transmission carry no id, and a stream sent with q=2 owes no reply, so neither is decoded.

type KittyDeleteTarget

type KittyDeleteTarget byte

KittyDeleteTarget is what a kitty graphics delete takes down, the d key. A lower-case value removes placements only. Its upper-case form also frees the image data.

const (
	KittyDeleteAll          KittyDeleteTarget = 'a' // d=a, every placement on the screen
	KittyDeleteAllFree      KittyDeleteTarget = 'A' // d=A, as d=a and also frees the image data
	KittyDeleteByID         KittyDeleteTarget = 'i' // d=i, the placements of image i, or placement p of it
	KittyDeleteByIDFree     KittyDeleteTarget = 'I' // d=I, as d=i and also frees the image data
	KittyDeleteByNumber     KittyDeleteTarget = 'n' // d=n, as d=i for the newest image with number I
	KittyDeleteByNumberFree KittyDeleteTarget = 'N' // d=N, as d=n and also frees the image data
	KittyDeleteAtCursor     KittyDeleteTarget = 'c' // d=c, placements over the cursor cell
	KittyDeleteAtCursorFree KittyDeleteTarget = 'C' // d=C, as d=c and also frees the image data
	KittyDeleteAtCell       KittyDeleteTarget = 'p' // d=p, placements over the cell at x, y
	KittyDeleteAtCellFree   KittyDeleteTarget = 'P' // d=P, as d=p and also frees the image data
	KittyDeleteAtCellZ      KittyDeleteTarget = 'q' // d=q, placements over the cell at x, y with z-index z
	KittyDeleteAtCellZFree  KittyDeleteTarget = 'Q' // d=Q, as d=q and also frees the image data
	KittyDeleteAtColumn     KittyDeleteTarget = 'x' // d=x, placements over column x
	KittyDeleteAtColumnFree KittyDeleteTarget = 'X' // d=X, as d=x and also frees the image data
	KittyDeleteAtRow        KittyDeleteTarget = 'y' // d=y, placements over row y
	KittyDeleteAtRowFree    KittyDeleteTarget = 'Y' // d=Y, as d=y and also frees the image data
	KittyDeleteAtZIndex     KittyDeleteTarget = 'z' // d=z, placements at z-index z
	KittyDeleteAtZIndexFree KittyDeleteTarget = 'Z' // d=Z, as d=z and also frees the image data
	KittyDeleteIDRange      KittyDeleteTarget = 'r' // d=r, the placements of images with ids from x to y
	KittyDeleteIDRangeFree  KittyDeleteTarget = 'R' // d=R, as d=r and also frees the image data
	KittyDeleteFrames       KittyDeleteTarget = 'f' // d=f, the animation frames of image i
	KittyDeleteFramesFree   KittyDeleteTarget = 'F' // d=F, as d=f and also frees the image data
)

type KittyGraphicsAction

type KittyGraphicsAction byte

KittyGraphicsAction is what a kitty graphics command asks for, the a key.

const (
	KittyActionQuery         KittyGraphicsAction = 'q' // probe support without storing an image
	KittyActionTransmit      KittyGraphicsAction = 't' // upload an image
	KittyActionTransmitPlace KittyGraphicsAction = 'T' // upload an image and place it
	KittyActionPlace         KittyGraphicsAction = 'p' // place an uploaded image
	KittyActionDelete        KittyGraphicsAction = 'd' // delete placements or images, see KittyDeleteTarget
	KittyActionFrame         KittyGraphicsAction = 'f' // send an animation frame
	KittyActionAnimation     KittyGraphicsAction = 'a' // control an animation
	KittyActionCompose       KittyGraphicsAction = 'c' // compose one frame onto another
)

type KittyGraphicsCompression

type KittyGraphicsCompression uint8

KittyGraphicsCompression is the compression of a kitty graphics payload, the o key.

const (
	KittyCompressionNone KittyGraphicsCompression = 0 // no o key
	KittyCompressionZlib KittyGraphicsCompression = 1 // o=z, zlib deflate
)

type KittyGraphicsFormat

type KittyGraphicsFormat uint8

KittyGraphicsFormat is the pixel format of a kitty graphics upload, the f key.

const (
	KittyFormatRGB  KittyGraphicsFormat = 24  // f=24, raw 8-bit RGB
	KittyFormatRGBA KittyGraphicsFormat = 32  // f=32, raw 8-bit RGBA
	KittyFormatPNG  KittyGraphicsFormat = 100 // f=100, PNG data
)

type KittyGraphicsMedium

type KittyGraphicsMedium byte

KittyGraphicsMedium is how a kitty graphics upload carries its image, the t key.

const (
	KittyMediumDirect       KittyGraphicsMedium = 'd' // image bytes in the payload
	KittyMediumFile         KittyGraphicsMedium = 'f' // payload names a file
	KittyMediumTempFile     KittyGraphicsMedium = 't' // payload names a temporary file to delete after reading
	KittyMediumSharedMemory KittyGraphicsMedium = 's' // payload names a shared memory object
)

func (KittyGraphicsMedium) IsFile

func (m KittyGraphicsMedium) IsFile() bool

IsFile reports whether the medium names something on the machine the terminal runs on (a file, a temporary file or a shared memory object) instead of carrying the image bytes in the payload.

type KittyGuestImages

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

KittyGuestImages is what one pane's emulator knows about the images its guest named: which id each image number (I=) stands for, which ids hold an image, and the answer owed to an upload that is still arriving in chunks.

It lives in the emulator because every emulator of a pane sees the same commands in the same order: the daemon's, and each attached client's. The ids it gives follow from that order. A client that attaches later has not seen the commands before it attached, so it takes the daemon's record with the snapshot it restores (see KittyGuestImagesState). From there it gives the same ids as the daemon.

The answers go out through the emulator's response pipe, and only the emulator that is set to answer writes them (SetKittyUploadAnswers). A daemon's emulator answers. A client emulator of a daemon pane does not, and its pipe is drained anyway, so a guest gets one answer however many clients are attached.

The zero value answers and is ready to use.

func (*KittyGuestImages) Handle

func (g *KittyGuestImages) Handle(cmd *KittyCommand, write func([]byte)) bool

Handle resolves a command's image number, keeps the record of which ids hold an image, and answers what kitty answers: the last chunk of an upload that named its image, and a placement. write sends an answer to the guest. It reports false when the command must not reach the passthrough: it names both i= and I=, or a number or an image the pane does not have.

func (*KittyGuestImages) Restore

func (g *KittyGuestImages) Restore(s *KittyGuestImagesState)

Restore replaces the record with the daemon's. A nil state, from a daemon that sends none, leaves the record as it is.

func (*KittyGuestImages) SetAnswers

func (g *KittyGuestImages) SetAnswers(on bool)

SetAnswers says whether this record answers the guest. Off, it still gives ids, and it opens no file.

func (*KittyGuestImages) SetFilesElsewhere

func (g *KittyGuestImages) SetFilesElsewhere(on bool)

SetFilesElsewhere says the pane runs on another machine. Its file medium uploads are refused without a look at the file.

func (*KittyGuestImages) State

State returns a copy of what a late client needs.

type KittyGuestImagesState

type KittyGuestImagesState struct {
	Numbers   map[uint32]uint32 `json:"numbers,omitempty"`    // image number to the id it stands for
	Known     []uint32          `json:"known,omitempty"`      // ids that hold an image
	Next      uint32            `json:"next,omitempty"`       // next id to give an image sent by number
	GuestHigh []uint32          `json:"guest_high,omitempty"` // ids at or above kittyImageNumberIDBase the guest chose itself
}

KittyGuestImagesState is the part of KittyGuestImages a client takes from the daemon when it attaches, so both give an image number the same id.

type KittyImageIDTranslator

type KittyImageIDTranslator func(guestID uint32) (hostID uint32, ok bool)

KittyImageIDTranslator turns a guest's image id into the id the host knows that image by. It reports false when the image has no host id yet, in which case the cell is left as the guest wrote it.

type KittyPlaceholderMode

type KittyPlaceholderMode int

KittyPlaceholderMode says what the emulator does with placeholder cells.

const (
	// KittyPlaceholdersDrop discards placeholder cells, which is what a host
	// that cannot draw them needs: kept, they render as missing-glyph boxes
	// where the picture should be, which is worse than the blank space the
	// application left room for. This is the default, so a caller that never
	// asks is never surprised.
	KittyPlaceholdersDrop KittyPlaceholderMode = iota
	// KittyPlaceholdersKeep stores them so they reach the host and it draws
	// the image.
	KittyPlaceholdersKeep
)

type KittyState

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

KittyState is the clear-notification relay between the emulator and the passthrough layer: a guest screen clear (ED, mode reset) must also clear the images the passthrough painted on the host terminal.

func NewKittyState

func NewKittyState() *KittyState

NewKittyState returns a KittyState with no clear callback.

func (*KittyState) ClearPlacements

func (s *KittyState) ClearPlacements()

ClearPlacements reports a guest screen clear to the passthrough layer, which owns the placements.

func (*KittyState) SetClearCallback

func (s *KittyState) SetClearCallback(fn func())

SetClearCallback registers the passthrough hook fired on guest screen clears.

type Logger

type Logger interface {
	// Printf logs a message formatted as fmt.Printf does.
	Printf(format string, v ...any)
}

Logger represents a logger interface.

type Mouse

type Mouse = uv.MouseEvent

Mouse represents a mouse event.

type MouseButton

type MouseButton = uv.MouseButton

MouseButton represents the button that was pressed during a mouse message.

type MouseClick

type MouseClick = uv.MouseClickEvent

MouseClick represents a mouse click event.

type MouseMotion

type MouseMotion = uv.MouseMotionEvent

MouseMotion represents a mouse motion event.

type MousePixel

type MousePixel struct {
	X, Y int  // pixel position
	OK   bool // whether X and Y are known
}

MousePixel is the pointer's position inside the pane in pixels, measured from the top-left pixel of the pane's first cell. A guest in SGR-pixel mode (DEC 1016) is told this position. OK is false when the host reported the pointer in cells only; the report then falls back to the cell centre.

type MouseRelease

type MouseRelease = uv.MouseReleaseEvent

MouseRelease represents a mouse release event.

type MouseWheel

type MouseWheel = uv.MouseWheelEvent

MouseWheel represents a mouse wheel event.

type OscHandler

type OscHandler func(data []byte) bool

OscHandler is a function that handles an OSC escape sequence.

type PmHandler

type PmHandler func(data []byte) bool

PmHandler is a function that handles a PM escape sequence.

type ProgressState

type ProgressState int

ProgressState is the state field of an OSC 9;4 progress report, the ConEmu progress sequence. It is a structured, in-band statement by the program in the pane about whether it is busy, which is why tuios reads it: a coding agent that emits it is describing its own state far more honestly than any guess made from its output.

const (
	// ProgressClear removes the progress indicator: the program is no longer
	// busy.
	ProgressClear ProgressState = 0
	// ProgressNormal is a determinate progress bar carrying a percentage.
	ProgressNormal ProgressState = 1
	// ProgressError means the operation failed.
	ProgressError ProgressState = 2
	// ProgressIndeterminate is a busy indicator with no known percentage.
	ProgressIndeterminate ProgressState = 3
	// ProgressWarning is a determinate bar flagged as needing attention.
	ProgressWarning ProgressState = 4
)

type SavedCursor

type SavedCursor struct {
	X, Y        int      // cursor position, zero-based
	Pen         uv.Style // rendition
	Link        uv.Link  // hyperlink the pen held
	PendingWrap bool     // wrap pending at the last column
	Origin      bool     // origin mode (DECOM)
	Protected   bool     // DECSCA protection
	// Charsets names the set in G0 to G3 by its designator byte, as
	// Charsets does. A zero byte reads as US ASCII.
	Charsets [4]byte
	GL, GR   int // the G sets invoked into GL and GR, 0 to 3
}

SavedCursor is the state DECSC saves and DECRC puts back: the position, the pen, the pending-wrap flag, origin mode, DECSCA protection and the character set selection. Link is the hyperlink the pen held, which the pure emulator saves with it and libghostty does not.

type Screen

type Screen interface {
	// Write feeds the emulator what the program printed.
	io.Writer
	// Read returns the replies the emulator sends the program, such as the
	// answer to a cursor position query. It blocks until there is a reply,
	// and returns io.EOF after Close.
	Read(p []byte) (n int, err error)
	// Resize sets the screen size in cells.
	Resize(width, height int)
	// Width returns the width of the screen in cells.
	Width() int
	// Height returns the height of the screen in cells.
	Height() int
	// CellAt returns the cell at column x, row y, for reading only. It
	// returns nil outside the screen.
	CellAt(x, y int) *uv.Cell
	// CursorPosition returns the cursor's column and row.
	CursorPosition() uv.Position
	// Render returns the screen as text, with its styles and links as escape
	// sequences.
	Render() string
	// String returns the text of the screen without styles.
	String() string
	// Close stops the emulator and makes a blocked Read return io.EOF.
	Close() error
}

Screen is the part of an emulator most programs need: what a program prints goes in, the screen comes out, and the emulator's replies go back to the program. Terminal has everything tuios uses, and every Terminal is a Screen.

type Scrollback

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

Scrollback is the ring of lines that have scrolled off the top of the screen. It is a ring so a push is O(1) once the ring is full.

Lines are stored encoded, not as uv.Line. A uv.Cell is 112 bytes: a string header, three colour interfaces, a link of two strings and an int width. A scrollback line kept in that form costs terminal width times 112 bytes no matter what is on it, so at the default 10000 lines a 207-column pane held 232 MB the moment its ring filled, and the daemon and every attached client each held their own copy. An earlier packing brought a cell down to 24 bytes, which is still 24 bytes for a plain letter: the same text as UTF-8 is one byte.

So a line is stored as the bytes of its text, with a style or a link written once where it changes rather than once per cell; see encodeLine. A plain line of a build log costs its length in bytes. A line is stored only up to its last cell that is not blank, and the ring's own slice of line headers grows as lines arrive rather than being allocated at the ring's capacity, so a pane that has printed nothing holds nothing. Reads decode back to uv.Line, padded to the width the line had, through a small cache so a render of a scrolled pane, which asks for the same line once per column, decodes each line once.

func NewScrollback

func NewScrollback(maxLines int) *Scrollback

NewScrollback creates a scrollback ring of maxLines lines. Zero or less means DefaultScrollbackSize.

func (*Scrollback) Clear

func (sb *Scrollback) Clear()

Clear drops every line and the storage behind it.

func (*Scrollback) Discard

func (sb *Scrollback) Discard()

Discard empties the ring and makes it drop every line pushed from now on, before the line is encoded. It is for an emulator whose history nobody reads: tuios gui-bridge runs one per pane only to follow titles, folders and modes, and its renderer keeps the history. Encoding each line that scrolled off was about a third of that process's work under a flood.

func (*Scrollback) Len

func (sb *Scrollback) Len() int

Len returns the number of lines in the ring.

func (*Scrollback) Line

func (sb *Scrollback) Line(index int) uv.Line

Line returns the line at index, oldest first, decoded to its original width, or nil when index is out of range. The result is shared with later calls for the same index until the ring changes, so callers must not write to it.

func (*Scrollback) LineWrapped

func (sb *Scrollback) LineWrapped(index int) bool

LineWrapped reports whether the line at index, oldest first, carried on to the next line by autowrap. The last line of the ring carries on to the screen's first row.

func (*Scrollback) Lines

func (sb *Scrollback) Lines() []uv.Line

Lines returns every line in the ring, oldest first, each decoded fresh.

func (*Scrollback) MaxLines

func (sb *Scrollback) MaxLines() int

MaxLines returns the ring's capacity.

func (*Scrollback) PushBlankLine

func (sb *Scrollback) PushBlankLine(width int)

PushBlankLine stores a blank line of the given width as the newest scrollback line: what a row of the screen that nothing has written holds.

func (*Scrollback) PushLine

func (sb *Scrollback) PushLine(line uv.Line)

PushLine stores a copy of line as the newest scrollback line. The caller keeps line and may go on writing to it: nothing here aliases it.

Into a full ring the push reuses the storage of the line it evicts when that is large enough, so a steady flood of similar lines allocates nothing.

func (*Scrollback) SetMaxLines

func (sb *Scrollback) SetMaxLines(maxLines int)

SetMaxLines resizes the ring, keeping the newest lines that fit.

func (*Scrollback) SetOnTrim

func (sb *Scrollback) SetOnTrim(fn func(int))

SetOnTrim sets a callback that fires when the ring overwrites oldest lines.

type ScrollbackCopy

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

ScrollbackCopy is a run of history lines copied out of a terminal in the form the pure emulator's ring keeps them, a byte or so a cell for text. A reader copies the lines while it holds the terminal's lock and decodes them after releasing it, so the terminal is held for a copy of the encoded bytes and not for the decode.

A backend that cannot copy its lines cheaply copies something else under the lock and makes the lines from it on first use: see build.

func (*ScrollbackCopy) Len

func (c *ScrollbackCopy) Len() int

Len is the number of lines in the copy.

func (*ScrollbackCopy) Padded

func (c *ScrollbackCopy) Padded(index int) bool

Padded reports whether line index of the copy wrapped a column early before a wide character. See Terminal.ScrollbackPadded.

func (*ScrollbackCopy) Rows

func (c *ScrollbackCopy) Rows(from, end int, fn func(index int, line uv.Line) bool)

Rows calls fn with the copy's lines from index from to end-1, counted from the copy's first line, each decoded to its full width into a buffer reused from line to line. fn must copy what it keeps. It stops when fn returns false.

func (*ScrollbackCopy) Text

func (c *ScrollbackCopy) Text(from, end int, fn func(index, width int, cells []TextCell) bool)

Text is Rows for a reader of text: see Terminal.ScrollbackText.

func (*ScrollbackCopy) Wrapped

func (c *ScrollbackCopy) Wrapped(index int) bool

Wrapped reports whether line index of the copy carried on to the next line by autowrap.

type SemanticMarker

type SemanticMarker struct {
	Type         SemanticMarkerType // which OSC 133 marker this is
	AbsLine      int                // scrollbackLen + cursorY at time of emission
	Col          int                // cursor X (column) at time of emission
	ExitCode     int                // only meaningful for 'D', -1 = unknown
	CapturedText string             // command text captured at C-marker time (before output)
}

SemanticMarker represents a single OSC 133 marker captured from the terminal.

type SemanticMarkerList

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

SemanticMarkerList is a thread-safe, bounded list of semantic markers.

A marker's line is kept relative to an origin that only moves forward: the list stores AbsLine plus trimmed, the number of lines the scrollback had dropped when the marker was added, and every reader subtracts the current trimmed again. A scrollback trim then only moves the origin. It used to rewrite every marker's line under the lock, once per line a full ring dropped, which on a flooding pane was 8% of the daemon's time and grew with the number of markers.

A marker whose line has fallen below the origin is gone. The trim drops those at the front, and readers skip any left behind later in the list (a marker can follow one on a lower line when the cursor moved up between them).

func NewSemanticMarkerList

func NewSemanticMarkerList(maxItems int) *SemanticMarkerList

NewSemanticMarkerList creates a new marker list with the given capacity.

func (*SemanticMarkerList) Add

Add appends a marker to the list, discarding the oldest if at capacity.

func (*SemanticMarkerList) AdjustForScrollbackTrim

func (l *SemanticMarkerList) AdjustForScrollbackTrim(linesRemoved int)

AdjustForScrollbackTrim moves the list's origin when scrollback lines are trimmed from the ring buffer, which lowers every marker's AbsLine by linesRemoved. Markers that fall before the new origin are removed. It costs nothing when the list is empty, and otherwise only drops what fell off the front.

func (*SemanticMarkerList) Clear

func (l *SemanticMarkerList) Clear()

Clear removes all markers.

func (*SemanticMarkerList) Last

Last returns a copy of the most recent marker of the given type, or nil if none.

func (*SemanticMarkerList) Len

func (l *SemanticMarkerList) Len() int

Len returns the number of markers.

func (*SemanticMarkerList) Markers

func (l *SemanticMarkerList) Markers() []SemanticMarker

Markers returns a copy of all markers.

func (*SemanticMarkerList) RemoveOnScreen

func (l *SemanticMarkerList) RemoveOnScreen(scrollbackLen int)

RemoveOnScreen removes markers whose AbsLine >= scrollbackLen, i.e. markers that reference visible screen content. Used when the screen is cleared (CSI 2J) so that stale on-screen markers don't cause output extraction to read overwritten content after new commands run.

func (*SemanticMarkerList) Trimmed

func (l *SemanticMarkerList) Trimmed() int

Trimmed is the list's origin: how many scrollback lines it has seen dropped since it was made. A row read now plus Trimmed is a row that stays the same line however much more the scrollback drops. A row stored that way is turned back into today's row by subtracting Trimmed again.

type SemanticMarkerType

type SemanticMarkerType byte

SemanticMarkerType represents an OSC 133 semantic zone marker type.

const (
	// MarkerPromptStart is 'A': prompt start
	MarkerPromptStart SemanticMarkerType = 'A'
	// MarkerCommandStart is 'B': command input start (after prompt)
	MarkerCommandStart SemanticMarkerType = 'B'
	// MarkerCommandExecuted is 'C': command execution start (output begins)
	MarkerCommandExecuted SemanticMarkerType = 'C'
	// MarkerCommandFinished is 'D': command finished (exit code available)
	MarkerCommandFinished SemanticMarkerType = 'D'
)

type SixelAction

type SixelAction int

SixelAction represents the type of sixel operation.

const (
	SixelActionDisplay SixelAction = iota // Display sixel image at cursor
	SixelActionQuery                      // Query sixel support (rarely used)
)

type SixelCommand

type SixelCommand struct {
	// AspectRatio specifies the pixel aspect ratio
	// 0,1 = 2:1 (default), 2 = 5:1, 3,4 = 3:1, 5,6 = 2:1, 7,8,9 = 1:1
	AspectRatio int

	// BackgroundMode specifies how the background is handled
	// 0 = device default, 1 = no change (transparent), 2 = set to color 0
	BackgroundMode int

	// HorizontalGrid is deprecated but may be present (ignored)
	HorizontalGrid int

	// Width is the calculated width of the image in pixels
	Width int

	// Height is the calculated height of the image in pixels
	Height int

	// Data contains the raw sixel raster data (after the 'q' introducer)
	Data []byte

	// RawSequence contains the complete DCS sequence for passthrough
	RawSequence []byte

	// CellWidth and CellHeight are the cell size in pixels the emulator
	// measured the image against, set before the passthrough sees it. The
	// image's marker cells were counted at this size, so the compositor
	// maps a cell back to its pixels with it.
	CellWidth, CellHeight int
}

SixelCommand represents a parsed Sixel graphics command. Sixel DCS format: ESC P <p1>;<p2>;<p3> q <sixel-data> ST

func ParseSixelCommand

func ParseSixelCommand(data []byte) *SixelCommand

ParseSixelCommand parses a DCS sixel sequence. The data parameter should contain everything after the DCS introducer, including parameters, the 'q' introducer, and sixel data.

func (*SixelCommand) ColsForWidth

func (cmd *SixelCommand) ColsForWidth(cellWidth int) int

ColsForWidth returns the number of terminal columns needed for a sixel image given its pixel width and the terminal's cell width.

func (*SixelCommand) RowsForHeight

func (cmd *SixelCommand) RowsForHeight(cellHeight int) int

RowsForHeight returns the number of terminal rows needed for a sixel image given its pixel height and the terminal's cell height.

type SixelImage

type SixelImage struct {
	Width, Height int // size in pixels
	// Pix holds one entry per pixel, row by row. Zero is a pixel no sixel
	// painted, which is drawn transparent; n is palette register n-1.
	Pix []uint16
	// Palette is indexed by register. Registers the image never set keep the
	// VT340 defaults, as a terminal would.
	Palette []color.RGBA
	// Exact says the guest's own bytes draw exactly this image on a sixel
	// terminal, so they may be sent as they are. It is false when the data
	// painted past the size the raster attributes declared (a terminal would
	// paint those pixels over whatever is beside the image's cells), when it
	// used a register past the 256 a pane is told it has, or when it asked
	// for an opaque background and left pixels unpainted (terminals disagree
	// on what fills them). Such an image is always re-encoded from Pix.
	Exact bool
}

SixelImage is a decoded sixel picture: one palette index per pixel, and the palette.

It is kept indexed rather than expanded to RGBA for two reasons. A sixel image is already paletted, so a crop re-encoded from the indices keeps every colour exactly as the program chose it, with no quantising step. And it is half the memory of RGBA at two bytes a pixel, which matters because a pane can hold a screenful of pictures in its scrollback.

func DecodeSixel

func DecodeSixel(cmd *SixelCommand) *SixelImage

DecodeSixel paints cmd's sixel data into an image of cmd.Width by cmd.Height pixels, the size the emulator already used to reserve the image's cells. Pixels drawn past that size are dropped, so the picture and the cells it owns always agree. It returns nil when the image is empty or larger than the limits above.

func (*SixelImage) At

func (img *SixelImage) At(x, y int) (color.RGBA, bool)

At returns the colour of one pixel, and false for a transparent one.

func (*SixelImage) Bytes

func (img *SixelImage) Bytes() int

Bytes is the memory the image holds, for the per-pane budget.

func (*SixelImage) RGBA

func (img *SixelImage) RGBA(r image.Rectangle) []byte

RGBA expands the part of the image inside r to 8-bit RGBA, four bytes a pixel, with unpainted pixels fully transparent. It is what a kitty host is sent when the image has to go to it in kitty's format.

type SixelPassthroughFunc

type SixelPassthroughFunc func(cmd *SixelCommand, cursorX, cursorY int) uint32

SixelPassthroughFunc receives a guest's sixel image and the cursor it was drawn at, and returns the id to mark the image's cells with, or 0 when the image will not be shown.

type SosHandler

type SosHandler func(data []byte) bool

SosHandler is a function that handles an SOS escape sequence.

type Terminal

type Terminal interface {
	// Byte I/O and lifecycle. Write feeds raw PTY bytes; Read drains query
	// responses (DA, CPR, ...) the emulator wants sent back to the guest;
	// WriteResponse queues a response produced outside the emulator.
	Write(p []byte) (n int, err error)
	// Read drains the responses the emulator wants sent back to the guest.
	// It returns io.EOF after Close.
	Read(p []byte) (n int, err error)
	// TakeResponses removes and returns the queued responses without
	// blocking, or nil when there are none. A host that drains after each
	// Write uses it instead of a goroutine blocked in Read.
	TakeResponses() []byte
	// WriteResponse queues data to come out of Read, for a response made outside
	// the emulator.
	WriteResponse(data []byte)
	// Close stops the emulator and makes a blocked Read return io.EOF.
	Close() error
	// Resize sets the screen size in cells. A size below 1 counts as 1.
	Resize(width int, height int)

	// Grid reads. CellAt addresses the active screen, MainCellAt the main
	// screen even while the alternate screen is active. Both hand out a
	// pointer for reading only: a row nothing has printed on is served from
	// one shared blank cell, and a write through the pointer would show on
	// every blank cell of every pane. Writes go through SetCell.
	Width() int
	// Height returns the height of the screen in cells.
	Height() int
	// Bounds returns the screen as a rectangle at the origin.
	Bounds() uv.Rectangle
	// CellAt returns the cell at x, y of the active screen, for reading only.
	CellAt(x, y int) *uv.Cell
	// MainCellAt returns the cell at x, y of the main screen, for reading only.
	MainCellAt(x, y int) *uv.Cell
	// Render returns the active screen as text with its styles and links
	// encoded as escape sequences.
	Render() string
	// String returns the text of the active screen without styles.
	String() string
	// TailText returns the last n rows of the active screen that carry text,
	// in reading order. Blank rows are skipped.
	TailText(n int) []string

	// Grid writes, used only to prime an emulator from a wire snapshot.
	SetCell(x, y int, c *uv.Cell)
	// SetMainCell writes c at x, y of the main screen.
	SetMainCell(x, y int, c *uv.Cell)

	// Cursor.
	CursorPosition() uv.Position
	// IsCursorHidden reports whether the guest has hidden the cursor.
	IsCursorHidden() bool
	// CursorPen returns the style and hyperlink the next printed character
	// gets.
	CursorPen() (uv.Style, uv.Link)
	// CursorStyle returns the cursor shape DECSCUSR last set, and whether it
	// is steady rather than blinking.
	CursorStyle() (style CursorStyle, steady bool)
	// GuestCursorColor is the cursor colour the guest set with OSC 12 and
	// has not reset with OSC 112, or nil when it set none. Unlike
	// GuestColors it copies no palette, so a renderer can read it per frame.
	GuestCursorColor() color.Color
	// RestoreCursorPosition moves the cursor to x, y without side effects, to
	// prime an emulator from a snapshot.
	RestoreCursorPosition(x, y int)
	// CursorPendingWrap reports whether the cursor stands on the last column
	// with a wrap pending: the next printed character goes to the start of
	// the next row, not over the cell the cursor is on. The cursor position
	// alone cannot say this.
	CursorPendingWrap() bool
	// RestoreCursorPendingWrap arms or clears the pending wrap, after
	// RestoreCursorPosition has put the cursor back.
	RestoreCursorPendingWrap(pending bool)
	// RestoreCursorPen puts back the pen CursorPen returned, to prime an
	// emulator from a snapshot.
	RestoreCursorPen(pen uv.Style, link uv.Link)
	// RestoreCursorStyle puts back the shape CursorStyle returned, to prime an
	// emulator from a snapshot.
	RestoreCursorStyle(style CursorStyle, steady bool)
	// CursorProtected reports whether DECSCA protects what the guest prints
	// next. RestoreCursorProtected puts it back.
	CursorProtected() bool
	// RestoreCursorProtected sets the protection CursorProtected reports.
	RestoreCursorProtected(on bool)
	// SavedCursor is what DECSC last saved on the active screen, or with main
	// set on the main screen under an active alternate one. A screen that
	// never saved a cursor reports the zero SavedCursor, which is where a
	// DECRC with nothing saved goes. RestoreSavedCursor puts one back.
	SavedCursor(main bool) SavedCursor
	// RestoreSavedCursor puts back the cursor SavedCursor returned.
	RestoreSavedCursor(main bool, c SavedCursor)
	// LastPrinted is the character REP repeats, as the guest sent it, before
	// any character set maps it. It is empty when nothing has been printed
	// since the last reset. RestoreLastPrinted puts it back.
	LastPrinted() string
	// RestoreLastPrinted puts back the character LastPrinted returned.
	RestoreLastPrinted(cluster string)

	// Tab stops. TabStops lists the columns that hold a stop, in order.
	// RestoreTabStops replaces the table with the columns given, after any
	// resize, since a resize to a new width resets the table. A column off
	// the screen is dropped.
	TabStops() []int
	// RestoreTabStops sets a tab stop at each column in cols and clears the
	// others.
	RestoreTabStops(cols []int)

	// Titles is the window title, the icon name and what XTWINOPS 22 saved.
	// RestoreTitles puts all three back, keeping the newest entries of a
	// stack longer than XTWINOPS keeps. It does not tell the host through
	// the Title callback, except on the libghostty backend, whose library
	// takes a title only as OSC 2 and reports each one it takes.
	Titles() Titles
	// RestoreTitles puts back the titles Titles returned.
	RestoreTitles(t Titles)

	// GuestColors is what the guest set with OSC 4, 10, 11 and 12 and has
	// not reset. RestoreGuestColors replaces all of it.
	GuestColors() GuestColors
	// RestoreGuestColors replaces the colours the guest set with c.
	RestoreGuestColors(c GuestColors)

	// ANSIModes reports the ANSI (not DEC private) modes the emulator
	// implements, by number: insert mode (4) and newline mode (20) on both
	// backends. GetModes cannot carry them, because the two kinds share a
	// number space there. RestoreANSIModes sets them without side effects
	// and ignores a mode the emulator does not implement.
	ANSIModes() map[int]bool
	// RestoreANSIModes sets the ANSI modes ANSIModes returned.
	RestoreANSIModes(modes map[int]bool)

	// PendingInput is the input since the parser last left its ground
	// state: the start of an escape sequence or of a UTF-8 character that
	// has not ended yet, without a control the parser has already carried
	// out inside it. It is empty at ground and at most MaxPendingInput
	// bytes. A snapshot carries it, because the rest of the sequence
	// arrives after the snapshot and an emulator at ground prints it as
	// text. RestorePendingInput drops whatever unfinished input the
	// emulator holds and then reads p, so the next byte continues p.
	PendingInput() []byte
	// RestorePendingInput replaces the unfinished input with p.
	RestorePendingInput(p []byte)

	// Protected cells. ProtectedCells lists the cells DECSCA protected on
	// the active screen, or with main set on the main screen under an active
	// alternate one, as runs along a row. RestoreProtectedCells replaces the
	// protection on that screen with the runs given, after the cells are
	// written: SetCell leaves a cell unprotected.
	ProtectedCells(main bool) []CellRun
	// RestoreProtectedCells replaces the DECSCA protection of a screen with
	// runs.
	RestoreProtectedCells(main bool, runs []CellRun)

	// Screen and mode state. The Restore* half of each pair exists for the
	// same snapshot priming as SetCell.
	IsAltScreen() bool
	// ActiveScreenIsAlt reports whether the emulator reads and writes the
	// alternate screen. It is for diagnostics: IsAltScreen reports the mode.
	ActiveScreenIsAlt() bool
	// RestoreAltScreenMode makes the alternate or the main screen active
	// without clearing it and without changing the modes.
	RestoreAltScreenMode(enabled bool)
	// IsSyncActive reports whether the guest has a synchronized update (mode
	// 2026) open. An update held open too long reads as closed.
	IsSyncActive() bool
	// SyncUpdate reports what IsSyncActive does, and a serial that changes
	// each time the guest opens a new synchronized update.
	SyncUpdate() (open bool, serial uint64)
	// GetModes returns a copy of the DEC private modes the guest has set or
	// reset, by number.
	GetModes() map[int]bool
	// RestoreModes sets the DEC private modes GetModes returned, without the
	// side effects of a mode change.
	RestoreModes(modes map[int]bool)
	// ScrollRegion returns the margins the guest set with DECSTBM and DECSLRM,
	// or the whole screen.
	ScrollRegion() uv.Rectangle
	// RestoreScrollRegion puts back the margins ScrollRegion returned. An empty
	// r changes nothing.
	RestoreScrollRegion(r uv.Rectangle)
	// ResetScrollRegion makes the whole screen scroll.
	ResetScrollRegion()
	// Charsets returns the designator byte of the character set in each of G0
	// to G3, and which of them GL and GR select.
	Charsets() (ids [4]byte, gl, gr int)
	// RestoreCharsets puts back the selection Charsets returned.
	RestoreCharsets(ids [4]byte, gl, gr int)
	// ApplicationCursorKeys reports whether DECCKM is set, so cursor keys send
	// SS3 sequences.
	ApplicationCursorKeys() bool
	// BracketedPasteEnabled reports whether bracketed paste (mode 2004) is on.
	BracketedPasteEnabled() bool
	// FocusReportingEnabled reports whether focus reporting (mode 1004) is on.
	FocusReportingEnabled() bool

	// Soft wraps. RowSoftWrapped reports whether a row of the active screen
	// carries on to the next row because autowrap moved the text there, as
	// opposed to a line that happens to fill the row and then ends.
	// ScrollbackSoftWrapped is the same for a history line, oldest first.
	// known is false where the backend cannot tell, and a caller must then
	// treat the row as ending.
	RowSoftWrapped(y int) (wrapped, known bool)
	// ScrollbackSoftWrapped is RowSoftWrapped for history line index, oldest
	// first.
	ScrollbackSoftWrapped(index int) (wrapped, known bool)
	// RestoreSoftWraps sets the soft-wrap flags a snapshot carries, after
	// its cells are written: screen is one flag per row of the active screen,
	// and history one per row of the newest history rows, oldest first,
	// aligned to the end of the history. A row with no flag given reads as
	// ending, so a nil screen clears every screen row, and a nil history
	// clears the newest history row, the one that could carry on into a
	// screen the snapshot replaced. The screen under an active alternate
	// screen is cleared too: its flags do not travel.
	RestoreSoftWraps(screen, history []bool)
	// RowPadded and ScrollbackPadded report whether a wrapped row ended a
	// column early because a wide character did not fit in its last column,
	// so that column is padding and not text. RestorePads sets the flags a
	// snapshot carries, after RestoreSoftWraps, aligned the same way; it
	// only marks rows that are wrapped. A backend that does not track it
	// reports false and ignores the restore.
	RowPadded(y int) bool
	// ScrollbackPadded is RowPadded for history line index, oldest first.
	ScrollbackPadded(index int) bool
	// RestorePads sets the padding flags RowPadded and ScrollbackPadded report.
	RestorePads(screen, history []bool)

	// Scrollback.
	ScrollbackLen() int
	// ScrollbackGeneration changes whenever the main screen's history does:
	// a line pushed, the ring trimmed, cleared or resized. A reader that
	// derived something from the history can keep it while the number
	// stays the same.
	ScrollbackGeneration() uint64
	// ScrollbackLine returns history line index, oldest first, or nil when
	// index is out of range.
	ScrollbackLine(index int) uv.Line
	// ScrollbackRows, ScrollbackText and CopyScrollback are for a reader of
	// many history lines at once. ScrollbackLine decodes each line into a
	// fresh line of 112-byte cells and keeps the newest in a cache for the
	// renderer, which a walk of the whole history churns and then pins.
	// These go round the cache.
	//
	// ScrollbackRows calls fn with each history line from index from to
	// end-1, oldest first, decoded to its full width into a buffer reused
	// from line to line: fn must copy what it keeps. It stops when fn
	// returns false. fn must not call the terminal, which may hold its own
	// lock while fn runs.
	ScrollbackRows(from, end int, fn func(index int, line uv.Line) bool)
	// ScrollbackText is ScrollbackRows for a reader that wants only the
	// text: each line is its cells' content and width, with no style and no
	// cell built. cells runs up to the line's last stored cell, and the
	// columns from len(cells) to width are spaces.
	ScrollbackText(from, end int, fn func(index, width int, cells []TextCell) bool)
	// CopyScrollback copies history lines from index from to end-1, with
	// their wrap and padding flags, into a form a reader decodes after it
	// releases the terminal.
	CopyScrollback(from, end int) *ScrollbackCopy
	// PushScrollbackLine appends line to the main screen's history, to prime
	// an emulator from a snapshot.
	PushScrollbackLine(line uv.Line)
	// ClearScrollback empties the main screen's history.
	ClearScrollback()
	// SetScrollbackMaxLines sets how many lines the history keeps.
	SetScrollbackMaxLines(maxLines int)

	// Input encoding toward the guest.
	SendMouse(m Mouse)
	// EncodeMouseEvent returns the report the guest's mouse mode gives for m,
	// or "" when the guest does not want it.
	EncodeMouseEvent(m Mouse) string
	// SendMouseAt and EncodeMouseEventAt also take the pointer's pixel
	// position inside the pane, which a guest in SGR-pixel mode (1016) is
	// told instead of the cell centre.
	SendMouseAt(m Mouse, at MousePixel)
	// EncodeMouseEventAt is EncodeMouseEvent with the pixel position at.
	EncodeMouseEventAt(m Mouse, at MousePixel) string
	// HasMouseMode reports whether the guest has any mouse tracking mode on.
	HasMouseMode() bool
	// HasPixelMouseMode reports whether the guest tracks the mouse in
	// SGR-pixel mode (1016).
	HasPixelMouseMode() bool
	// HasAllMotionMode reports whether the guest tracks all mouse motion
	// (mode 1003).
	HasAllMotionMode() bool
	// HasCellMotionMode reports whether the guest tracks motion while a button
	// is pressed (mode 1002).
	HasCellMotionMode() bool
	// KittyKeyboardFlags returns the kitty keyboard protocol flags in effect.
	KittyKeyboardFlags() int
	// KittyKeyboardStack returns a copy of the active screen's kitty keyboard
	// flag stack, base entry first.
	KittyKeyboardStack() []int
	// RestoreKittyKeyboardState puts back the stack KittyKeyboardStack
	// returned, on the active screen. An empty stack changes nothing.
	RestoreKittyKeyboardState(stack []int)
	// KittyKeyboardMainStack is the main screen's flag stack while the
	// alternate screen is in use, nil otherwise. RestoreKittyKeyboardMainStack
	// puts it back.
	KittyKeyboardMainStack() []int
	// RestoreKittyKeyboardMainStack puts back the stack KittyKeyboardMainStack
	// returned. An empty stack changes nothing.
	RestoreKittyKeyboardMainStack(stack []int)
	// DisableKittyKeyboardProtocol stops the emulator offering the kitty
	// keyboard protocol, for a pane whose PTY cannot carry it. See
	// Emulator.DisableKittyKeyboardProtocol.
	DisableKittyKeyboardProtocol()
	// KittyKeyboardUnavailable reports whether DisableKittyKeyboardProtocol
	// was called.
	KittyKeyboardUnavailable() bool
	// ModifyOtherKeys is the xterm modifyOtherKeys level the guest set with
	// XTMODKEYS (CSI > 4 ; n m): 0 off, 1 or 2. See EncodeModifyOtherKeys.
	ModifyOtherKeys() int
	// RestoreModifyOtherKeys puts back the level ModifyOtherKeys returned.
	// A level outside 0 to 2 changes nothing.
	RestoreModifyOtherKeys(level int)

	// Colors.
	SetThemeColors(fg, bg, cur color.Color, ansiPalette [16]color.Color)
	// SetReportColors sets the colours an OSC 10 and OSC 11 query is answered
	// with while the guest has not set its own: the ground the pane is really
	// drawn on, when that is not the default. A nil colour keeps the default
	// answer. Nothing is drawn differently; it only changes the answer.
	SetReportColors(fg, bg color.Color)
	// SetReportPalette sets what an OSC 4 query for one of the sixteen ANSI
	// slots is answered with while neither the guest nor a theme has set that
	// slot: the host terminal's own colour, when tuios knows it. A nil entry
	// keeps the default answer. Like SetReportColors it changes only the
	// answer; the slot is still drawn by the host.
	SetReportPalette(pal [16]color.Color)
	// PaletteColor returns the colour of ANSI slot i (0 to 15) as it is drawn,
	// or nil for a slot out of range.
	PaletteColor(i int) color.Color
	// IndexedColor returns the colour of palette index i (0 to 255), or nil
	// for an index out of range.
	IndexedColor(i int) color.Color

	// Host hooks and graphics state.
	SetCallbacks(cb Callbacks)
	// GetCallbacks returns the callbacks SetCallbacks installed.
	GetCallbacks() Callbacks
	// SetScreenClearFunc sets the ScreenClear callback and keeps the others.
	SetScreenClearFunc(f func())
	// SetKittyPassthroughFunc installs the reader of every graphics
	// command. fn must not write to rawData: cmd.RawPayload shares its bytes.
	SetKittyPassthroughFunc(fn func(cmd *KittyCommand, rawData []byte))
	// SetKittyHeaderOnly says whether the passthrough acts on the control
	// keys alone, so the payload is not decoded. See ParseKittyHeader.
	SetKittyHeaderOnly(on bool)
	// SetKittyUploadAnswers says whether this emulator answers the guest's
	// kitty uploads and placements. A client emulator of a daemon pane does
	// not: the daemon's does. See KittyGuestImages.
	SetKittyUploadAnswers(on bool)
	// SetKittyFilesElsewhere says the pane runs on another machine, so a file
	// it names for an upload is refused without a look at it.
	SetKittyFilesElsewhere(on bool)
	// KittyGuestImagesState and RestoreKittyGuestImages carry the ids given
	// to kitty image numbers from the daemon to a client that attaches.
	KittyGuestImagesState() *KittyGuestImagesState
	// RestoreKittyGuestImages puts back the state KittyGuestImagesState
	// returned.
	RestoreKittyGuestImages(s *KittyGuestImagesState)
	// SetKittyImageIDTranslator installs the guest-to-host image id mapping
	// used for kitty Unicode placeholder cells. See kitty_placeholder.go.
	SetKittyImageIDTranslator(fn KittyImageIDTranslator)
	// SetKittyPlaceholderMode says whether placeholder cells are kept or
	// dropped. See kitty_placeholder.go.
	SetKittyPlaceholderMode(m KittyPlaceholderMode)
	// SetSixelPassthroughFunc installs the function that takes a guest's
	// sixel image and returns the id its cells are marked with. See
	// sixel_marker.go.
	SetSixelPassthroughFunc(fn SixelPassthroughFunc)
	// SetSixelAdvertised installs the function that decides whether the
	// pane is told it can draw sixel: attribute 4 in the DA1 reply, and an
	// answer to XTSMGRAPHICS. Nil tells it nothing.
	SetSixelAdvertised(fn func() bool)
	// SetTextSizingFunc installs the function that takes each OSC 66 text
	// sizing sequence, with the cursor position, the scale and the length of
	// the text in characters.
	SetTextSizingFunc(fn func(rawOSC []byte, cursorX, cursorY, scale, textLen int))
	// SetReflowFunc sets a function a resize calls after it reflowed rows.
	// remap takes a row counted from the oldest history row, as an image
	// placement records it, and returns where that row's text is now. A
	// backend that cannot say never calls fn.
	SetReflowFunc(fn func(remap func(absLine int) int))
	// SetCellSize sets the size of one cell in pixels, for size reports and
	// SGR-pixel mouse reports. A size below 1 is ignored.
	SetCellSize(width, height int)
	// KittyMainState returns the kitty image state of the main screen.
	KittyMainState() *KittyState
	// KittyAltState returns the kitty image state of the alternate screen.
	KittyAltState() *KittyState
	// ReserveImageSpace moves the cursor below an image rows high, scrolling
	// as needed, so the next output does not cover the image.
	ReserveImageSpace(rows, cols int)
	// SemanticMarkers returns the OSC 133 prompt and command markers.
	SemanticMarkers() *SemanticMarkerList
}

Terminal is the emulator surface the rest of tuios consumes. It exists so the implementation can be swapped at build time (see New): the pure-Go Emulator is the default, a libghostty-vt backed implementation is available behind the ghostty build tag. Exactly one implementation is compiled into a binary; differential comparison between the two lives in tests only.

The method set is the complete external surface of Emulator as of the extraction: every method here has at least one caller outside this package. Grow it only when a caller needs more, and implement additions on both backends in the same change.

Only package vt implements Terminal, and it may gain methods in any release. Use it, and do not implement it: a type outside this package that implements it can stop compiling on an update. A program that needs its own implementation should depend on Screen, which stays small.

func New

func New(w, h int) Terminal

New returns the emulator implementation selected at build time. The default build is pure Go so that go install works with no toolchain and CGO_ENABLED=0 cross-compilation keeps working; the ghostty build tag swaps in the libghostty-vt backed implementation.

func NewWithScrollback

func NewWithScrollback(w, h, maxLines int) Terminal

NewWithScrollback is New with the scrollback depth fixed at construction. Every pane is built through here because the libghostty backend can only take the depth when its terminal is made; see the ghostty variant.

type TextCell

type TextCell struct {
	Content []byte // text of the cell
	Width   int    // columns the cell takes
}

TextCell is one history cell without its style or link: what it shows and how many columns it takes. Content is the cell's text, empty for the spacer a wide character leaves in the column after it. It aliases the history's own storage, so it is valid only until the callback it was passed to returns.

type TitleEntry

type TitleEntry struct {
	Title, Icon       string // saved title and icon name
	HasTitle, HasIcon bool   // whether the entry holds each
}

TitleEntry is one entry of the title stack. A push can save the title, the icon name or both, and a pop puts back only what the entry holds.

type Titles

type Titles struct {
	Title, Icon string       // window title and icon name
	Stack       []TitleEntry // saved titles, oldest first
}

Titles is the window title, the icon name and the title stack XTWINOPS 22 and 23 push to and pop from, oldest entry first.

Directories

Path Synopsis
Package snapshot captures what an emulator holds, packs it for a wire or a file, and brings another emulator to the same state.
Package snapshot captures what an emulator holds, packs it for a wire or a file, and brings another emulator to the same state.
Package vtgen generates terminal input that looks like something a program would actually emit.
Package vtgen generates terminal input that looks like something a program would actually emit.

Jump to

Keyboard shortcuts

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