pub struct KeymapHandle { /* private fields */ }Expand description
Editor-facing handle to the keymap registry.
Reads are wait-free. Self::lookup does one
ArcSwap::load + one trie walk. The keystroke path holds
the returned Arc<MergedKeymap> only for the duration of
the lookup; concurrent writes (mode push/pop, user :bind,
plugin registration) cannot stall it.
Writes are mutex-routed. Self::bind / Self::unbind
/ Self::push_layer / Self::pop_layer take a brief
mutex on the layer stack, mutate the affected per-mode
tries, rebuild the merged cell, and ArcSwap::store it.
Writes are infrequent (startup; mode transitions; user
commands), so the lock is uncontended in practice.
Implementations§
Source§impl KeymapHandle
impl KeymapHandle
Sourcepub fn new() -> KeymapHandle
pub fn new() -> KeymapHandle
A handle on a fresh, empty KeymapRegistry. Clone the handle to
share the registry; a second new() is an unrelated registry.
Sourcepub fn reverse_entries(&self, id: CommandId) -> Vec<(KeyChord, KeymapLayer)>
pub fn reverse_entries(&self, id: CommandId) -> Vec<(KeyChord, KeymapLayer)>
Reverse-lookup entries for id: the chord sequence that fires it,
each chord paired with the layer providing the binding. Empty when
nothing binds id. Freshens the derived state first.
Coverage is deliberately narrow (it feeds the : completion
margin): Normal mode only, literal-only paths (a binding
through a {char} wildcard is skipped), and first binding wins
when several chords bind the same command. Both the always-on
layers and every gated mode layer are indexed.
(C′) Prefer this over Self::reverse_cache_arc: a raw handle
on the ArcSwap bypasses the registry’s lazy derived-state
refresh and can read a cache that a pending bind has invalidated.
Cold path (the command palette and the completion margin’s
keybinding column), so paying a rebuild here is free where paying
it per write was not.
Sourcepub fn reverse_cache_arc(
&self,
) -> Arc<ArcSwapAny<Arc<HashMap<CommandId, Vec<(KeyChord, KeymapLayer)>>>>> ⓘ
pub fn reverse_cache_arc( &self, ) -> Arc<ArcSwapAny<Arc<HashMap<CommandId, Vec<(KeyChord, KeymapLayer)>>>>> ⓘ
The raw reverse-cache cell behind Self::reverse_entries.
Exists for lattice-host, which builds a KeymapReverseLookupHandle
from it: lattice-keymap cannot depend on lattice-completion
(circular dependency), so that type lives downstream and takes the
cache through this accessor. Reads through it skip the lazy
derived-state refresh, so they can lag a bind until the next
lookup-style call freshens it.
Sourcepub fn lookup(&self, mode: BindingMode, chords: &[KeyChord]) -> LookupResult
pub fn lookup(&self, mode: BindingMode, chords: &[KeyChord]) -> LookupResult
Look up the typed binding for chords in mode.
Wait-free.
K.1.c (2026-05-30): preserves pre-K.1.c semantics by
treating every registered mode layer — major and minor — as
active (overlaid in ModeId-alphabetical order, matching K.1.b’s
sorted-layers-vec merge order). Legacy callers (the
translate dispatcher’s completion-popup / snippet
keystroke path) continue to work unchanged — their
mode lifecycle already gates at push/pop, so
“everything always active” matches the push/pop
surface.
For per-buffer-gated lookup (the emacs-style
composability story — do in diff-mode only fires
when the active buffer has diff-mode active) use
Self::lookup_with_context with the buffer’s
active_modes. D.5 wires diff-mode through that
path; other modes migrate as their consumers care.
Sourcepub fn lookup_with_context(
&self,
mode: BindingMode,
chords: &[KeyChord],
active_modes: &[ModeId],
) -> LookupResult
pub fn lookup_with_context( &self, mode: BindingMode, chords: &[KeyChord], active_modes: &[ModeId], ) -> LookupResult
K.1.c (2026-05-30): mode-aware lookup.
Composes a fresh per-keystroke merged trie:
- Start with the cached always-on merge
(
Builtin + User + Buffer). - For each
mode_idinactive_modes(in slice order — callers pass the active major first, then minors in activation order) overlay that mode’sMajorMode/MinorModelayer on top — later entries win, so a minor beats the major and the last-activated minor wins. - Note: the always-on cache already has
User / Bufferoverlaid aboveBuiltin. The minor-mode overlay applied in step 2 therefore sits above User/Buffer at lookup time — which differs from the pre-K.1.c “MinorMode < User < Buffer” priority. Rationale: mode-scoped chords (doindiff-mode,M-dincorfu-popupinfo-map) intentionally claim their chord while the mode is active, even over the user’s global rebinds; users wanting to override a specific mode’s binding use theOwnedLayer { mode_id }capability to bind inside that mode’s layer (where same-layer last-write-wins applies). This matches emacs’s minor-mode-precedence-over-global semantics.
Wait-free reads: two ArcSwap::load calls
(merged, gated_mode_tries) + per-active_modes
merge work. Typical active_modes.len() is 0-3 so
the overhead is small; with an empty slice no composite is
built at all. A ModeId with no registered layer is skipped.
§Examples
use lattice_grammar::{CommandId, CommandInvocation, SourceLocation};
use lattice_keymap::{BindingMode, ChordPattern, KeymapHandle, KeymapLayer, LookupResult, ModeId};
use lattice_protocol::KeyChord;
let keymap = KeymapHandle::new();
let path = [ChordPattern::Literal(KeyChord::char('g')), ChordPattern::Literal(KeyChord::char('d'))];
keymap.bind(KeymapLayer::MajorMode(ModeId::new("rust-mode")), BindingMode::Normal, &path,
CommandInvocation::of(CommandId::new(9)), SourceLocation::synthetic("doc"));
let rust = [ModeId::new("rust-mode")];
let g = KeyChord::char('g');
assert!(matches!(keymap.lookup_with_context(BindingMode::Normal, &[g], &rust), LookupResult::Partial));
assert!(matches!(
keymap.lookup_with_context(BindingMode::Normal, &[g, KeyChord::char('d')], &rust),
LookupResult::Bound { .. },
));
// Not this buffer's major: the layer is invisible.
assert!(matches!(keymap.lookup_with_context(BindingMode::Normal, &[g], &[]), LookupResult::Unbound));Sourcepub fn continuations_with_context(
&self,
mode: BindingMode,
chords: &[KeyChord],
active_modes: &[ModeId],
) -> Option<NodeView>
pub fn continuations_with_context( &self, mode: BindingMode, chords: &[KeyChord], active_modes: &[ModeId], ) -> Option<NodeView>
WK.1: the immediate continuations of chords in the same
composite Self::lookup_with_context resolves against.
This is which-key’s source of truth, and design §2 makes it the
feature’s one correctness property: the popup is derived from the
trie the dispatcher walks, never from the static catalog. Both
halves of this function mirror lookup_with_context exactly —
the same always-on fast path, the same overlay order — and differ
only in the terminal step, where that one resolves a binding and
this one reports a node’s children. Any other construction
reintroduces the :describe-bindings bug (a mode that shadows a
builtin chord not reflected, so the view advertises a binding
that will not fire) in a more visible place.
Not Self::continuations, which is :describe-key’s query:
activation-agnostic, all-layers, one row per registration. That
one answers “does this chord exist anywhere”; this one answers
“what can I press next, here”. Same trie, opposite contexts.
None when the prefix leaves the trie. Telemetry path — runs on
the actor thread after the idle delay, never per keystroke.
Sourcepub fn bind(
&self,
layer: KeymapLayer,
mode: BindingMode,
path: &[ChordPattern],
command: CommandInvocation,
source: SourceLocation,
)
pub fn bind( &self, layer: KeymapLayer, mode: BindingMode, path: &[ChordPattern], command: CommandInvocation, source: SourceLocation, )
Register a binding at (layer, mode, path). Replaces
any prior binding at the exact same triple within the
same layer (last-bind-wins per layer); higher-priority
layers shadow lower-priority ones automatically via the
merged-trie rebuild.
Sourcepub fn bind_modes(
&self,
layer: KeymapLayer,
modes: &[BindingMode],
path: &[ChordPattern],
command: CommandInvocation,
source: SourceLocation,
)
pub fn bind_modes( &self, layer: KeymapLayer, modes: &[BindingMode], path: &[ChordPattern], command: CommandInvocation, source: SourceLocation, )
Register one binding across SEVERAL modes in a single call.
Equivalent to calling Self::bind once per mode, but inserts
into every mode’s trie under one lock and rebuilds the merged
trie + reverse cache ONCE (not per mode). The same
Arc<BoundCommand> is shared across the modes’ tries, except that a
Visual or Select entry named alongside Normal gets its own copy: it’s
an explicit declaration, and the motion mirror tells its own rows apart
by identity (VM.4).
This is the imperative multi-mode primitive init.rs / plugins /
host helpers use directly (the declarative peer is
crate::Keymap::bind_chord_modes and the keymap_entry!
mode: [..] form). modes must be non-empty; an empty slice is
a no-op.
Sourcepub fn bind_bound(
&self,
layer: KeymapLayer,
mode: BindingMode,
path: &[ChordPattern],
bound: Arc<BoundCommand>,
)
pub fn bind_bound( &self, layer: KeymapLayer, mode: BindingMode, path: &[ChordPattern], bound: Arc<BoundCommand>, )
Lower-level binder: register a pre-built
Arc<BoundCommand> directly, e.g. one built with
BoundCommand::with_fall_through or shared across several
paths. Used by the per-mode registration helpers
(lattice_ui_tui::keymap_replace::register_replace_bindings and
siblings). Self::bind is this plus BoundCommand::from_invocation.
Same semantics as Self::bind: last write wins at the exact
(layer, mode, path); with a command registry set, a Normal-mode
motion is mirrored into Visual (and Select when its first chord
cannot be typed). The binding’s own layer field is not
consulted — layer decides where it goes.
Sourcepub fn unbind(
&self,
layer: KeymapLayer,
mode: BindingMode,
path: &[ChordPattern],
) -> Option<Arc<BoundCommand>>
pub fn unbind( &self, layer: KeymapLayer, mode: BindingMode, path: &[ChordPattern], ) -> Option<Arc<BoundCommand>>
Remove the binding at (layer, mode, path). No-op if
nothing was registered there. Returns the dropped
binding so callers can echo provenance (“unbound dd
from user, init.rs:42”).
Sourcepub fn push_layer(
&self,
kind: PushLayerKind,
label: impl Into<String>,
bindings: HashMap<BindingMode, KeymapTrie>,
) -> LayerId
pub fn push_layer( &self, kind: PushLayerKind, label: impl Into<String>, bindings: HashMap<BindingMode, KeymapTrie>, ) -> LayerId
Install a minor-mode or buffer layer.
K.1.b (2026-05-30): for PushLayerKind::MinorMode(mode_id),
the layer’s identity is the mode_id — pushing for the
same mode_id is idempotent on the layer: the
existing layer’s bindings are replaced, no sibling layer
is minted. The same holds for MajorMode(mode_id) and for
Buffer: the registry finds an existing layer by its
KeymapLayer key, so a second Buffer push replaces the
first’s bindings and returns the same LayerId.
A replacing push also replaces the layer’s label, and discards any
bindings previously added to that layer with Self::bind.
bindings is the layer’s full per-mode binding set –
computed by the caller (e.g. completion-popup wires its
overrides at activation time). The registry copies the
tries in; the caller’s KeymapTrie instances are no
longer needed after the call returns.
Returns the LayerId of the installed layer (whether
freshly minted or pre-existing for the same mode_id).
For MinorMode, prefer popping via
Self::pop_minor_mode_layer (by mode_id) over
Self::pop_layer (by LayerId); both work but the
former is what matches the install signature.
Sourcepub fn pop_layer(&self, id: LayerId)
pub fn pop_layer(&self, id: LayerId)
Pop the layer issued by an earlier push_layer.
No-op if the id is unknown (caller may double-pop on
the way out of an error path; defensive).
Sourcepub fn remove_layer(&self, layer: KeymapLayer)
pub fn remove_layer(&self, layer: KeymapLayer)
Remove an entire layer by its KeymapLayer identity, dropping every
binding it holds across all binding-modes, then rebuild the merged /
gated / reverse caches. The teardown seam for a plugin mode’s keymap
(PH7.12b): lattice-plugin-host’s bind_mode_keymap binds a plugin mode’s chords into
KeymapLayer::MinorMode(mode_id) via Self::try_bind_chord_string —
an implicitly-created layer, so the host never holds a LayerId to
pop_layer with. This removes it by the layer key
the host does know (the mode’s own MinorMode(mode_id)). No-op if no
such layer exists (idempotent second unload / a mode that bound nothing).
Mirrors pop_layer’s rebuild exactly — every site that stores merged /
gated_mode_tries must also rebuild the reverse cache.
Sourcepub fn set_command_registry(
&self,
commands: Arc<ArcSwapAny<Arc<CommandRegistry>>>,
)
pub fn set_command_registry( &self, commands: Arc<ArcSwapAny<Arc<CommandRegistry>>>, )
VM.4: give the keymap the command registry it asks “is this a motion?”.
From here on every write mirrors motions into Visual, and into Select when their first chord can’t be typed (keymap-architecture.md §15). Rescans every existing layer, so calling this after bindings have landed is exactly as good as calling it first. Boot calls it the moment the handle exists.
Sourcepub fn layers(&self) -> Vec<KeymapLayer>
pub fn layers(&self) -> Vec<KeymapLayer>
VM.4: every registered layer, lowest priority first.
Exists so an invariant can be asserted across ALL layers rather than
the one a test happens to name. The “a motion is live in Visual” drift
test used to check Builtin only, so it could never have noticed a
re-pushed mode layer losing its mirror.
Sourcepub fn binding_count(&self) -> usize
pub fn binding_count(&self) -> usize
Total binding count across all layers. Telemetry + tests; not on the hot path.
Sourcepub fn enumerate_chord_bindings(
&self,
mode: BindingMode,
chords: &[KeyChord],
) -> Vec<(KeymapLayer, Arc<BoundCommand>)>
pub fn enumerate_chord_bindings( &self, mode: BindingMode, chords: &[KeyChord], ) -> Vec<(KeymapLayer, Arc<BoundCommand>)>
K.1.d (2026-05-30): enumerate every binding registered
for chords in mode across all layers, returning the
layer + binding pair for each. Telemetry path (drives
:describe-key‘s mode-aware section); not on the
keystroke hot path. Order: layer-priority ascending
(Builtin first, then MajorMode, then MinorMode layers
in ModeId-alphabetical order, then User, then Buffer).
Callers cross-reference the layers’ MinorMode entries
against the active buffer’s ActiveModes to mark
which would actually fire right now.
Sourcepub fn resolve_trace(
&self,
mode: BindingMode,
chords: &[KeyChord],
active_modes: &[ModeId],
) -> KeymapResolution
pub fn resolve_trace( &self, mode: BindingMode, chords: &[KeyChord], active_modes: &[ModeId], ) -> KeymapResolution
Full per-layer trace for chords in mode.
Returns a KeymapResolution whose hits list every registered
layer that has a terminal binding at the given chord path, in
priority order ascending (Builtin first, Buffer last). The active
flag on each hit is set by crossing the layer against active_modes:
Builtin,User,Bufferare always active.MajorMode(id)andMinorMode(id)are active iffidis contained inactive_modes.
Telemetry path; not on the keystroke hot path.
Sourcepub fn resolve_trace_all_modes(
&self,
chords: &[KeyChord],
active_modes: &[ModeId],
) -> Vec<KeymapResolution>
pub fn resolve_trace_all_modes( &self, chords: &[KeyChord], active_modes: &[ModeId], ) -> Vec<KeymapResolution>
Run Self::resolve_trace for every BindingMode variant.
Returns only the modes that have at least one registered binding
for chords (i.e. non-empty hits). Callers that want to display
:describe-key with all modes iterate the returned vec; modes with
no bindings are omitted to keep output compact.
Telemetry path; not on the keystroke hot path.
Sourcepub fn any_layer_expects_more(&self, chords: &[KeyChord]) -> bool
pub fn any_layer_expects_more(&self, chords: &[KeyChord]) -> bool
Is chords still an INCOMPLETE prefix of some REGISTERED binding —
in any binding mode, in any layer, active here or not?
This is the question that lets :describe-key’s chord capture end a
sequence without reserving a terminator key. A chord argument is a
sequence (gg, <C-w>v, <leader>fz), so capture cannot submit on the
first keystroke; but the trie already distinguishes “waiting for more”
from “this is the answer” on every keystroke of ordinary dispatch, and
that is exactly the distinction capture needs. Asking here is what frees
<CR> / <Esc> / <BS> to be describable keys rather than controls.
Any LAYER, not the active ones (DK.4). This deliberately does not
take an active_modes slice, and the omission is the fix for a
user-reported truncation: capture runs while the *command-line*
buffer is focused, so an activation-gated query resolves against the
MINIBUFFER’s modes — which are never the org / magit / plugin modes
whose chords the user is asking about. <C-c><C-x><C-b> submitted
after two chords and described <C-c><C-x>, because org-mode’s
MajorMode layer was invisible to the question. No multi-chord
binding owned by a major mode or a plugin could be captured at all.
The rule that replaces it: :describe-key answers for EVERY key, not
only the keys active where you stand — so capture keeps reading while
any registered binding anywhere could extend the sequence, and the
rendered answer marks each layer [active] / [inactive] for the
buffer the prompt was opened from. Sequence SHAPE is a property of the
keymap; what FIRES is a property of the buffer. Only the second one is
contextual.
Any mode, not the current one, for the same reason: an Insert-mode-only prefix must not submit early mid-sequence.
Unbound deliberately terminates. “This key does nothing” is a first-
class answer — it is the one a user asking why <M-k> did nothing
needs — and treating it as “keep waiting” would hang capture on exactly
the query that motivated it. A chord that is BOUND at this depth also
terminates, matching dispatch: the trie stops at the first binding, so
anything grown beneath it can never fire (the continuations are still
listed in the answer, flagged as unreachable).
Telemetry path; not on the keystroke hot path.
Sourcepub fn continuations(
&self,
chords: &[KeyChord],
active_modes: &[ModeId],
) -> Vec<Continuation>
pub fn continuations( &self, chords: &[KeyChord], active_modes: &[ModeId], ) -> Vec<Continuation>
DK.4: every binding registered strictly BELOW chords, across all
layers and all binding modes, annotated with whether its layer is
active on the buffer described by active_modes.
The prefix half of “:describe-key answers for every key”. A prefix
has no binding of its own, so the layer trace is empty and the honest
answer is its subtree: what can follow, what each continuation runs,
and which of them can fire here.
Results are sorted by binding mode (declaration order), then by
rendered chord suffix, so the output is stable across runs.
Continuations whose path crosses a CharLiteral wildcard (f{char},
'{mark}) are included with the wildcard rendered as {char}.
Telemetry path; not on the keystroke hot path.
Sourcepub fn layer_label_string(&self, layer: KeymapLayer) -> String
pub fn layer_label_string(&self, layer: KeymapLayer) -> String
Human-readable label for a KeymapLayer, derived from the layer’s
registered label string (set at push_layer / bind time). Falls
back to default_label when the layer hasn’t been explicitly named.
Used by :describe-key output.
Sourcepub fn layer_label(&self, id: LayerId) -> Option<String>
pub fn layer_label(&self, id: LayerId) -> Option<String>
Human-readable label for the layer carrying id, if any.
Drives :describe-key’s provenance row (“user, init.rs:42”;
“minor-mode:completion-popup”). Telemetry path; not on the
hot path.
Sourcepub fn try_bind(
&self,
capability: KeymapCapability,
layer: KeymapLayer,
mode: BindingMode,
path: &[ChordPattern],
command: CommandInvocation,
source: SourceLocation,
) -> Result<(), KeymapError>
pub fn try_bind( &self, capability: KeymapCapability, layer: KeymapLayer, mode: BindingMode, path: &[ChordPattern], command: CommandInvocation, source: SourceLocation, ) -> Result<(), KeymapError>
Capability-gated Self::bind. The host hands every
caller a KeymapCapability derived from its manifest;
this entry point checks the capability before committing
the write so plugins / init.rs can’t escape their
declared scope.
Scope: Full → any layer; User → User only; MinorMode →
any MinorMode(_) or Buffer; OwnedLayer { mode_id } → that
mode’s own MinorMode(mode_id) or MajorMode(mode_id).
§Errors
KeymapError::CapabilityDenied when the capability does not
cover layer; nothing is written.
Sourcepub fn try_bind_chord_string(
&self,
capability: KeymapCapability,
layer: KeymapLayer,
mode: BindingMode,
chord_str: &str,
command: CommandInvocation,
source: SourceLocation,
) -> Result<(), KeymapError>
pub fn try_bind_chord_string( &self, capability: KeymapCapability, layer: KeymapLayer, mode: BindingMode, chord_str: &str, command: CommandInvocation, source: SourceLocation, ) -> Result<(), KeymapError>
Capability-gated convenience that parses chord_str
("<leader>w", "gd", "<C-w>j") into a
Vec<ChordPattern::Literal> before delegating to
Self::try_bind. The host’s WIT bind host-fn calls
this; user init.rs calls a thin wrapper around it.
chord_str must round-trip through
lattice_protocol::chord::parse_chord_sequence; wildcards
(<CharLiteral>) aren’t expressible from chord strings
today and require Self::try_bind with a hand-built
&[ChordPattern]. <leader> / <Leader> is expanded first
against Self::leader.
§Errors
KeymapError::InvalidChord when the (leader-expanded) string does
not parse; otherwise as Self::try_bind. The chord is parsed
before the capability is checked.
§Examples
use lattice_grammar::{CommandId, CommandInvocation, SourceLocation};
use lattice_keymap::{BindingMode, KeymapCapability, KeymapError, KeymapHandle, KeymapLayer, LookupResult};
use lattice_protocol::KeyChord;
let keymap = KeymapHandle::new();
keymap.set_leader(",");
let cmd = CommandInvocation::of(CommandId::new(3));
keymap.try_bind_chord_string(KeymapCapability::User, KeymapLayer::User, BindingMode::Normal,
"<leader>w", cmd.clone(), SourceLocation::synthetic("init.rs")).unwrap();
let hit = keymap.lookup(BindingMode::Normal, &[KeyChord::char(','), KeyChord::char('w')]);
assert!(matches!(hit, LookupResult::Bound { command, .. } if command.command == cmd));
let bad = keymap.try_bind_chord_string(KeymapCapability::User, KeymapLayer::User,
BindingMode::Normal, "<Nope>", cmd, SourceLocation::synthetic("init.rs"));
assert!(matches!(bad, Err(KeymapError::InvalidChord(_))));Sourcepub fn layer_bindings(
&self,
layer: KeymapLayer,
mode: BindingMode,
) -> Vec<(Vec<ChordPattern>, Arc<BoundCommand>)>
pub fn layer_bindings( &self, layer: KeymapLayer, mode: BindingMode, ) -> Vec<(Vec<ChordPattern>, Arc<BoundCommand>)>
OM.4b: every terminal binding in ONE layer’s mode trie, as
(chord path, bound command) pairs.
The existing walks are either global (merged, every layer folded
together) or per-CommandId (the reverse cache). Neither answers “what
did this layer bind”, which is what a caller expanding a mode’s
contributions needs: the chord comes from the layer, the command’s kind
comes from the CommandRegistry, and only the pairing identifies e.g. a
text object that needs operator-pending rows generating.
Snapshots into a Vec rather than lending an iterator, because the
caller’s next move is to write bindings into the same registry and it
must not be holding the lock while doing so. O(bindings in one layer),
off any hot path — this runs at plugin load, not per keystroke.
Sourcepub fn set_leader(&self, leader: &str)
pub fn set_leader(&self, leader: &str)
Set what <leader> expands to. The host calls this at boot from the
keymap.leader option, BEFORE any subsystem or plugin registers its
bindings — expansion is bind-time, so a leader set afterwards does not
move bindings that already landed.
Sourcepub fn expand_leader(&self, chord_str: &str) -> String
pub fn expand_leader(&self, chord_str: &str) -> String
Expand <leader> in chord_str against the current leader.
Exposed so a caller that must parse a binding string itself
(:describe-key) resolves it the same way binding did.
Sourcepub fn try_unbind_chord_string(
&self,
capability: KeymapCapability,
layer: KeymapLayer,
mode: BindingMode,
chord_str: &str,
) -> Result<Option<Arc<BoundCommand>>, KeymapError>
pub fn try_unbind_chord_string( &self, capability: KeymapCapability, layer: KeymapLayer, mode: BindingMode, chord_str: &str, ) -> Result<Option<Arc<BoundCommand>>, KeymapError>
Capability-gated Self::unbind from a vim-notation chord
string — the symmetric counterpart to
try_bind_chord_string, so a
caller that bound by string (a plugin’s register-binding,
PL8.D) can reverse it by the same string on unload without
re-parsing to ChordPatterns itself. An unparseable chord is
KeymapError::InvalidChord; a capability denial is
KeymapError::CapabilityDenied; Ok(None) means the path
wasn’t bound (idempotent re-unbind).
Sourcepub fn try_unbind(
&self,
capability: KeymapCapability,
layer: KeymapLayer,
mode: BindingMode,
path: &[ChordPattern],
) -> Result<Option<Arc<BoundCommand>>, KeymapError>
pub fn try_unbind( &self, capability: KeymapCapability, layer: KeymapLayer, mode: BindingMode, path: &[ChordPattern], ) -> Result<Option<Arc<BoundCommand>>, KeymapError>
Capability-gated Self::unbind. Returns the dropped
binding (or None when the path wasn’t bound) so the
host can echo “unbound dd (was: delete-line)”.
Sourcepub fn try_push_layer(
&self,
capability: KeymapCapability,
kind: PushLayerKind,
label: impl Into<String>,
bindings: HashMap<BindingMode, KeymapTrie>,
) -> Result<LayerId, KeymapError>
pub fn try_push_layer( &self, capability: KeymapCapability, kind: PushLayerKind, label: impl Into<String>, bindings: HashMap<BindingMode, KeymapTrie>, ) -> Result<LayerId, KeymapError>
Capability-gated Self::push_layer. Permitted for every
capability except User, whatever kind names: MinorMode and
OwnedLayer { mode_id } are NOT checked against the pushed
layer’s kind or mode id here, unlike Self::try_bind. The User
capability can’t push runtime layers – user config writes live
in the static User layer registered at boot.
§Errors
KeymapError::CapabilityDenied for User, naming the layer the
push would have created.
Sourcepub fn pop_minor_mode_layer(&self, mode_id: ModeId) -> bool
pub fn pop_minor_mode_layer(&self, mode_id: ModeId) -> bool
K.1.b (2026-05-30): pop a minor-mode layer by its
ModeId. The natural complement to
push_layer(PushLayerKind::MinorMode(mode_id), …) —
callers don’t have to thread a separate LayerId
through teardown when the mode id is what they already
know. No-op if no layer for mode_id is currently
installed (defensive against double-pop on error paths).
Returns true iff a layer was removed.
Trait Implementations§
Source§impl Clone for KeymapHandle
impl Clone for KeymapHandle
Source§fn clone(&self) -> KeymapHandle
fn clone(&self) -> KeymapHandle
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for KeymapHandle
impl Debug for KeymapHandle
Source§impl Default for KeymapHandle
impl Default for KeymapHandle
Source§fn default() -> KeymapHandle
fn default() -> KeymapHandle
Auto Trait Implementations§
impl !RefUnwindSafe for KeymapHandle
impl !UnwindSafe for KeymapHandle
impl Freeze for KeymapHandle
impl Send for KeymapHandle
impl Sync for KeymapHandle
impl Unpin for KeymapHandle
impl UnsafeUnpin for KeymapHandle
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more