@graelo/pi-vim1.0.1
Vim mode for the pi coding agent prompt editor
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-vim
Vim-style prompt editing for Pi.
pi-vim replaces Pi's main input editor with a CustomEditor-based modal
editor. It targets practical prompt editing for agent prompts, not full Vim
parity.
Breaking changes
v1.0.0
- The fork is renamed from pi-vimmode to pi-vim.
/vimmodeis now/vim, and:vimmode inspectis now:vim inspect. - Options no longer live in Pi's
settings.json. Move the oldpiVimModeobject, without its wrapper key, to~/.pi/agent/extensions/pi-vim/config.json(or.pi/extensions/pi-vim/config.jsonat a trusted repository's root), and move~/.pi/agent/pi-vimmode.config.jsto~/.pi/agent/extensions/pi-vim/config.js. The old locations are not read. - See
CHANGELOG.mdfor removed commands and settings.
v0.7.0
Ctrl-vno longer enters visual block mode by default.Ctrl-v, WindowsAlt-v, andCtrl-Alt-vare delegated to Pi for image/clipboard paste in normal and visual modes unless explicitly rebound.- Visual block mode now has an empty default keybinding. Configure
keymap.commands.visualBlockwith a non-protected key such as<A-b>, or explicitly allow and bind<C-v>if Vim-style visual block is more important than Pi image paste in your workflow.
{
"keymap": {
"commands": { "visualBlock": ["<A-b>"] }
}
}
To intentionally reclaim Ctrl-v for visual block:
{
"keymap": {
"commands": { "visualBlock": ["<C-v>"] },
"allowProtectedOverrides": ["<C-v>"]
}
}
Install / load
Install from npm:
pi install npm:@graelo/pi-vim
or Install from Git to install latest version:
pi install git:https://github.com/graelo/pi-vim
For local development from this checkout:
npm install
pi -e ./src/index.ts
Pi discovers the extension through package.json:
{
"pi": {
"extensions": ["./src/index.ts"]
}
}
For local testing, load this package as a Pi extension using Pi's normal extension loading flow.
Compatibility with extensions that modifies editor
Pi currently exposes a single custom-editor factory which makes last extension
could overrides previous editor factories.
Currently, pi-vim is implemented with CustomEditor which cannot decorate
an arbitrary editor instances provided by other extensions. This means editor
extensions that maintain per-instance state, such as history or additional
editor behavior, may lose that state when their factory is replaced.
Until pi supports composable order independant editor extension api, you should
load pi-vim in front of other extensions that set editor component, like
@zigai/pi-prompt-history. Load pi-vim before other extensions in
settings.json:
{
"packages": ["pi-vim", "another-editor-extension"]
}
See issue #16 for more information.
Quick start
- Start Pi with the extension loaded.
- Type normally in insert mode.
- Press
Escto enter normal mode when autocomplete is inactive. - Use supported Vim commands such as
h,j,k,l,w,b,e,0,$,i,a,x,dd,cw,p,/,n,N,v,V, configured visual block,:s,:d,:y,:pu,:t,:m,:j,:noh,q,@, and@@. - Press
i,a,I,A,o,O,C,s, orSto return to insert mode after edits; use operator forms such ascw,cc, orc$when changing by motion.
Default modes:
- INSERT: Pi-like text entry. Autocomplete, submit, newlines, image paste, external editor, and app shortcuts use Pi's default behavior.
- NORMAL: supported Vim command mode. Unsupported printable keys are ignored.
- VISUAL: characterwise selection.
- V-LINE: linewise selection.
- V-BLOCK: rectangular block selection.
Esc in normal mode delegates to Pi so interrupt/abort behavior still works.
Esc in visual modes cancels the selection and returns to normal mode.
Documentation
Canonical user-facing docs live under docs/:
docs/features.md: supported modes, motions, edits, operators, prompt-native text objects, character search, prompt search, visual modes, Ex command-line commands, registers, marks, macros, UI/status rendering, Pi shortcut compatibility, limitations, recovery, and validation examples.docs/settings.md: every supported setting, defaults, accepted value shapes, merge behavior, key sequence syntax, protected-key validation, warnings, troubleshooting, and practical config examples.docs/adr/0002-user-facing-pi-vimmode-docs.md: documentation source-of-truth decision and maintenance rules.
README is the quickstart and index. Keep detailed behavior and settings reference in the canonical docs above.
Common configuration
Options go in ~/.pi/agent/extensions/pi-vim/config.json (or under
PI_CODING_AGENT_DIR when set). A trusted repository can override them in
.pi/extensions/pi-vim/config.json at its root. See
docs/settings.md
for precedence.
Minimal startup override:
{
"startMode": "normal"
}
Example keymap/UI override:
{
"leader": " ",
"cursor": {
"normal": "block",
"insert": "bar"
},
"keymap": {
"commands": {
"startSearch": ["/"],
"showKeybindings": ["<leader>k"]
}
},
"ui": {
"status": {
"items": ["mode", "pending", "search", "macro", "cursorPosition", "warnings"]
}
}
}
EasyMotion
EasyMotion has no default binding. Bind command.easymotion, type a target
character, then press its label to move the cursor. Matching is case-insensitive
and prompt-wide, with up to 52 labels (lowercase, then uppercase). Labels are
render-only substitutions, so prompt text and undo/redo history stay unchanged.
Configure label color with easymotion.labelColor:
{
"easymotion": {
"labelColor": "\u001b[31m"
}
}
Common ANSI color codes: \u001b[31m (red), \u001b[32m (green), \u001b[33m
(yellow), \u001b[34m (blue), \u001b[35m (magenta), \u001b[36m (cyan),
\u001b[37m (white). Default is red (\u001b[31m).
Trusted global JS keybindings live at ~/.pi/agent/extensions/pi-vim/config.js
and run as unsandboxed local code with full Pi process privileges. See
trusted JavaScript config guide:
/** @type {import("../../npm/node_modules/@graelo/pi-vim/config").VimConfig} */
export default (vim) => {
vim.g.mapleader = " ";
vim.keymap.set("i", "<A-w>", vim.prompt.deleteWordBackward());
vim.keymap.set("n", "<leader>q", vim.prompt.reflow({ width: 88 }));
vim.keymap.set("n", "ZD", ":vimdoctor<CR>");
};
Run /vim reload after editing root JS config. See
docs/config.md
for complete trusted JavaScript API, workflows, reload, and safety contract. See
docs/settings.md
for canonical JSON defaults and settings.
Recover or disable
If the extension blocks editing or configuration goes wrong:
- Run
/vim offto restore Pi's previous editor for the current extension runtime. - Run
/vim onor/vimto enable the Vim editor again. - Start with
docs/features.md#disable-or-recover. - Use
pi listto inspect installed extensions. - Use
pi removeorpi uninstallwith the installed extension identifier to remove it. - Remove or edit
extensions/pi-vim/config.jsonin the agent directory or the repository.pi/directory to drop pi-vim overrides. - Restart Pi after changing extension or config state.
Architecture
VimEditor is the Pi adapter shell. It owns CustomEditor integration,
snapshots, effect application, rendering bridge, public cursor restoration, and
best-effort terminal cursor writes. Insert-mode bar hardware cursors stay
visible while Pi agent work is active; non-bar cursors are suppressed during
busy output.
Modal editing behavior lives under src/modal/:
engine.tsowns mode transitions, finite semantic key dispatch, register updates, and supported Vim semantics.types.tsdefines adapter-applied effects such as delegation, edits, macro replay, cursor restoration, invalidation, and terminal cursor hints.view.tsderives mode labels, status items, visual status text, and cursor position text without needing Pi TUI objects.
The parser in src/commands.ts and text transforms in src/buffer.ts remain
pure helpers. Config maps keys to supported semantic actions; it does not add
private Pi APIs, recursive mappings, .vimrc, Vimscript, or Neovim Lua support.
Project docs
docs/features.md: canonical feature guide.docs/settings.md: canonical settings reference.docs/adr/: architecture decision records, managed withadrs.docs/solutions/: reusable learnings for parser, buffer, lifecycle, and visual-mode bugs.openspec/specs/: durable OpenSpec requirements for supported Vim behavior.
Validate
npm run check
npm run lint
npm test
npm run check:config-reference
openspec validate --specs --strict
npm pack --dry-run
Before publishing, inspect dry-run package contents and confirm src/,
CHANGELOG.md, and the user docs are included, and that tests, benchmarks, and
OpenSpec files are not.
Manual smoke checklist:
- Load extension in Pi.
- Type text in insert mode.
- Press
Esc, use normal-mode motions and edits. - Use
v,V, and a configured visual-block binding such as<A-b>; confirm visual highlighting and selection operations. - Configure
startMode,cursor, a keymap binding, and UI status items; confirm behavior changes. - Confirm insert/normal submit and normal-mode
Escstill delegate to Pi where expected. - Record and replay a macro with
q{slot},@{slot}, and@@. - Run
/query,n,N,:%s/old/new/g,:2,3copy$,:move0, and:noh; confirm prompt-local search/Ex behavior.