Documentation
¶
Overview ¶
Package keymap maps terminal keystrokes to named actions.
Lookups do not mutate a Map. Sequence progress lives in Pending, so a map can be shared by independent readers without sharing their partially typed sequences, provided its bindings are not changed concurrently.
Index ¶
- Constants
- type Action
- type Binding
- type Map
- func (m *Map) Action(keys ...input.Chord) (Action, bool)
- func (m *Map) Bind(action Action, keys ...input.Chord)
- func (m *Map) Bindings() []Binding
- func (m *Map) Keys(action Action) []input.Keys
- func (m *Map) Lookup(key input.Key, pending *Pending) (Action, bool)
- func (m *Map) Unbind(keys ...input.Chord) bool
- type Pending
Examples ¶
Constants ¶
const DefaultTimeout = time.Second
DefaultTimeout is how long a partially typed sequence remains current when a Map does not specify a positive Timeout.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Action ¶
type Action string
Action identifies an operation independently of the keystrokes bound to it. Empty is reserved for no action.
type Map ¶
type Map struct {
// Timeout controls how long a partially typed sequence remains current. Zero
// and negative values use [DefaultTimeout].
Timeout time.Duration
// contains filtered or unexported fields
}
Map associates chord sequences with actions.
A sequence that is a proper prefix of another binding is unreachable: without a timer driving lookup, the shorter binding cannot be chosen while the longer one may still arrive. The longer sequence therefore takes precedence.
The zero value is an empty map. Use Map by pointer after binding keys; copying a populated Map would share its internal tree.
Example ¶
package main
import (
"fmt"
"github.com/Tangerg/oolong/core/input"
"github.com/Tangerg/oolong/core/keymap"
)
func main() {
// A consumer names its operations; the map says which keystrokes produce each
// name. Neither the event protocol nor the map needs to know what an operation does.
keys := &keymap.Map{}
keys.Bind("delete-word-back", input.Ctrl.Rune('w'))
keys.Bind("delete-word-back", input.Alt.With(input.Backspace))
keys.Bind("submit", input.Chord{Code: input.Enter})
var pending keymap.Pending
for _, key := range []input.Key{
{Code: input.Character, Rune: 'w', Mods: input.Ctrl},
{Code: input.Enter},
{Code: input.Character, Rune: 'q'},
} {
action, mine := keys.Lookup(key, &pending)
fmt.Printf("%-9s %-18s mine=%v\n", key, "\""+string(action)+"\"", mine)
}
}
Output: ctrl+w "delete-word-back" mine=true enter "submit" mine=true q "" mine=false
Example (Sequences) ¶
package main
import (
"fmt"
"github.com/Tangerg/oolong/core/input"
"github.com/Tangerg/oolong/core/keymap"
)
func main() {
// A binding can be more than one chord long. The first chord is the map's and
// names nothing yet, which the caller has to consume rather than pass on.
keys := &keymap.Map{}
keys.Bind("go-to-top", input.Chord{Rune: 'g'}, input.Chord{Rune: 'g'})
var pending keymap.Pending
for range 2 {
action, mine := keys.Lookup(input.Key{Rune: 'g'}, &pending)
fmt.Printf("%q taken=%v waiting=%q\n", action, mine, pending.Keys().String())
}
}
Output: "" taken=true waiting="g" "go-to-top" taken=true waiting=""
func (*Map) Bind ¶
Bind associates keys with action, replacing an existing binding for the same sequence. Empty actions and empty sequences are ignored.
func (*Map) Keys ¶
Keys returns copies of the sequences bound to action, in binding order.
Example ¶
package main
import (
"fmt"
"github.com/Tangerg/oolong/core/input"
"github.com/Tangerg/oolong/core/keymap"
)
func main() {
// Keys reports the sequences bound to an action in insertion order, so callers do
// not have to reconstruct binding precedence.
keys := &keymap.Map{}
keys.Bind("delete-word-back", input.Ctrl.Rune('w'))
keys.Bind("delete-word-back", input.Alt.With(input.Backspace))
for _, bound := range keys.Keys("delete-word-back") {
fmt.Println(bound)
}
}
Output: ctrl+w alt+backspace