Skip to main content

Keymap

Struct Keymap 

Source
pub struct Keymap<A, M: Mode> { /* private fields */ }
Expand description

A modal keymap that maps chord sequences to user-defined actions.

Generic over both the action type A and the mode discriminator M. M can be any Copy + Eq + Hash + Debug type — typically a consumer-defined enum such as VimMode or HelixMode. Chords are stored per-M in separate tries. Call Keymap::feed once per key event; it manages an internal per-mode buffer and returns a KeyResolve indicating what happened.

Implementations§

Source§

impl<A: Clone, M: Mode> Keymap<A, M>

Source

pub fn new(leader: char) -> Self

Create a new keymap with the given leader character.

Source

pub fn set_leader(&mut self, c: char)

Update the leader character (re-parses are not needed; leader is applied at add/feed time through Chord::parse).

Source

pub fn set_timeout(&mut self, t: Duration)

Override the ambiguity-resolution timeout.

Source

pub fn leader(&self) -> char

The current leader character.

Source

pub fn timeout_duration(&self) -> Duration

The current timeout duration.

Source

pub fn add( &mut self, mode: M, chord_str: &str, action: A, desc: &str, ) -> Result<(), KeymapError>

Parse chord_str (vim notation, <leader> expanded) and register action for mode unconditionally.

Source

pub fn add_if( &mut self, mode: M, chord_str: &str, action: A, desc: &str, predicate: impl Fn() -> bool + Send + Sync + 'static, ) -> Result<(), KeymapError>

Parse chord_str and register action for mode gated behind a runtime predicate.

When the predicate returns false at resolve time the binding is treated as if it does not exist: the key falls through to the next dispatch layer (engine FSM, tmux fallback, etc.).

predicate must be Fn() -> bool + Send + Sync + 'static. Capture runtime state via Arc<Mutex<…>> or Arc<AtomicBool> as needed.

§When to use this over an always-bound action

Prefer this when the gate has no fall-back behaviour — the binding should simply “not exist” when the predicate is false, and the key should reach whatever handler runs after the keymap (engine, tmux fallback, etc.). Action-variant gating (an always-bound action that checks state at dispatch time and shows a toast on miss) is fine when the user benefits from feedback; use add_if when silent fall-through is the desired UX.

Intentionally retained for future consumers — not yet called by apps/hjkl. Concrete planned callers (issue #120 review):

  • kryptic-sh/hjkl#39 — scripting (lua / vimscript) layer: user-defined conditional bindings (if filetype == 'rust' then bind(...)) need a host-side predicate primitive.
  • kryptic-sh/hjkl#113 — extension API: third-party plugins registering bindings gated on runtime state (debugger attached, project type detected, etc.).
  • kryptic-sh/hjkl#115 — git hunk actions: <leader>hs / <leader>hr only meaningful inside a git repo; silent fall-through is cleaner than a not-in-git-repo toast.
Source

pub fn add_chord(&mut self, mode: M, chord: Chord, binding: Binding<A>)

Register a pre-parsed chord + binding.

Source

pub fn remove(&mut self, mode: M, chord_str: &str) -> Result<bool, KeymapError>

Remove the binding for chord_str in mode. Returns Ok(true) if something was actually removed.

Source

pub fn children(&self, mode: M, prefix: &Chord) -> Vec<(KeyEvent, Binding<A>)>

Return the direct-child terminal bindings reachable from prefix in mode. Used by which-key to list available completions.

Source

pub fn children_all( &self, mode: M, prefix: &Chord, ) -> Vec<(KeyEvent, Option<Binding<A>>)>

Return all direct children reachable from prefix in mode — both terminal bindings and pure-prefix (submenu) entries.

Terminal entries carry Some(Binding); prefix-only entries carry None. Callers (e.g. which-key) should render prefix-only entries with a synthetic description such as "…".

Source

pub fn feed(&mut self, mode: M, ev: KeyEvent, _now: Instant) -> KeyResolve<A>

Feed a single key event for mode and return what happened.

now is used to drive timeout logic — pass Instant::now() in production; use a fake Instant in tests if needed.

Source

pub fn timeout_resolve(&mut self, mode: M) -> KeyResolve<A>

Force-resolve any pending chord state (called when the timeout fires).

Three outcomes:

  • Buffer matches a terminal binding → Match(binding) and the buffer is drained. This is the Ambiguous resolution case (e.g. both g and gd bound: pressing g and waiting fires the g binding).
  • Buffer is a pure prefix (no terminal at this depth but deeper bindings exist) → Unbound(vec![]) and the buffer is left in place. The user is mid-chord; the timeout fired for which-key purposes but no chord-level action is required.
  • Buffer is a dead-end (no terminal, no descendants) → Unbound(buf) with the drained events. This shouldn’t normally occur given that feed only buffers keys that extend a valid prefix.
Source

pub fn pending(&self, mode: M) -> &[KeyEvent]

Return a snapshot of the currently pending chord buffer for mode. Empty when no chord is in progress.

Source

pub fn reset(&mut self, mode: M)

Reset the pending buffer for mode (e.g. on mode switch).

Source

pub fn pop(&mut self, mode: M) -> Option<KeyEvent>

Pop the last key from the pending buffer for mode. Returns the removed key, or None if the buffer was empty.

Used by callers (e.g. which-key popup) to implement Backspace-as-navigate: the user backs out of a chord prefix one key at a time.

Auto Trait Implementations§

§

impl<A, M> !RefUnwindSafe for Keymap<A, M>

§

impl<A, M> !UnwindSafe for Keymap<A, M>

§

impl<A, M> Freeze for Keymap<A, M>

§

impl<A, M> Send for Keymap<A, M>
where M: Send, A: Send,

§

impl<A, M> Sync for Keymap<A, M>
where M: Sync, A: Sync,

§

impl<A, M> Unpin for Keymap<A, M>
where M: Unpin, A: Unpin,

§

impl<A, M> UnsafeUnpin for Keymap<A, M>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.