emu

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2024 License: MIT, MIT Imports: 12 Imported by: 0

README

emu (formerly vt10x)

Package emu provides a VT100-compatible terminal emulator. For the most part it attempts to emulate xterm as closely as possible (ie to be used with TERM=xterm-256color.)

emu's basic mode of operation is quite simple: you Write() some bytes and it will correctly calculate the state of the virtual terminal which you can happily capture and send elsewhere (with Terminal.View()).

emu's magic, however, comes from Terminal.Flow(), which is an API for viewing the terminal's scrollback buffer with a viewport of arbitrary size. This is important because cy's core feature is to be able to replay terminal sessions, the lines of which should wrap appropriately to fit your terminal screen.

This package is a fork of github.com/hinshun/vt10x. The original library was rough, incomplete, and had a range of serious bugs that I discovered after integrating it. Because of this, little of the original code remains.

Documentation

Overview

Package terminal is a emu terminal emulation backend, influenced largely by st, rxvt, xterm, and iTerm as reference. Use it for terminal muxing, a terminal emulation frontend, or wherever else you need terminal emulation.

In development, but very usable.

Index

Constants

View Source
const (
	// TODO(cfoust): 11/14/23 I'm genuinely not sure why this isn't in terminfo,
	// but it is supported in the VT100 standard
	// See:
	// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
	// https://vt100.net/docs/vt510-rm/LineFeedMode.html
	LineFeedMode   = "\033[20h"
	EnterAltScreen = "\033[?1049h"
	ExitAltScreen  = "\033[?1049l"
)
View Source
const (
	AttrReverse = 1 << iota
	AttrUnderline
	AttrBold
	AttrGfx
	AttrItalic
	AttrStrikethrough
	AttrBlink
	AttrWrap
	AttrBlank
	AttrTransparent
)

TODO(cfoust): 05/19/23 combine this with the other declaration

Variables

View Source
var (
	RGBPattern  = regexp.MustCompile(`^([\da-f]{1})\/([\da-f]{1})\/([\da-f]{1})$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$`)
	HashPattern = regexp.MustCompile(`[\da-f]`)
)

Functions

func IsAltMode added in v0.1.11

func IsAltMode(mode ModeFlag) bool

Types

type Cell

type Cell struct {
	geom.Vec2
	Glyph
}

type ChangeFlag

type ChangeFlag uint32

ChangeFlag represents possible state changes of the terminal.

const (
	ChangedScreen ChangeFlag = 1 << iota
	ChangedTitle
)

Terminal changes to occur in VT.ReadState

type Color

type Color uint32

Color maps to the ANSI colors [0, 16) and the xterm colors [16, 256).

const (
	Black Color = iota
	Red
	Green
	Yellow
	Blue
	Magenta
	Cyan
	LightGrey
	DarkGrey
	LightRed
	LightGreen
	LightYellow
	LightBlue
	LightMagenta
	LightCyan
	White
)

ANSI color values

const (
	DefaultFG Color = 0
	DefaultBG Color = Color(colorBG)
)

Default colors are potentially distinct to allow for special behavior. For example, a transparent background. Otherwise, the simple case is to map default colors to another color.

func ANSIColor added in v0.6.0

func ANSIColor(color int) Color

func RGBColor added in v0.6.0

func RGBColor(r, g, b int) Color

func XTermColor added in v0.6.0

func XTermColor(color int) Color

func (Color) ANSI

func (c Color) ANSI() (color int, ok bool)

ANSI reports whether Color is within [0, 16) and returns that color if it is.

func (Color) Default added in v0.6.0

func (c Color) Default() bool

Default reports whether this color has been set. If false, it represents the default foreground or background color.

func (Color) RGB added in v0.6.0

func (c Color) RGB() (r, g, b int, ok bool)

RGB reports whether Color is in the RGB color space.

func (Color) XTerm added in v0.6.0

func (c Color) XTerm() (color int, ok bool)

XTerm reports whether Color is within [0, 256) and returns that color if it is.

type Cursor

type Cursor struct {
	geom.Vec2
	Attr  Glyph
	State uint8
	Style CursorStyle
}

type CursorStyle

type CursorStyle int
const (
	CursorStyleBlock CursorStyle = iota
	CursorStyleSteadyBlock
	CursorStyleUnderline
	CursorStyleBlinkUnderline
	CursorStyleBar
	CursorStyleBlinkBar
)

type Dirty added in v0.1.6

type Dirty struct {

	// line dirtiness
	Lines map[int]bool

	// the most recent cell that was `setChar`'d
	Print   Cell
	Printed bool

	Scroll   Scroll
	Scrolled bool

	Clear   geom.Rect
	Cleared bool

	Flag ChangeFlag
	// contains filtered or unexported fields
}

func (*Dirty) Hook added in v0.1.13

func (d *Dirty) Hook(hook string) (value, ok bool)

Hook returns true if the hook has appeared since the last Reset().

func (*Dirty) LastWrite added in v0.1.13

func (d *Dirty) LastWrite() WriteID

func (*Dirty) Reset added in v0.1.6

func (d *Dirty) Reset()

Reset the change mask and dirtiness.

func (*Dirty) ScreenChanged added in v0.1.6

func (d *Dirty) ScreenChanged() bool

func (*Dirty) SetHooks added in v0.1.13

func (d *Dirty) SetHooks(hooks []string)

SetHooks registers strings to be compared against any Device Control String input. See https://vt100.net/docs/vt510-rm/chapter4.html for more information.

An example of a device control string is "\033Pcy\033". Specifying "cy" in a call to `SetHooks` means that if this specific byte sequence appears in the input to the terminal since the last Reset(), Hook("cy") will return true.

type FlowResult added in v0.1.13

type FlowResult struct {
	// The total number of physical lines in the history AND on the screen
	NumLines int
	Lines    []ScreenLine
	OK       bool
	Cursor   Cursor
	CursorOK bool
}

func (*FlowResult) Coord added in v0.1.13

func (f *FlowResult) Coord(pos geom.Vec2) (result geom.Vec2, ok bool)

Coord gets the coordinate for a cell on the "screen" produced by the original viewport.

type Glyph

type Glyph struct {
	Char   rune
	Mode   int16
	FG, BG Color
	Write  WriteID
}

func EmptyGlyph

func EmptyGlyph() Glyph

func (Glyph) Equal added in v0.1.15

func (g Glyph) Equal(other Glyph) bool

func (Glyph) IsDefault added in v0.1.13

func (g Glyph) IsDefault() bool

func (Glyph) IsEmpty added in v0.1.5

func (g Glyph) IsEmpty() bool

func (Glyph) Transparent added in v0.1.6

func (g Glyph) Transparent() bool

func (Glyph) Width added in v0.1.13

func (g Glyph) Width() int

type Line

type Line []Glyph

func LineFromString added in v0.1.13

func LineFromString(text string) Line

func (Line) Clone added in v0.1.13

func (l Line) Clone() Line

func (Line) IsEmpty added in v0.1.13

func (l Line) IsEmpty() bool

func (Line) IsWrapped added in v0.1.13

func (l Line) IsWrapped() bool

func (Line) Length added in v0.1.13

func (l Line) Length() int

Length returns the physical length of the line, accounting for the width of the final rune. Be aware that when the final rune is a double-width character (such as a CJK ideogram) Length can return a number that is greater than the number of Glyphs in the Line.

func (Line) Occupancy added in v0.1.13

func (l Line) Occupancy() []bool

Get the occupancy state of the given line.

func (Line) String

func (l Line) String() (str string)

func (Line) Whitespace added in v0.1.13

func (l Line) Whitespace() (first, last int)

Whitespace returns the indices of the first and last non-empty cells for the given line.

type ModeFlag

type ModeFlag uint32

ModeFlag represents various terminal mode states.

const (
	ModeWrap ModeFlag = 1 << iota
	ModeInsert
	ModeAppKeypad
	ModeAltScreen
	ModeCRLF
	ModeMouseButton
	ModeMouseMotion
	ModeReverse
	ModeKeyboardLock
	ModeHide
	ModeEcho
	ModeAppCursor
	ModeMouseSgr
	Mode8bit
	ModeBlink
	ModeFBlink
	ModeFocus
	ModeMouseX10
	ModeMouseMany
	ModeMouseMask = ModeMouseButton | ModeMouseMotion | ModeMouseX10 | ModeMouseMany
)

Terminal modes

type ScreenLine added in v0.1.13

type ScreenLine struct {
	// The coordinate of this row
	R int
	// The columns in that row this line occupies, [C0,C1)
	C0, C1 int
	// The slice containing the glyphs in this range
	Chars Line
}

func (ScreenLine) Root added in v0.1.13

func (l ScreenLine) Root() geom.Vec2

Root returns the coordinate of the beginning of this ScreenLine.

type Scroll added in v0.1.6

type Scroll struct {
	Up            bool
	Origin, Count int
}

type State

type State struct {
	deadlock.RWMutex
	DebugLogger *log.Logger
	// contains filtered or unexported fields
}

State represents the terminal emulation state. Use Lock/Unlock methods to synchronize data access with VT.

func (*State) Cell

func (t *State) Cell(x, y int) Glyph

Cell returns the glyph containing the character code, foreground color, and background color at position (x, y) relative to the top left of the terminal. TODO(cfoust): 08/24/23 move this to row, col

func (*State) Changes added in v0.1.6

func (t *State) Changes() *Dirty

func (*State) CsiDispatch

func (t *State) CsiDispatch(params []int64, intermediates []byte, ignore bool, r rune)

func (*State) Cursor

func (t *State) Cursor() Cursor

Cursor returns the current position of the cursor.

func (*State) CursorVisible

func (t *State) CursorVisible() bool

CursorVisible returns the visible state of the cursor.

func (*State) EscDispatch

func (t *State) EscDispatch(intermediates []byte, ignore bool, b byte)

func (*State) Execute

func (t *State) Execute(b byte)

func (*State) Flow added in v0.1.13

func (s *State) Flow(
	viewport, root geom.Vec2,
) (result FlowResult)

func (*State) GetLines added in v0.1.13

func (s *State) GetLines(start, end int) (lines []Line)

func (*State) History

func (t *State) History() []Line

func (*State) Hook

func (t *State) Hook(params []int64, intermediates []byte, ignore bool, r rune)

func (*State) IsAltMode added in v0.1.13

func (t *State) IsAltMode() bool

func (*State) Mode

func (t *State) Mode() ModeFlag

Mode returns the current terminal mode.

func (*State) OscDispatch

func (t *State) OscDispatch(params [][]byte, bellTerminated bool)

func (*State) Print

func (t *State) Print(c rune)

func (*State) Put

func (t *State) Put(b byte)

func (*State) Root added in v0.1.13

func (t *State) Root() geom.Vec2

func (*State) Screen

func (t *State) Screen() []Line

func (*State) Size

func (t *State) Size() geom.Vec2

func (*State) String

func (t *State) String() string

func (*State) Title

func (t *State) Title() string

Title returns the current title set via the tty.

func (*State) Unhook

func (t *State) Unhook()

type Terminal

type Terminal interface {
	// View displays the virtual terminal.
	View

	// Parse parses input and writes terminal changes to state.
	Parse(p []byte) (n int)

	// Write does the same as Parse, but locks first.
	io.Writer
}

Terminal represents the virtual terminal emulator.

func New

func New(opts ...TerminalOption) Terminal

New returns a new virtual terminal emulator.

type TerminalInfo

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

type TerminalOption

type TerminalOption func(*TerminalInfo)
var WithoutHistory TerminalOption = func(info *TerminalInfo) {
	info.disableHistory = true
}

Providing WithoutHistory disables the scrollback buffer, which drastically reduces the amount of memory a Terminal uses.

func WithSize

func WithSize(size geom.Vec2) TerminalOption

func WithWriter

func WithWriter(w io.Writer) TerminalOption

type View

type View interface {
	// String dumps the virtual terminal contents.
	fmt.Stringer

	// Size returns the size of the virtual terminal.
	Size() geom.Vec2

	// Resize changes the size of the virtual terminal.
	//Resize(cols, rows int)
	Resize(geom.Vec2)

	// Mode returns the current terminal mode.
	Mode() ModeFlag

	// Title represents the title of the console window.
	Title() string

	// Cell returns the glyph containing the character code, foreground color, and
	// background color at position (x, y) relative to the top left of the terminal.
	Cell(x, y int) Glyph

	// Cursor returns the current position of the cursor.
	Cursor() Cursor

	// CursorVisible returns the visible state of the cursor.
	CursorVisible() bool

	// Screen gets all of the lines on the screen.
	Screen() []Line

	// History returns the scrollback buffer.
	History() []Line

	IsAltMode() bool

	// The location in history of the top-left cell of the screen. The `R`
	// field refers to the line in history and the `C` refers to a column
	// in that line that the cell contains. For example, when only one line
	// is in the scrollback buffer and it does not wrap onto the screen,
	// Root() will return [1, 0].
	Root() geom.Vec2

	// Flow is an API for quickly rewrapping the physical (read: unwrapped)
	// lines to fit inside of the given viewport.
	//
	// For example, with a history that looks like this:
	// “`
	// abcdefg
	// !abc
	// foobarbaz
	// “`
	// where "!" represents a viewport with `R==2` and `C==3` would
	// return:
	// “`
	// abc
	// foo
	// “`
	//
	// A viewport with `R==-2` and `C==3` would return:
	// “`
	// bcd
	// efg
	// “`
	Flow(viewport, root geom.Vec2) FlowResult

	// GetLines gets unwrapped lines from the terminal's history.
	GetLines(start, end int) []Line

	Changes() *Dirty
}

View represents the view of the virtual terminal emulator.

type WriteID added in v0.1.13

type WriteID uint32

WriteID represents the unique ID of a single contiguous Write() to the terminal.

Jump to

Keyboard shortcuts

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