Ex-commands

The : line. Type : from Normal mode to enter the cmdline, type a command, hit <CR> to run.

:w<CR>                  " write
:e foo.rs<CR>           " open foo.rs
:set tabstop=4<CR>      " set option
:%s/foo/bar/g<CR>       " substitute throughout buffer

Lattice's ex-command surface is a typed command registry. Every command has an arg schema (with prompt strings + optional default values + completion); the cmdline parser validates against it. This means tab-completion, arg-prompts on missing required args, and :describe-command work for every command, including plugin-supplied ones.

Built-in command count: roughly 130 at the time of writing. :apropos<Tab> enumerates every name; :describe-command NAME shows full metadata.


Quick reference

Buffer / file

CommandAction
:w / :writeWrite buffer to its current path
:w PATHWrite to PATH
:wq / :xWrite + quit
:q / :quitQuit if buffer is clean
:q!Quit unconditionally
:e PATH / :editOpen PATH in active pane
:e!Reload current file from disk
:bn / :bnextCycle to next buffer
:bp / :bprevCycle to previous buffer
:b NSwitch to buffer #N
:b PATTERNSwitch to buffer matching PATTERN
:buffers / :bOpen the fuzzy buffer switcher (picker)
:history [commands|searches]Fuzzy picker over history. commands (default): command line (q:). searches: search line (q/ / q?). <CR> loads into the prompt, does not run
:bd / :bdeleteClose active buffer
:bd!Close even if dirty
:lsList every open buffer as static text

Splits / panes

CommandAction
:split / :spHorizontal split of active pane
:vsplit/:vspVertical split
:close / :clClose active pane
:only / :onClose every pane except the active one

<C-w>-prefixed chords (<C-w>s, <C-w>v, <C-w>q, ...) are the keymap equivalents.

File tree / oil

CommandAction
:Tree [path]Open file tree rooted at path (default: current dir)
:TreeCloseDismiss file-tree pane
:Oil [path]Open oil-style editable directory listing

Search / substitute

CommandAction
:s/pat/repl/Substitute first match on current line
:s/pat/repl/gAll matches on current line
:%s/pat/repl/gAll matches in buffer
:'<,'>s/pat/repl/g (in Visual)All matches in selection
:noh / :nohlsearchClear hlsearch overlay
:g/pat/CMDRun :CMD on every line matching pat
:v/pat/CMDRun :CMD on every line not matching pat

Options / customize

CommandAction
:set NAME=VALUESet typed option
:set NAME (boolean)Set to true
:set noNAME (boolean)Set to false
:set NAME?Echo current value
:optionsList every customizable option
:describe-option NAMEShow one option's full metadata
:describe-option-resolution NAMEShow which resolver layer provides NAME's value
:customizeOpen the customize picker
:customize <group>Open the focused group view
:customize <mode-name>Open the mode's contributed-options view

Modes

CommandAction
:<mode-name>Toggle a registered mode (e.g. :lsp-mode)
:list-modesList every registered mode
:describe-mode NShow one mode's metadata

LSP

See lsp for the full inventory. Most-used:

CommandAction
:lsp-formatFormat the buffer
:lsp-format-rangeFormat the Visual selection
:lsp-rename NEWNAMERename symbol under cursor
:lsp-symbolsDocument symbol picker
:lsp-workspace-symbol QUERYWorkspace symbol search
:lsp-code-actionCode-action picker
:lsp-statusPer-server attach + capability status
:lsp-log [server]Open per-server log buffer
:lsp-trace SERVERToggle JSON-RPC tracing for SERVER
:lsp-trace-log [server]Open the trace log
:lsp-restart SERVERRestart SERVER
:lsp-server-logOpen the server's stderr feed

Diagnostics

CommandAction
:diagnosticsOpen the diagnostics picker
:diag-next / :cnextJump to the next diagnostic
:diag-prev / :cprevJump to the previous

Help / introspection

CommandAction
:help [TOPIC]Open help for TOPIC; no arg → topic index
:describe-command NAMEShow one command's metadata
:list-commandsList every registered command, grouped by source (built-in / plugin / user)
:describe-mode [NAME]Show a mode's metadata (keymap, options, source)
:list-modesList every registered mode + its :<mode-name> toggle
:describe-bufferShow active buffer's state summary
:describe-key CHORDShow what CHORD does (in every mode it's bound)
:describe-eventsList every typed event
:describe-event NAMEShow one event's descriptor
:apropos PATTERNSearch commands + options + events for PATTERN
:keymapList every default chord binding

State / scratch

CommandAction
:reg/:registersList populated registers
:marksList set marks
:jumps(When implemented) show position-history ring
:reload-snippetsRe-read every snippet file

Completion

CommandAction
:completeTrigger LSP completion at cursor

Misc

CommandAction
:hover [TEXT]Open a hover popup with TEXT (testing path)
:HoverCloseDismiss active hover popup
:42Jump to line 42
:'a,'b!CMD(Future) Filter range through external CMD
:!CMD(Future) Run external CMD

Cmdline UX

The : line is itself a buffer with a major mode (command-line). Every Normal-mode editing primitive that makes sense in a single-line context applies — motions, deletion, undo (within the line), etc.

Specific behaviours:

  • <Tab> after the command name expands arg completion (paths for path-typed args, names for name-typed args).
  • <Tab> on a partial command name expands the command.
  • <Esc> cancels and returns to Normal.
  • <C-c> same as <Esc> (cancel).
  • <C-h> opens :describe-command for the partially-typed command (when implemented).
  • <Up> / <Down> walk command history.
  • <C-n> / <C-p> same as <Down> / <Up>.

As you type, the : line is live-decorated:

  • Syntax highlighting — the command word, range prefix (%, '<,'>), ! bang, and :s/pattern/replacement/flags fields each colour by their role.
  • Error indicator — an unknown command (once you type a space after it) is flagged inline, and its word turns the diagnostic-error colour.
  • Parameter hint — a dim hint of the command's expected arguments (<file>, <pattern>/<replacement>/[flags], …) trails the line.
  • :s/// preview — matches of the in-progress substitution are highlighted in the buffer before you press <CR>.

Expanding the command line

<C-x><C-e> expands the one-row : line into a full-modal mini-buffer band that grows upward, pushing the panes above it up. In the band you get the whole vim grammar — Normal/Insert/Visual, motions, registers, undo, multi-line editing. <C-x><C-e> again (or <Esc> then the chord) collapses back to the one-row line with your edits intact; <CR> from the collapsed line runs it (the band never auto-executes). <C-c> cancels and discards the expanded edits.

  • command-line.expand-height sizes the band: half (default, half the frame), full (as tall as the frame allows), or a bare integer for a fixed row count. E.g. :set command-line.expand-height=full.

Command-line history picker

Beyond the in-line <Up>/<Down> walk, past commands and search patterns are browsable through fuzzy pickers — the modern replacement for vim's command-line window:

Command history (command_history):

  • q: (Normal-mode chord) or :history or :history commands opens a fuzzy picker over your command history, newest first. Type to filter; <CR> loads the chosen command into the : line — it does not run it. Tweak it (or <C-x><C-e> to expand into the full-modal band), then <CR> to execute.
  • q: from inside the expanded command-line band seeds the picker filter with whatever you have typed so far.
  • q: steals nothing from macro recording: qaqz still record into their registers (: is not a valid register name).

Search history (search_history):

  • q/ or q? (Normal-mode chords) or :history searches opens a fuzzy picker over your search history, newest first. Accept loads the chosen term into the / search line — does not run the search. Tweak it (or expand), then <CR> to execute.
  • q/ and q? share the same ring; the direction matches the chord.
  • Like q:, these are exact-path bindings that don't interfere with macro recording (/ and ? are not valid register names).

Both pickers are trait-driven via CommandHistorySource / SearchHistorySource in lattice-picker, accessible through :picker history / :picker search-history as well.


Arg schemas

Every command's args are typed:

  • string — bare string
  • path — file/dir path; <Tab> does path completion
  • option-name — registered typed-option name; <Tab> enumerates
  • mode-name — registered mode; <Tab> enumerates
  • command-name — registered command; <Tab> enumerates
  • chord — keystroke notation; the next chord is captured

Args can be Required, Optional (with default), or None.

Arg-prompts

Submitting a command without a required arg doesn't error — the cmdline prefills with the command keyword + space and the echo line shows the schema's prompt:

:describe-command<CR>
                  → cmdline shows: describe-command
                  → echo shows:    command:

Type the arg, submit, the command runs.

For chord-typed args, the prompt arms a chord capture: the next chord you press auto-submits as the argument.

<Esc> from a primed arg-prompt cancels back to Normal.


:g / :v (global / inverse-global)

Run a body command on every line matching (or not matching) a pattern.

:g/^$/d                 " delete every empty line
:g/TODO/p               " print every line containing TODO
:v/foo/d                " delete every line that doesn't contain `foo`
:%g/^/m0                " (future) move-line: reverse every line

The body is parsed at submit time, before any line is processed. So a typo'd body errors immediately, not partway through:

:g/foo/notacommand<CR>
                  → "unknown command: notacommand" (immediate)

Substitute (:s)

Vim's substitute, with live-preview while typing.

:s/pat/repl/             " first match on current line
:s/pat/repl/g            " all matches on current line
:%s/pat/repl/g           " all matches in buffer
:'<,'>s/pat/repl/g       " all matches in Visual selection

Live preview

While typing the cmdline, every match the substitute would hit lights up in magenta with a strike-through overlay. Cancel (<Esc>) clears the preview without modifying anything; submit (<CR>) commits.

For :%s/pat/repl/g, the preview spans the whole buffer; for :s/pat/repl/g, just the current line.

Pattern syntax

Lattice uses regex crate syntax (fancy-regex for backref- heavy patterns). \d+ works; (?P<name>...) works; (\w+) \w+ \1 (find duplicate-word neighbours) works.

Replacement

Plain text. \1 ... \9 reference capture groups. \0 (or &) references the whole match. (Vim's ~ and case- modifier escapes — \u, \l — land in a follow-up.)


Ranges

Most commands accept a range prefix.

RangeMeaning
(omitted)Current line for line-oriented ops; current cursor pos
42Line 42
42,50Lines 42 through 50 inclusive
'a,'bFrom mark a to mark b
'<,'>The previous Visual selection
%Whole buffer (= 1,$)
.Current line
$Last line
+5 / -5Relative to current

Examples:

:5,10d                   " delete lines 5..=10
:%s/foo/bar/g            " substitute throughout buffer
:.,$d                    " delete from cursor to end-of-buffer

Aliases

Most ex-commands have multiple surface forms — a long name + a short alias + sometimes a vim-style abbreviation. The full alias table is dynamic; :describe-command NAME lists each command's known aliases. Examples:

Long formAliases
:write:w
:edit:e
:quit:q
:buffer-next:bn, :bnext
:nohlsearch:noh
:diagnostics-next:diag-next, :dnext, :cnext, :cn
:buffer-picker:buffers, :b

Tab completion

<Tab> completion fires on:

  1. Command names. :des<Tab> cycles through describe-* commands.
  2. Arg names for option-name / mode-name / command-name args.
  3. Paths for path args.
  4. Enum values for typed-option enum values: :set foldmethod=<Tab> enumerates manual / indent / markdown / syntax.

The popup is a vertico-style picker; type to filter, <Tab> / <S-Tab> to navigate, <CR> to accept, <Esc> to cancel.


Edge cases

Commands with bang variants

Some commands accept ! to override safety checks:

  • :q! quit even if dirty
  • :e! reload even if dirty
  • :bd! close even if dirty
  • :w! write even if read-only (when applicable)

The bang variant is a separate dispatch path; the schema declares accepts_bang: true.

Empty body for :g / :v

:g/foo/<CR>
                  → error: empty body

:g with no body has no defined semantics; vim defaults to :p (print) but lattice rejects to keep the surface explicit.

Range on a non-range command

:%set tabstop=4<CR>
                  → error: this command doesn't accept a range

Each command's schema declares accepts_range. Settings commands typically don't.

Multiple commands on one line

Lattice doesn't yet support | as a command separator. One command per : invocation. Workaround: use :g// for batched runs.

History

The editor keeps two independent history rings (in-memory; not persisted to disk in v1):

  • command_history — every : submit pushes here (oldest-first, cap 100, dedup on consecutive identical). Walked by <Up>/<Down> in the : line; browsed via q: / :history / :history commands.
  • search_history — every / / ? submit pushes here (same dedup and cap). Walked by <Up>/<Down> in the search line; browsed via q/ / q? / :history searches.

See also

  • modal-editing — the keymap-side of the editor.
  • buffers — buffer / pane commands in context.
  • options:set + :customize deep dive.
  • modes:<mode-name> toggle + introspection.
  • lsp — every :lsp-* command in context.
  • completion — cmdline completion mechanics.
  • docs/dev/architecture/design.md §5.2.1 — unified command / grammar dispatcher (developer reference).