pub struct CommandRegistry { /* private fields */ }Expand description
The one registry of every command: motions, operators, text objects, ex-commands and actions, built-in and plugin alike (DESIGN.md §5.2.1).
Registration. Each kind has a register_<kind> method taking a
canonical name, a doc string and a spec. It mints a fresh
CommandId from a process-wide counter, records the caller’s file and
line as provenance (#[track_caller]; callers cannot forge it), and
returns a typed id (MotionId, OperatorId, …). Plugins go
through register_plugin_<kind>, which stamps
SourceLayer::Plugin instead, and are
removed wholesale by Self::unregister_plugin.
Names. Names are namespaced by kind: motion:word-forward,
operator:delete, text-object:inner-word, ex:write, action:….
Names are not checked for uniqueness: registering a name again mints a
new id and repoints the name at it, while the old id stays
dispatchable. Aliases (:w) are not registry entries; the :
front-end maps them to canonical names.
Lookup and dispatch. Self::id_by_name and Self::lookup
resolve names and ids to CommandSpec metadata;
execute takes the registry and an invocation and
routes by kind. At runtime the registry is shared as a
CommandRegistryHandle: readers load a
snapshot wait-free, writers clone, mutate and store it.
§Examples
use lattice_grammar::{CommandKind, CommandRegistry, builtins, ex_commands};
let mut registry = CommandRegistry::new();
assert!(registry.is_empty());
let b = builtins::populate(&mut registry);
ex_commands::populate(&mut registry);
let id = registry.id_by_name("operator:delete").unwrap();
assert_eq!(id, b.delete.0);
let spec = registry.lookup(id).unwrap();
assert_eq!(spec.kind, CommandKind::Operator);
assert_eq!(registry.lookup_by_name("ex:write").unwrap().kind, CommandKind::ExCommand);
// Aliases are the front-end's business, not the registry's.
assert!(registry.id_by_name("w").is_none());Implementations§
Source§impl CommandRegistry
impl CommandRegistry
Sourcepub fn new() -> Self
pub fn new() -> Self
An empty registry. Populate it with
builtins::populate and
ex_commands::populate, then the
host’s and subsystems’ own registrations.
Sourcepub fn tag_word_forward_motion(&mut self, id: MotionId)
pub fn tag_word_forward_motion(&mut self, id: MotionId)
Tag a motion as “word-forward class” (vim w / W) so the
operator range resolver applies the word-motion line-stop special
case to it. Called by builtins::populate right after the two
word-forward motions are registered. Idempotent.
Sourcepub fn is_word_forward_motion(&self, id: CommandId) -> bool
pub fn is_word_forward_motion(&self, id: CommandId) -> bool
Whether id is a word-forward-class motion (see
Self::tag_word_forward_motion).
Sourcepub fn register_motion(
&mut self,
name: &str,
doc: &str,
spec: MotionSpec,
) -> MotionId
pub fn register_motion( &mut self, name: &str, doc: &str, spec: MotionSpec, ) -> MotionId
Register a motion. The caller’s source location is captured
via #[track_caller] – the caller cannot supply or override
it. Trusted subsystems (config loader, plugin host bridge,
runtime dispatcher) reach the pub(crate) insert_motion
companion directly with a layer-appropriate source.
Sourcepub fn register_operator(
&mut self,
name: &str,
doc: &str,
spec: OperatorSpec,
) -> OperatorId
pub fn register_operator( &mut self, name: &str, doc: &str, spec: OperatorSpec, ) -> OperatorId
Register an operator; provenance and id minting as for
Self::register_motion.
Sourcepub fn register_text_object(
&mut self,
name: &str,
doc: &str,
spec: TextObjectSpec,
) -> TextObjectId
pub fn register_text_object( &mut self, name: &str, doc: &str, spec: TextObjectSpec, ) -> TextObjectId
Register a text object; provenance and id minting as for
Self::register_motion.
Sourcepub fn register_ex_command(
&mut self,
name: &str,
doc: &str,
spec: ExCommandSpec,
) -> ExCommandId
pub fn register_ex_command( &mut self, name: &str, doc: &str, spec: ExCommandSpec, ) -> ExCommandId
Register an ex-command; provenance and id minting as for
Self::register_motion. The command’s latency class comes from
ExCommandSpec::latency_class (other kinds are always Reflex).
Sourcepub fn register_action(
&mut self,
name: &str,
doc: &str,
spec: ActionSpec,
) -> CommandId
pub fn register_action( &mut self, name: &str, doc: &str, spec: ActionSpec, ) -> CommandId
Register a free-form action (DESIGN.md §5.2.1; see
docs/dev/notes/8i-approach.md). Used by chord bindings whose
historical Action enum payload had no grammar concept
attached. The spec’s apply returns an
crate::effect::Effect – typically
Effect::AppAction(AppEffect::...).
Sourcepub fn register_plugin_motion(
&mut self,
plugin_id: u32,
name: &str,
doc: &str,
spec: MotionSpec,
) -> MotionId
pub fn register_plugin_motion( &mut self, plugin_id: u32, name: &str, doc: &str, spec: MotionSpec, ) -> MotionId
Register a plugin-contributed motion under SourceLayer::Plugin(plugin_id).
Sourcepub fn register_plugin_operator(
&mut self,
plugin_id: u32,
name: &str,
doc: &str,
spec: OperatorSpec,
) -> OperatorId
pub fn register_plugin_operator( &mut self, plugin_id: u32, name: &str, doc: &str, spec: OperatorSpec, ) -> OperatorId
Register a plugin-contributed operator under SourceLayer::Plugin(plugin_id).
Sourcepub fn register_plugin_text_object(
&mut self,
plugin_id: u32,
name: &str,
doc: &str,
spec: TextObjectSpec,
) -> TextObjectId
pub fn register_plugin_text_object( &mut self, plugin_id: u32, name: &str, doc: &str, spec: TextObjectSpec, ) -> TextObjectId
Register a plugin-contributed text object under SourceLayer::Plugin(plugin_id).
Sourcepub fn register_plugin_ex_command(
&mut self,
plugin_id: u32,
name: &str,
doc: &str,
spec: ExCommandSpec,
) -> ExCommandId
pub fn register_plugin_ex_command( &mut self, plugin_id: u32, name: &str, doc: &str, spec: ExCommandSpec, ) -> ExCommandId
Register a plugin-contributed ex-command under SourceLayer::Plugin(plugin_id).
Sourcepub fn register_plugin_action(
&mut self,
plugin_id: u32,
name: &str,
doc: &str,
spec: ActionSpec,
) -> CommandId
pub fn register_plugin_action( &mut self, plugin_id: u32, name: &str, doc: &str, spec: ActionSpec, ) -> CommandId
Register a plugin-contributed action under SourceLayer::Plugin(plugin_id).
Sourcepub fn unregister_plugin(&mut self, plugin_id: u32) -> usize
pub fn unregister_plugin(&mut self, plugin_id: u32) -> usize
Remove every command a plugin contributed, keyed by its host-issued
plugin_id (the u32 inside SourceLayer::Plugin). The teardown seam
for a plugin reload / unload (PH7.12b): the registry is otherwise
append-only, so without this a reload would re-register on top of the
old entries and the by_id/by_name maps would grow unbounded across
reloads (audit F6). Provenance-driven — only Plugin(plugin_id) entries
go; built-in / config / runtime commands are never touched, mirroring
the forgery invariant (a caller supplies only a u32, never a
SourceLayer). Returns the number of commands removed (0 if the plugin
contributed none — an idempotent no-op on a second unload). Every
index (by_id, by_name, the word-forward tag set) is kept consistent.
Sourcepub fn lookup(&self, id: CommandId) -> Option<&CommandSpec>
pub fn lookup(&self, id: CommandId) -> Option<&CommandSpec>
Metadata for a registered id, or None if the id is unknown here
(never registered, or removed by Self::unregister_plugin).
Sourcepub fn lookup_by_name(&self, name: &str) -> Option<&CommandSpec>
pub fn lookup_by_name(&self, name: &str) -> Option<&CommandSpec>
Metadata by canonical name ("motion:word-forward"). Exact match;
no alias or prefix resolution.
Sourcepub fn id_by_name(&self, name: &str) -> Option<CommandId>
pub fn id_by_name(&self, name: &str) -> Option<CommandId>
The id currently bound to a canonical name. How modes and the host
find a command they did not register themselves (e.g.
id_by_name("action:…") at mode activation).
Sourcepub fn motion_is_jump(&self, id: CommandId) -> bool
pub fn motion_is_jump(&self, id: CommandId) -> bool
Is id a motion that vim would call a jump?
MotionSpec::jump has been declared since the grammar’s first slice
and, until VM.3a, read by nobody: the host decided what counted as a
jump with a hardcoded goto_first_line || goto_last_line in
run_document_invocation. So }, {, (, ), the sixteen
tree-sitter structural motions and every plugin motion declared
jump: true and silently got neither a position-history entry nor a
fold-open at the destination — org’s headline motions say in their own
source comment that a headline jump “is somewhere you want <C-o> to
bring you back from”, and it was not.
false for a non-motion or an unregistered id, so a caller can ask
about any CommandId without pre-checking the kind.
Sourcepub fn motion_curswant(&self, id: CommandId) -> CurswantEffect
pub fn motion_curswant(&self, id: CommandId) -> CurswantEffect
VM.3g-1: what this command does to the goal column. Anything that is NOT
a motion — an operator, an action, an ex-command — answers
SetFromTarget, which is what vim does after an edit, an Insert exit or
a yank: the column it leaves the cursor on becomes the new goal.
Sourcepub fn ex_command_spec(&self, id: CommandId) -> Option<&ExCommandSpec>
pub fn ex_command_spec(&self, id: CommandId) -> Option<&ExCommandSpec>
Borrow the ExCommandSpec body for an ex-command id. Returns
None for ids that aren’t ex-commands or aren’t registered.
Used by the :-line parser front-end so it can call the
command’s parse_args callback before building the
CommandInvocation.
Sourcepub fn names(&self) -> impl Iterator<Item = &str>
pub fn names(&self) -> impl Iterator<Item = &str>
Every registered canonical name, in no particular order.
Sourcepub fn generation(&self) -> u64
pub fn generation(&self) -> u64
Monotonic mutation counter (see the generation field). Read by the
completion layer’s command-name generator to key its cache: a change
means the command set moved (a plugin loaded or unloaded), so the cached
candidate list must be regenerated rather than served stale.
Trait Implementations§
Source§impl Clone for CommandRegistry
impl Clone for CommandRegistry
Source§fn clone(&self) -> CommandRegistry
fn clone(&self) -> CommandRegistry
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more