Documentation
¶
Overview ¶
Package keymap turns emacs key notation into structured keystrokes and resolves sequences of them against a prefix tree of bindings.
This package depends only on the standard library. Translating a terminal library's event type into a Key is deliberately somebody else's job, which is what keeps every rule in here unit-testable without a terminal.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LatinKey ¶ added in v0.9.1
LatinKey is the key of a US keyboard where a layout puts r, and false for a rune no layout nem knows puts anywhere - including every Latin one.
func SortContinuations ¶ added in v0.5.1
func SortContinuations(cs []Continuation)
SortContinuations puts cs in the order Continuations returns, for a caller that merges the continuations of several maps.
func SpecString ¶
SpecString renders a key sequence in canonical notation, the form used by config files and describe-bindings.
Types ¶
type Continuation ¶
type Continuation struct {
// Key is the next keystroke, normalized as the map stores it.
Key Key
// Command is the bound command name. Empty when IsPrefix.
Command string
// IsPrefix reports that this key leads to a further keymap rather than to a
// command, so pressing it waits for another key.
IsPrefix bool
// Count is how many bindings this key leads to: the recursive total beneath
// a prefix, and 1 for a leaf. A panel reporting "+register 3" is claiming
// three reachable commands, so counting only immediate children would lie
// about any nesting deeper than one level.
Count int
}
Continuation is one key that may follow a prefix.
A node in the tree is either terminal or internal — Map.Bind refuses to let a key be both a command and a prefix — so exactly one of Command and IsPrefix is meaningful on any given Continuation.
type Key ¶
type Key struct {
Rune rune // base character; 0 when Special != SpecialNone
Special SpecialKey // non-None for keys that have no character
Ctrl bool
Meta bool // emacs Meta: Alt, or an ESC prefix
// Shift is only meaningful when Special != SpecialNone: a rune carries its own
// case, so S- on a character is meaningless. Normalize enforces this by
// clearing Shift on any rune key, and ParseSpec rejects "S-a" outright.
Shift bool
}
Key is a single keystroke.
func Normalize ¶
Normalize folds the ambiguities that terminals impose on control keys, so a binding matches no matter which encoding the terminal happened to send.
The folds exist because a terminal does not transmit "Ctrl" as a modifier bit for control characters: it transmits a single byte in the C0 range, and several distinct keystrokes collapse onto the same byte before the program ever sees them. Folding to one canonical spelling is therefore recovering information the terminal already destroyed, not a policy choice.
Every fold here is unconditional. The one genuinely contentious case, C-h, is opt-in per Map via Map.TreatCtrlHAsBackspace.
func ParseSpec ¶
ParseSpec parses emacs key notation into a key sequence. Keys are separated by whitespace, so "C-x C-f" is two keystrokes and "C-x" is one.
It never panics; malformed input always comes back as an error.
func (Key) String ¶
String renders the key in canonical emacs notation. The result always parses back to the same key via ParseSpec, for every key this package can produce.
Modifiers are emitted in the fixed order C- M- S-. Shift is emitted only for special keys: a rune already carries its own case.
type Layout ¶ added in v0.9.1
type Layout int
Layout chooses between the layouts that put one letter on different keys.
const ( // LayoutAuto reads every layout nem knows. Persian and Arabic keyboards // put a few shared letters - ط د ذ ز ظ - on different keys; auto follows // the Persian ones. LayoutAuto Layout = iota // LayoutArabic is auto following the Arabic keyboard for those letters. LayoutArabic // LayoutOff reads nothing back: keys are what the terminal says. LayoutOff )
type Map ¶
type Map struct {
// TreatCtrlHAsBackspace folds C-h into <backspace>. Off by default, because
// in emacs C-h is the help prefix; turn it on for terminals whose erase
// character is ^H. See the comment in Map.normalize.
TreatCtrlHAsBackspace bool
// contains filtered or unexported fields
}
Map resolves key sequences to command names.
The zero value is not usable; call New.
func (*Map) Bind ¶
Bind binds a key sequence to a command name, creating intermediate prefix maps as needed. Rebinding an existing sequence replaces it silently.
It fails if the sequence would shadow, or be shadowed by, an existing binding: binding C-x C-f when C-x is already a command, or binding C-x when C-x C-f exists. The error names both bindings.
func (*Map) Bindings ¶
Bindings returns every binding as canonical spec string to command name, for describe-bindings and for M-x to show where a command lives.
func (*Map) Continuations ¶
func (m *Map) Continuations(seq []Key) []Continuation
Continuations lists the keys that may follow seq.
This is what a which-key panel is built from: after a pending prefix, it answers "what can I press now, and what will it do".
seq is normalized the same way Map.Lookup normalizes it, including this map's opt-in folds, so a caller may pass keys straight from the terminal decoder. It returns nil when seq resolves to a complete binding (a terminal node has no children, so nothing can follow it) and when seq matches nothing at all — neither case is an error.
The result is ordered for a human reading a panel: plain runes first, since those are the quickest to press and read as menu letters; then runes carrying Ctrl or Meta; then named keys such as <f1> and <up>. Within each group, keys are sorted ascending by canonical notation. The order is total and stable, which matters because Go randomizes map iteration and an unsorted implementation would reshuffle a panel between one keystroke and the next.
func (*Map) Unbind ¶
Unbind removes the binding for a sequence and prunes any prefix nodes left empty, so a former prefix stops reporting Pending.
func (*Map) Where ¶
Where returns every key sequence bound to command, in canonical notation, sorted for determinism. It returns nil when the command has no bindings.
A command legitimately has several bindings — undo answers to both C-_ and C-x u — so this is the reverse index of Map.Bindings, which callers would otherwise have to invert themselves on every lookup.
type Result ¶
type Result struct {
Kind ResultKind
Command string // set only when Kind is Found
}
Result is the outcome of a Map.Lookup.
type ResultKind ¶
type ResultKind int
ResultKind says what a lookup found.
const ( // Undefined means the sequence matches no binding and cannot become one. Undefined ResultKind = iota // Pending means the sequence is a proper prefix of at least one binding, so // the caller should read another key. This is how C-x waits. Pending // Found means the sequence resolves to a command. Found )
func (ResultKind) String ¶
func (r ResultKind) String() string
type SpecialKey ¶
type SpecialKey int
SpecialKey identifies a key that produces no character.
const ( SpecialNone SpecialKey = iota KeyEnter KeyTab KeyBackspace KeyDelete KeyEscape KeyUp KeyDown KeyLeft KeyRight KeyHome KeyEnd KeyPgUp KeyPgDn KeyF1 KeyF2 KeyF3 KeyF4 KeyF5 KeyF6 KeyF7 KeyF8 KeyF9 KeyF10 KeyF11 KeyF12 )
The special keys nem understands.