Documentation
¶
Overview ¶
Package lineedit is a line editor as a pure model: key events in, the line, the cursor, candidate listings and submitted lines out. It has no terminal, DOM or widget type in it, so every front end — the playground's xterm.js page, a go-widgets terminal widget, wctr's terminal, the guest shell's sh — drives the same implementation. It imports the standard library only (and no net/http), so a WebAssembly guest can link it without growing: it is its own module, github.com/go-wasmcontainers/ engine/lineedit, versioned by tags lineedit/vX.Y.Z.
It provides: editing (insert, Backspace, Delete, Left/Right, Home/End, Ctrl-A/E/B/F, Ctrl-U/K/W, Ctrl-L), history (Up/Down, Ctrl-P/N, bounded, exportable for persistence), reverse incremental search (Ctrl-R), and Tab completion through a Completer: a unique match is inserted with a trailing space (unless the completer says noSpace), several are completed to their longest common prefix, a second Tab lists them in columns, or as "value -- description" lines when candidates have descriptions, asking "Display all N possibilities? (y or n)" past a threshold. Completion understands the line's quoting. Columns are counted with RuneWidth, so wide (CJK, emoji) and combining characters place the cursor correctly.
ParseKeys turns terminal input (what xterm.js's onData delivers) into keys; Renderer turns successive States into ANSI output for a terminal. A widget can ignore both and use Key and State directly. Reader is the ready-made driver for a raw-mode terminal stream: it reads bytes, decodes keys, edits and draws, and returns one line per ReadLine.
Index ¶
- Constants
- Variables
- func Format(cs []Candidate, cols int) []string
- func Quote(w string, quote byte, closed bool) string
- func RuneWidth(r rune) int
- func Split(line string) ([]string, error)
- func Width(s string) int
- type Candidate
- type Completer
- type Editor
- type Event
- type Key
- type KeyCode
- type Options
- type Partial
- type Reader
- type Renderer
- type State
Constants ¶
const MaxLine = 4096
MaxLine bounds the line the splitter accepts.
Variables ¶
var ErrInterrupt = errors.New("interrupt")
ErrInterrupt is what Reader.ReadLine returns for Ctrl-C.
var ErrUnterminated = errors.New("unterminated quote or escape")
ErrUnterminated is returned for an open quote or a trailing backslash.
Functions ¶
func Format ¶
Format lays candidates out for a terminal cols wide: one aligned "value -- description" line each when any has a description (as zsh and fish show them), columns filled top to bottom otherwise (as bash).
func Quote ¶
Quote renders a word for insertion: inside the given open quote (0 for none), so that Split reads it back as w; closed adds the closing quote.
func RuneWidth ¶
RuneWidth is the number of terminal columns r takes: 0 for a combining mark or a zero-width character (a joiner, a variation selector), 2 for the wide and fullwidth East Asian characters and the emoji blocks, 1 otherwise. The wide ranges are an approximation of Unicode's East Asian Width property (UAX #11), enough to place the cursor for CJK text and emoji.
Types ¶
type Candidate ¶
type Candidate struct {
// Value is the text inserted; Description is shown beside it in a
// listing.
Value string `json:"value"`
Description string `json:"description,omitempty"`
}
Candidate is one completion choice.
type Completer ¶
type Completer func(ctx context.Context, words []string, current string) (cands []Candidate, noSpace bool)
Completer lists the candidates for the word being typed: words are the complete words before it, current is its (unquoted) prefix. noSpace asks that a unique match get no trailing space.
type Editor ¶
type Editor struct {
// contains filtered or unexported fields
}
Editor is the line editor.
func (*Editor) SetHistory ¶
SetHistory replaces the history (a restored one), bounded. A restored history is untrusted (browser storage, a file): an entry that a user could not have typed — invalid UTF-8 or a non-printable rune, which the renderer would otherwise write to the terminal as is — is dropped.
type Event ¶
type Event struct {
// Submit is set when Enter ended a line; Line is that line.
Submit bool
Line string
// Print are lines to show above the prompt (a candidate listing, a
// question); the line is then shown again below them.
Print []string
// Interrupt is Ctrl-C on an empty or abandoned line ("^C").
Interrupt bool
// Clear is Ctrl-L: clear the screen, keep the line.
Clear bool
// EOF is Ctrl-D on an empty line.
EOF bool
// Bell is a key that did nothing (no completion, end of history).
Bell bool
}
Event is what a key did besides editing.
type Key ¶
Key is one key press.
type KeyCode ¶
type KeyCode int
KeyCode names a non-character key.
const ( KeyRune KeyCode = iota // a printable character, in Key.Rune KeyEnter KeyBackspace KeyDelete KeyLeft KeyRight KeyHome KeyEnd KeyUp KeyDown KeyTab KeyEscape KeyCtrlA KeyCtrlB KeyCtrlC KeyCtrlD KeyCtrlE KeyCtrlF KeyCtrlG KeyCtrlK KeyCtrlL KeyCtrlN KeyCtrlP KeyCtrlR KeyCtrlU KeyCtrlW KeyUnknown )
type Options ¶
type Options struct {
// Prompt is shown before the line (default "$ ").
Prompt string
// Complete answers Tab; nil disables completion.
Complete Completer
// HistorySize bounds the history (default 500).
HistorySize int
// Cols is the display width used for listings (default 80); SetCols
// changes it.
Cols int
}
Options configure an Editor.
type Partial ¶
type Partial struct {
// Words are the complete words before the one being typed.
Words []string
// Current is the word being typed, unquoted ("" for a new word).
Current string
// Start is the byte offset in the line where the current word begins.
Start int
// Quote is the quote the current word is still inside (' or "), or 0.
Quote byte
}
Partial is the line before the cursor, split for completion.
func SplitPartial ¶
SplitPartial splits a line prefix the way Split does, except that the last word may be unterminated (an open quote, a trailing backslash).
type Reader ¶
type Reader struct {
In io.Reader
Out io.Writer
// Cols returns the terminal width (nil, or 0 or less: 80).
Cols func() int
// Complete answers Tab; nil disables completion.
Complete Completer
// HistorySize bounds the history (0: 500).
HistorySize int
// PromptStyle wraps the prompt as Renderer.PromptStyle does; "" is
// none, which is what a shell wants (its prompt carries its own style).
PromptStyle string
// contains filtered or unexported fields
}
Reader edits lines read from a terminal in raw mode (no echo, no line buffering): it decodes the bytes into keys, applies them to an Editor and draws the result with a Renderer. It reads one byte at a time, so nothing past the line is consumed from In. Putting the terminal in raw mode is the caller's business (and only while a line is being typed).
func (*Reader) ReadLine ¶
ReadLine shows prompt and returns the line typed, without its newline. It returns io.EOF for Ctrl-D on an empty line (or the end of In with nothing typed), ErrInterrupt for Ctrl-C, and the error of In otherwise. A prompt of several lines is written once, its last line redrawn.
type Renderer ¶
type Renderer struct {
// Cols is the terminal width.
Cols int
// PromptStyle wraps the prompt (default bold cyan); "" for none.
PromptStyle string
// contains filtered or unexported fields
}
Renderer turns States into ANSI output for a terminal that does not wrap lines on its own behalf (xterm.js does: the renderer accounts for it). It counts columns with RuneWidth; a prompt holding escape sequences is counted as the text it is, so a coloured prompt belongs in PromptStyle.
func (*Renderer) Forget ¶
func (r *Renderer) Forget()
Forget drops what was rendered (the screen was cleared).
func (*Renderer) Leave ¶
Leave moves the cursor below the input (after Enter, Ctrl-C) and forgets it: the next Render starts a fresh prompt.