keymap

package
v0.1.0 Latest Latest
Warning

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

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

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

Examples

Constants

View Source
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.

func (Action) String

func (a Action) String() string

String returns the action identifier.

type Binding

type Binding struct {
	Keys   input.Keys
	Action Action
}

Binding associates a chord sequence with an action.

func (Binding) String

func (b Binding) String() string

String returns the chord sequence followed by its action identifier.

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) Action

func (m *Map) Action(keys ...input.Chord) (Action, bool)

Action returns the action named by a complete sequence.

func (*Map) Bind

func (m *Map) Bind(action Action, keys ...input.Chord)

Bind associates keys with action, replacing an existing binding for the same sequence. Empty actions and empty sequences are ignored.

func (*Map) Bindings

func (m *Map) Bindings() []Binding

Bindings returns a deep copy of every binding, in binding order.

func (*Map) Keys

func (m *Map) Keys(action Action) []input.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

func (*Map) Lookup

func (m *Map) Lookup(key input.Key, pending *Pending) (Action, bool)

Lookup advances pending with key and returns the completed action and whether the key belongs to this map. A sequence prefix belongs to the map even though its returned action is empty. A nil Pending can resolve only single-chord bindings.

func (*Map) Unbind

func (m *Map) Unbind(keys ...input.Chord) bool

Unbind removes a sequence and reports whether it was bound.

type Pending

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

Pending records progress through one reader's partially typed sequence. Its zero value has no progress.

func (*Pending) Clear

func (p *Pending) Clear()

Clear abandons the partially typed sequence.

func (*Pending) Keys

func (p *Pending) Keys() input.Keys

Keys returns a copy of the chords typed so far.

Jump to

Keyboard shortcuts

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