Skip to main content

Module ex_commands

Module ex_commands 

Source
Expand description

Built-in ex-commands registered as peers of motions / operators / text objects in the unified CommandRegistry (DESIGN.md §5.2.1).

Each spec’s apply callback is intentionally thin: it only packages the parsed args into the matching Effect variant. The host (App) owns the side-effect implementation (file I/O, view options, echo area, document swap, …) – this keeps the closures static-state-free so they can later be loaded from a WASM plugin without redesign.

Coverage:

  • Keyword form: :w[rite], :q[uit], :wq/:x, :noh[lsearch], :reg[isters], :marks, :d[elete], :set, :e[dit].
  • Delimiter-syntax form (Appendix B.2): :s/.../.../[g], :%s/.../.../[g], :g/.../.../, :v/.../.../. These use Args::List to carry pattern / replacement / flags / body / inverted as positional ArgValues; the parser front-end strips the delimiter prefix and dispatches through the same grammar::execute() as everything else.

(The list above is the original core; populate now also registers the buffer / pane / tab commands, the :describe-* and :list-* help family, the :lsp-* commands, :format, :tutor, :cd and more — see ExBuiltins and :list-commands.)

Every builtin is registered as ex:<name>. Aliases (:w for ex:write, :q for ex:quit, :e for ex:edit, …) are NOT separate registry entries – they would inflate the CommandId namespace and complicate :describe-command. Alias resolution is the parser front-end’s job (expand_alias / ALIAS_TABLE in lattice-host’s excommand module). New subsystem-coupled commands follow the project naming rule: one dashed, namespaced alias (lsp-format), no collapsed or generic forms.

§Examples

How the : front-end turns :w out.txt into an Effect: resolve the name, let the spec parse the rest of the line, dispatch.

use lattice_core::{BufferId, Document};
use lattice_grammar::{
    CancellationToken, CommandInvocation, CommandRegistry, Effect, ex_commands, execute,
};
use lattice_protocol::position::Position;

let mut registry = CommandRegistry::new();
ex_commands::populate(&mut registry);

// `w` -> `ex:write` is the host alias table's job; the registry holds
// the canonical name.
let id = registry.id_by_name("ex:write").unwrap();
let spec = registry.ex_command_spec(id).unwrap();
let args = (spec.parse_args)("out.txt", false).unwrap();

let mut doc = Document::from_text("hello\n");
let effect = execute(
    &registry,
    &mut doc,
    BufferId(0),
    Position::ZERO,
    CommandInvocation::of(id).with_args(args),
    &CancellationToken::never(),
)
.unwrap();
// The command only describes the work; the host does the I/O.
match effect {
    Effect::SaveBuffer { path } => assert_eq!(path, Some("out.txt".into())),
    other => panic!("unexpected {other:?}"),
}

Structs§

ExBuiltins
The ids of the built-in ex-commands, as returned by populate; mirrors Builtins for motions / operators / text objects.

Functions§

populate
Register every built-in ex-command into registry and return the ids callers need by field (see ExBuiltins).