ansi

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package ansi is what an escape sequence is made of.

Escape sequences travel in both directions and carry many meanings. What their readers share is syntax: which bytes are parameters, which byte ends a sequence, what an empty field means, and where a sequence stops. This package owns only that syntax so every semantic decoder can build on the same byte-level rules.

Nothing here decides what a sequence means. A final byte of 'm' is a style to one reader and nothing at all to the other, and this package has no opinion about either.

What a sequence looks like

Three shapes, and everything else is text:

ESC [ 1 ; 31 m          a control sequence: parameters, then a final byte
ESC ] 8 ; ; url ST      a string command: a body, then a terminator
ESC ( B                 an escape with intermediates and a final byte

Index

Constants

View Source
const (
	// Escape introduces every sequence there is.
	Escape = 0x1b
	// Bell ends a string command on the terminals that never adopted the standard
	// terminator, which is most of them.
	Bell = 0x07
)
View Source
const Limit = 1 << 20

Limit is well past any real parameter and short of anything that could overflow. A number beyond it is treated as malformed.

Variables

View Source
var ErrSequenceTooLong = errors.New("ansi: unfinished sequence exceeds 65536 bytes")

ErrSequenceTooLong means an unfinished escape sequence crossed the amount a stream scanner will retain. A sequence that has not ended within that bound is more likely an accidental or hostile retention leak than terminal syntax.

Functions

func Body

func Body(b byte) bool

Body reports whether b may appear between a control sequence's introducer and the byte that ends it: an intermediate byte, which selects a variant of the sequence, or a parameter byte, which is a digit, a separator, or the marker a private sequence opens with.

The two halves are not separately exported. Nothing outside this package has ever needed to tell them apart — what a reader asks is "is this still the body" and then "is this the end" — and a predicate nobody calls is a predicate nobody keeps true.

func Final

func Final(b byte) bool

Final reports whether b ends a control sequence and says what it was.

Types

type Kind

type Kind uint8

Kind says what a piece of a stream turned out to be.

const (
	// Plain is text carrying no sequence.
	Plain Kind = iota
	// Control is ESC [ — parameters and a final byte. Styling, cursor movement,
	// erasure and mode changes are all this shape.
	Control
	// String is a command with a body and a terminator: an operating system
	// command, a device control string, and the three like them. [Piece.Final]
	// holds the byte that introduced it, because that is what says which.
	String
	// Other is an escape with intermediates and a final byte and no parameters:
	// selecting a character set, entering keypad mode, saving the cursor.
	Other
	// Malformed is bytes that began like a sequence and cannot be one. They are a
	// piece of their own rather than text, because a reader that fell back to
	// reading them as text would print the introducer.
	Malformed
)

type Parameter added in v0.4.0

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

Parameter is one semicolon-separated parameter and its colon-separated subparameters.

A field left empty is the protocol's default, which is zero. A field that is not a number, or is far larger than any parameter legitimately gets, is -1: a decoder can then refuse the sequence instead of acting on a value invented for it. Parameter is an immutable view into its Params; its methods do not expose the parser's storage.

func (Parameter) At added in v0.4.0

func (p Parameter) At(i int) int

At returns field i, or zero when i is outside the parameter. Zero is also the protocol default for an omitted field.

func (Parameter) Len added in v0.4.0

func (p Parameter) Len() int

Len is how many fields the parameter carries, including its leading value.

func (Parameter) Values added in v0.4.0

func (p Parameter) Values() iter.Seq[int]

Values visits the parameter's fields in wire order without exposing mutable parser storage.

type Params

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

Params is a sequence's parameter section, parsed once and read by whichever decoder the final byte selects.

There is one parser rather than one per sequence family. Two parsers over the same syntax drift: they disagree about what an empty field means, or about what to do with a field that is not a number, and the sequence that exercises the difference is the one nobody tested.

func Parse

func Parse(body string) Params

Parse reads a control sequence's parameter section — everything between the introducer and the final byte.

func (Params) At

func (ps Params) At(i int) int

At is the leading value of group i, or zero when the group is absent.

func (Params) First

func (ps Params) First() int

First is the leading parameter, or zero when there was none. Zero is the protocol's own default for a missing parameter, so a caller need not distinguish.

func (Params) Group

func (ps Params) Group(i int) Parameter

Group is parameter i and its subparameters, or an empty parameter when i is outside the sequence.

func (Params) Len added in v0.4.0

func (ps Params) Len() int

Len is how many parameters the sequence carried.

func (Params) Marker added in v0.4.0

func (ps Params) Marker() byte

Marker is the byte a private sequence begins with — '<' for a mouse report, '?' for a terminal's answer about a mode — or zero for an ordinary sequence.

func (Params) Valid added in v0.4.0

func (ps Params) Valid() bool

Valid reports whether every parameter field was numeric and within Limit. Empty fields are valid protocol defaults; malformed and excessive fields are represented by a negative value and make the complete parameter section invalid.

type Piece

type Piece struct {
	Kind Kind
	// Raw is the piece's own bytes, whole. For a sequence it includes the
	// introducer and the terminator, so that a reader passing what it does not
	// understand through to a terminal can pass it on exactly as it came.
	Raw string
	// Body is the part between the introducer and the end: the parameter section
	// of a [Control] piece, or a [String] piece's body without its terminator.
	// Empty for anything else.
	Body string
	// Final is the byte that ended a [Control] or [Other] piece and says what it
	// was, and the byte that introduced a [String] piece, for the same reason.
	Final byte
}

Piece is one part of a stream: a run of text, or one sequence.

func Next

func Next(s string) (p Piece, n int, ok bool)

Next reads the piece at the front of s.

It reports the piece and how many bytes it took. The false case is the one that matters for anything reading a stream: what is at the front of s could still become a longer sequence or UTF-8 character, nothing about it can be decided until more arrives, and no bytes were consumed. Scanner owns that undecided suffix for callers reading arbitrary chunks.

Text runs up to the next escape byte and no further, so a caller is handed the largest run it can treat as one thing.

type Scanner added in v0.4.0

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

Scanner turns arbitrarily chunked terminal bytes into complete [Piece]s.

Feed calls its visitor once for each complete piece, in order. A Piece and its strings are borrowed for that call; a visitor that retains one must clone the strings it needs. An incomplete escape sequence or UTF-8 character stays in the Scanner until another Feed completes it. Pending exposes that suffix for an owner settling the end of a stream.

A Scanner belongs to one goroutine and must not be copied after its first use. Its zero value is ready to use.

func (*Scanner) Feed added in v0.4.0

func (s *Scanner) Feed(chunk string, visit func(Piece) error) error

Feed scans chunk and visits every piece that became complete.

If visit returns an error, Feed stops and returns it. The remainder is discarded: a semantic consumer that rejected a complete piece cannot safely resume midway through the same chunk. ErrSequenceTooLong likewise clears the runaway suffix, leaving the Scanner ready for a later independent chunk.

func (*Scanner) Pending added in v0.4.0

func (s *Scanner) Pending() string

Pending is the undecided suffix waiting for another chunk. The returned string is valid until the next call to Feed or Reset.

func (*Scanner) Reset added in v0.4.0

func (s *Scanner) Reset()

Reset drops an undecided suffix and returns the Scanner to its zero state.

Jump to

Keyboard shortcuts

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