Skip to content

feat(cli): add vim modal editing to the prompt input#11428

Open
drye wants to merge 3 commits into
Kilo-Org:mainfrom
drye:feat/cli-vim-mode-prompt
Open

feat(cli): add vim modal editing to the prompt input#11428
drye wants to merge 3 commits into
Kilo-Org:mainfrom
drye:feat/cli-vim-mode-prompt

Conversation

@drye

@drye drye commented Jun 18, 2026

Copy link
Copy Markdown

Issue

Fixes #9647

Context

Adds a vim mode for the CLI prompt input, as requested in #9647 (Claude Code has a similar toggleable vim mode). When enabled, the prompt becomes a modal editor with NORMAL/INSERT modes so longer prompts can be edited with familiar vim keys without leaving the TUI.

It is fully opt-in and a no-op for existing users until turned on.

Implementation

The prompt input is the @opentui/core TextareaRenderable in packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx. The TUI dispatches a renderable's onKeyDown before the textarea's own handleKeyPress, and only runs the latter if (!key.defaultPrevented). That gives a clean seam: in NORMAL mode we handle the key and preventDefault() so the textarea never inserts it.

  • component/prompt/vim.ts is a self-contained, renderer-agnostic engine operating on a small VimDoc interface (text/cursor + insert/remove/undo/redo). Keeping it decoupled from OpenTUI makes it unit-testable against a plain in-memory document. It implements a practical subset:
    • motions: h j k l, w W b B e E, 0 ^ $, gg G, numeric counts (3w, 5j), sticky desired column on j/k
    • edits: x X, D C, s, r{char}, dd cc yy, d/c/y + motion (with the vim cwce special case), p P
    • insert transitions: i I a A o O; history: u, Ctrl+r
  • The prompt adapts the live textarea to VimDoc using buffer-aware ops (insertText, setSelection/deleteSelection) so file-mention extmarks survive edits. Enter still submits, Tab still completes, and global Ctrl/Meta combos (e.g. Ctrl+C) still pass through in NORMAL mode.
  • UX: a NORMAL/INSERT indicator in the meta row and a matching block/bar cursor shape. Mode resets to INSERT after submit/clear.
  • Opt-in surfaces: a vim boolean in tui.jsonc, a prompt.vim.toggle keybind (default unbound), a Toggle vim mode entry in the command palette (ctrl+p), and a /vim slash command.

A few behaviours are documented approximations of real vim (e.g. linewise cc, internal-only paste register, no f/t find-char yet).

Screenshots / Video

Demo of modal editing in the prompt: INSERT/NORMAL/VISUAL switching, motions, edits, and the mode indicator.

Vim mode in the Kilo CLI prompt

How to Test

Manual/local verification

  • bun run typecheck for @kilocode/cli (opencode package): passes with 0 errors (agent-executed).
  • bun test test/cli/cmd/tui/prompt/vim.test.ts: 27/27 pass (agent-executed).
  • Ran the TUI from source (bun run dev) with "vim": true and exercised motions/edits/mode switching, plus confirmed Enter/Tab/Ctrl+C behavior (human-executed).

Reviewer test steps

  1. From packages/opencode, run bun run dev (or a built binary).
  2. Enable vim mode: add { "vim": true } to ~/.config/kilo/tui.jsonc, or open ctrl+pToggle vim mode, or type /vim.
  3. In the prompt: type text (INSERT), press Esc (NORMAL), try w b 0 $ gg G, dd dw cw x, i a A o, yy p, u / Ctrl+r.
  4. Confirm Enter still submits, Tab still completes, and Ctrl+C still exits.

Blocked checks and substitute verification

  • The repo pre-push hook runs a full-monorepo turbo typecheck which fails on the unrelated @kilocode/kilo-jetbrains package because Java 21 is not installed in this environment. Substitute verification: ran bun run typecheck directly in the @kilocode/cli package (0 errors) and the vim unit tests. CI will run the full suite.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

Implements vim mode for the CLI prompt (issue Kilo-Org#9647).

- New self-contained, unit-tested vim engine (component/prompt/vim.ts)
  operating on a renderer-agnostic VimDoc: NORMAL/INSERT modes, motions
  (h/j/k/l, w/W/b/B/e/E, 0/^/$, gg/G, counts, sticky column on j/k),
  edits (x/X, D/C, s, r, dd/cc/yy, d/c/y + motion, p/P), insert
  transitions (i/I/a/A/o/O), and u / Ctrl+r.
- Integrates into the prompt textarea via onKeyDown interception (blocks
  textarea insertion in NORMAL mode), using buffer-aware edit ops so file
  mention extmarks stay intact. Enter still submits, Tab still completes,
  Ctrl+C still exits.
- Adds a NORMAL/INSERT indicator and matching cursor shape.
- Opt-in: 'vim' tui config option, 'prompt.vim.toggle' keybind, the
  'Toggle vim mode' command palette entry, and a /vim slash command.
- 27 unit tests for the engine.
Comment thread packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts Outdated
Comment thread packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts Outdated
Comment thread packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts Outdated
Comment thread packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
Comment thread packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts
@kilo-code-bot

kilo-code-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 5
SUGGESTION 1

Fix: Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 340 Linewise deletes and changes into EOF drop the previous line break.
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 405 dd on the final line also deletes the previous line.
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 421 Linewise paste after the last line loses its separator newline.
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx 441 Disabling vim mode can leave the block cursor behind.

SUGGESTION

File Line Issue
packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts 202 Add an EOF regression case for linewise delete.
Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx 1546 Several prompt-emptying and restore paths (clearPrompt, stash push/pop, history recall) still bypass resetVim(), so stale visual or pending normal-mode state can leak into an emptied or restored prompt.
Files Reviewed (4 files)
  • .changeset/vim-mode-prompt-input.md - 0 issues
  • packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx - 2 issues
  • packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts - 3 issues
  • packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts - 1 issue
Previous Review Summaries (2 snapshots, latest commit 23c3946)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 23c3946)

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 5
SUGGESTION 1

Fix: Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 340 Linewise deletes and changes into EOF drop the previous line break.
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 405 dd on the final line also deletes the previous line.
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 421 Linewise paste after the last line loses its separator newline.
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx 441 Disabling vim mode can leave the block cursor behind.

SUGGESTION

File Line Issue
packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts 202 Add an EOF regression case for linewise delete.
Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx 1546 Several prompt-emptying and restore paths (clearPrompt, stash push/pop, history recall) still bypass resetVim(), so stale visual or pending normal-mode state can leak into an emptied or restored prompt.
Files Reviewed (4 files)
  • .changeset/vim-mode-prompt-input.md - 0 issues
  • packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx - 2 issues
  • packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts - 3 issues
  • packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts - 1 issue

Previous review (commit 69f5b9d)

Status: 5 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 1

Fix: Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 332 Linewise delete and change motions that run into EOF pull the previous newline into the deletion range.
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 397 dd on the final line rewinds to the previous line start and deletes too much.
packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts 413 Linewise paste after the final line loses the separator newline because the EOF branch is unreachable.
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx 429 Toggling vim mode off from NORMAL mode does not restore the non-vim cursor style.

SUGGESTION

File Line Issue
packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts 192 Add an EOF regression case for dd or another linewise delete into EOF.
Other Observations (not in diff)

None.

Files Reviewed (6 files)
  • .changeset/vim-mode-prompt-input.md - 0 issues
  • packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx - 1 issue
  • packages/opencode/src/cli/cmd/tui/component/prompt/vim.ts - 3 issues
  • packages/opencode/src/cli/cmd/tui/config/keybind.ts - 0 issues
  • packages/opencode/src/cli/cmd/tui/config/tui-schema.ts - 0 issues
  • packages/opencode/test/cli/cmd/tui/prompt/vim.test.ts - 1 issue

Reviewed by gpt-5.4-20260305 · 50,151 tokens

Review guidance: REVIEW.md from base branch main

drye added 2 commits June 18, 2026 16:52
Adds VISUAL (v) and VISUAL-LINE (V) modes to the prompt vim engine:

- Selection-extending motions (h/j/k/l, w/b/e, 0/^/$, gg/G, counts).
- Operators on the selection: d/x (delete), c/s (change), y (yank);
  o swaps the moving end with the anchor; v/V toggle/switch sub-modes;
  Esc exits. Selection is highlighted via the textarea's setSelection.
- VimDoc gains setSelection/clearSelection; VISUAL/V-LINE indicator and
  block cursor; selection cleared on reset/submit/disable.
- 10 new engine unit tests (37 total).
Addresses kilo-code-bot review on PR Kilo-Org#11428:

- Centralise linewise d/c/y in a single linewiseOperate helper used by
  operator+motion, dd/cc/yy, and visual-line. Fixes:
  - dd on the final line no longer deletes the previous line.
  - cc on the final line leaves a single empty line (no extra blank).
  - linewise delete/change into EOF only removes one adjoining newline.
- Linewise paste after the final (newline-less) line now inserts a
  separator so the pasted line is not merged onto the last line.
- Disabling vim mode restores the default cursor style instead of
  leaving a block cursor behind.
- resetVim() now also runs on clearPrompt, stash push/pop, stash-list
  select, and history recall so stale visual/normal state cannot leak
  into an emptied or restored prompt.
- Add linewise-EOF regression tests (dd/cc/yy/dG/Vd); 44 tests total.
@drye

drye commented Jun 18, 2026

Copy link
Copy Markdown
Author

Thanks for the review — all six items addressed in a5df310:

Warnings (inline, resolved):

  • Linewise d/c/y into EOF now go through one linewiseOperate helper (one adjoining newline only; register newline-terminated).
  • dd on the final line keeps the preceding line.
  • Linewise paste after a newline-less final line keeps a separating newline.
  • Disabling vim restores the default cursor style (no lingering block cursor).

Suggestion: added a vim linewise EOF edge cases test block (dd/cc/yy/dG/Vd).

Other observation (not in diff): resetVim() now also runs on clearPrompt, stash push/pop, stash-list select, and history recall, so stale visual/normal-mode state can't leak into an emptied or restored prompt.

Verification: bun test test/cli/cmd/tui/prompt/vim.test.ts → 44/44 pass; bun run typecheck → 0 errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: vim mode for CLI prompt input

1 participant