Skip to content

feat(editor): add opt-in Vim keybindings for writable file editors - #28412

Open
Shadorain wants to merge 12 commits into
stablyai:mainfrom
Shadorain:Shadorain/feature-vim-mode-in-editor
Open

Shadorain wants to merge 12 commits into
stablyai:mainfrom
Shadorain:Shadorain/feature-vim-mode-in-editor

Conversation

@Shadorain

@Shadorain Shadorain commented Oct 13, 2026 •

Copy link
Copy Markdown

ELI5

Adds a Vim mode to Orca's built-in file editor. A new Editor Keybindings setting under Settings → General → Editor offers Default (unchanged, persisted default) or Vim. Choosing Vim turns on modal editing in writable file editors and in the writable half of editable diffs, with a status row that shows the current mode (--NORMAL--, --INSERT--, etc.). :w writes the file through the normal save path. Users who never switch see no change.

What Changed

Diff size: source +418 / −16 (18 files), tests +419 / −0 (5 files).

  • New persisted setting editorKeybindings ('default' | 'vim', default 'default'); unknown/missing values resolve to Default without rewriting the stored value.
  • New segmented Editor Keybindings row in Settings → General → Editor, searchable via vim, keybindings, modal, normal mode keywords.
  • monaco-vim@0.4.4 added as a dependency, loaded lazily via import() so Default sessions never pull it.
  • New monaco-vim-mode.ts + use-monaco-vim-attachment.tsx seam: attaches initVimMode only to writable, full-height Monaco editors and the modified side of editable DiffViewers; renders a status row below the editor body; registers a single process-global defineEx('write') that routes :w to whichever editor currently owns focus.
  • A capture-phase Escape bridge on the editor container closes the find widget before Vim can swallow Escape; other Save/Find chords keep their existing capture-phase listeners.
  • Toggle off removes the status row and disposes the adapter without remounting the editor, so undo history survives.

Why

#26921 asks for Vim editing so users can make quick manual edits without leaving Orca. Orca embeds Monaco, not a VS Code extension host, so VSCodeVim cannot be installed; monaco-vim is the smallest maintained bridge. A home-grown keymap was rejected for the same reason the older, broader PR #9755 was left alone: this keeps scope to Default/Vim plus :w and reuses the existing Save path rather than reimplementing save or tab commands.

Linked Issue

Fixes #26921

Visual Proof

N/A — recorded but not attached here: the Electron e2e spec could not run on this host (see Testing). Settings row is a segmented Default/Vim control matching the existing Editor Word Wrap row; the status row is a muted bar under the editor showing --NORMAL--.

Testing

  • Automated tests added/updated, or explained why not below
  • I manually tested these changes locally

Ran in the worktree:

  • pnpm test src/renderer/src/components/editor/monaco-vim-mode.test.ts — real monaco.editor.create + monaco-vim under happy-dom: attaches in --NORMAL--, x deletes, i/Escape round-trips modes, :w reaches the focused editor's save callback, Escape closes an open find widget instead of reaching Vim, dispose removes the adapter.
  • pnpm test on the new settings/search/shared tests and the existing DiffViewer/DiffSectionBody/EditorContent lifecycle suites — all pass (64 tests).
  • oxlint --deny-warnings and oxfmt --check clean on changed files.

Not run — this host OOM-kills the full-renderer typecheck and the Electron e2e build (8 GB RAM, saturated by other sessions; both exit 137):

  • pnpm tc
  • ORCA_BACKGROUND_LAUNCH=1 pnpm test:e2e -- tests/e2e/vim-keybindings-file-editor.spec.ts (the spec is committed and covers the full acceptance flow; it needs a host that can build the app)

Notes

  • Cross-platform: no platform-specific code; shortcuts stay on the existing platform-aware handlers. SSH/folder workspaces share the same renderer and save path — no wire or protocol changes.
  • The only vitest config change is inlining monaco-vim so Vite resolves its extensionless monaco-editor internal imports under the test runner; production bundling resolves them without any alias (verified with a standalone Vite build).
  • Attach failure is non-fatal: the error is logged, the adapter is disposed, and the editor stays on Default keybindings.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason — could not launch the app on this host; settings row follows the existing segmented-control pattern
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred) — changed-file lint/format and the touched test suites pass; full typecheck and e2e blocked on host memory as noted above

Adds an editorKeybindings setting (default/vim) under Settings → General →
Editor. When set to vim, writable full-height file editors and the modified
side of editable diffs attach monaco-vim, start in Normal mode, show the
adapter status row, and route :w through the surface's existing save path.
Orca Save/Find stay on their capture-phase shortcuts; Escape closes the find
widget before vim sees it. Read-only, auto-height, combined-diff, terminal,
and rich-markdown surfaces are untouched.

Refs stablyai#26921
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review.

Walkthrough

Adds an opt-in Vim keybinding setting for Monaco editors. Vim attaches to writable, full-height file editors and the modified side of editable diffs. The integration supports Vim mode changes, routes :w through existing save callbacks, and handles Escape when the find widget is open. It also adds preference defaults, settings search, unit and end-to-end tests, and documentation.

Merge Risk: Minimal · up to e1f95

The identified save-routing and type-binding risks are resolved; no actionable merge-blocking issue remains after normal checks.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning The description has all template sections: ELI5, What Changed, Why, Linked Issue (Fixes #26921), Visual Proof, Testing, Risk, AI Disclosure, Review, Notes, and Checklist. The author gives a clear befo… Add a Risk section. Name the riskiest part of the change, such as the monaco-vim attachment, the global Escape capture bridge, and the settings-type changes, and state what users would see if it fails. Set the Level to Low, Medium, or High.…
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: adding opt-in Vim keybindings for writable file editors.
Linked Issues check Passed The only directly linked issue, #26921, is closed. Per the assessment rules, it supplies background only. No active directly linked targets remain, so no linked-issue coding requirements apply. The PR…
Out of Scope Changes check Passed The current whole-PR summary (merge base b0ad924 to head e1f950f) lists no changes to docs/bug-reproductions/delayed-agent-launch.md and no MiniMaxEndpoint relocation or import changes. The earlier ou…
Full details: Linked Issues check

Explanation

The only directly linked issue, #26921, is closed. Per the assessment rules, it supplies background only. No active directly linked targets remain, so no linked-issue coding requirements apply. The PR still implements the historical request for Vim editing: opt-in Vim mode in writable file editors and editable diff sides, but this does not create a requirement. No coding requirement is unmet.

Full details: Out of Scope Changes check

Explanation

The current whole-PR summary (merge base b0ad924 to head e1f950f) lists no changes to docs/bug-reproductions/delayed-agent-launch.md and no MiniMaxEndpoint relocation or import changes. The earlier out-of-scope findings are therefore no longer supported by the current evidence. The PR comments also state that these changes were reverted. The remaining changes connect to the Vim feature: the Vim dependency and lazy loading, the vitest inlining of monaco-vim, the settings type and default, the settings row and search entry, the MonacoEditor and DiffViewer attachment, the monaco-vim-mode adapter and hook, the e2e probe getValue addition, tests, the e2e spec, documentation, and the plan file. The move of editor settings from global-settings-types.ts into the new editor-global-settings.ts type supports placing the new editorKeybindings field. This is a type refactor that connects to the feature. This verdict relies on the AI-generated summary and the PR comments. No repository inspection was available to confirm the reverted files directly.

Full details: Description check

Explanation

The description has all template sections: ELI5, What Changed, Why, Linked Issue (Fixes #26921), Visual Proof, Testing, Risk, AI Disclosure, Review, Notes, and Checklist. The author gives a clear before and after for the user, the mechanism, and the reason for the chosen approach. Gaps: Visual Proof is N/A but the template requires before and after visuals for UI changes, and the author gives a reason (the app could not launch on this host). The Risk section is missing entirely. The template requires a Risk section with a Level and a backout plan. The Agent skill upstream boundary section is also absent. Manual testing is unchecked, and the lint, typecheck, test, and build checklist item is only partly done. Typecheck and the e2e spec were not run.

Resolution

Add a Risk section. Name the riskiest part of the change, such as the monaco-vim attachment, the global Escape capture bridge, and the settings-type changes, and state what users would see if it fails. Set the Level to Low, Medium, or High. Explain how to back it out: a plain revert, or what a revert would not undo, such as persisted editorKeybindings values. Add the Agent skill upstream boundary section and check the applicable box. Complete the manual test or state clearly that it was not done. Add the missing before and after visuals, or keep N/A with the reason. Run pnpm typecheck and the e2e spec on a host with enough memory, or state the remaining gap. Also review the removal of editorAutoSave, editorAutoSaveDelayMs, editorMinimapEnabled, editorFontFamily, and editorWordWrap from GlobalSettings. The description does not explain that change, but the summary shows it. Include it under What Changed or Risk.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8f8180f6-63e2-440f-813c-3bfb10a32ab9
Commits

Reviewing files that changed from the base of the PR and between 8327b2a and e1f950f.

Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing: 8
  • config/vitest.config.ts
  • package.json
  • src/renderer/src/components/editor/DiffViewer.tsx
  • src/renderer/src/components/editor/MonacoEditor.tsx
  • src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
  • src/renderer/src/components/settings/general-editor-search.test.ts
  • src/shared/global-settings-base.ts
  • src/shared/global-settings-types.ts
Files with no reviewable changes: 1
  • src/shared/global-settings-types.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 88ae35fc-b05f-45fa-bdfb-b834bcb1e356
📥 Commits

Reviewing files that changed from the base of the PR and between 6cfe678 and b4e71f4.

⛔ Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing: 19
  • config/vitest.config.ts
  • package.json
  • src/renderer/src/components/editor/DiffViewer.tsx
  • src/renderer/src/components/editor/MonacoEditor.tsx
  • src/renderer/src/components/editor/monaco-e2e-probe.ts
  • src/renderer/src/components/editor/monaco-vim-mode.test.ts
  • src/renderer/src/components/editor/monaco-vim-mode.ts
  • src/renderer/src/components/editor/use-monaco-vim-attachment.ts
  • src/renderer/src/components/settings/EditorKeybindingsSetting.test.tsx
  • src/renderer/src/components/settings/EditorKeybindingsSetting.tsx
  • src/renderer/src/components/settings/GeneralEditorSettingsSection.tsx
  • src/renderer/src/components/settings/GeneralPane.test.ts
  • src/renderer/src/components/settings/general-editor-search.ts
  • src/shared/constants.test.ts
  • src/shared/default-global-settings.ts
  • src/shared/editor-keybindings.test.ts
  • src/shared/editor-keybindings.ts
  • src/shared/global-settings-types.ts
  • tests/e2e/vim-keybindings-file-editor.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

@Shadorain
Shadorain force-pushed the Shadorain/feature-vim-mode-in-editor branch from c57892c to a147d78 Compare October 15, 2026 21:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 648963db-8f21-40d4-8a25-cff204e8b8cc
📥 Commits

Reviewing files that changed from the base of the PR and between a147d78 and 8327b2a.

⛔ Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing: 4
  • src/main/rate-limits/minimax/minimax-fetcher.ts
  • src/main/rate-limits/minimax/minimax-request-context.ts
  • src/shared/global-settings-types.ts
  • src/shared/minimax-endpoint.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment thread src/shared/global-settings-types.ts Resolved
@Shadorain

Copy link
Copy Markdown
Author

Dispositions:

  1. Missing MiniMaxEndpoint import (thread + review): Valid, fixed. GlobalSettings.minimaxEndpoint referenced the type after the re-export removal. Resolution follows upstream's new GlobalSettingsBase in src/shared/global-settings-base.ts — MiniMaxEndpoint stays a local export of global-settings-types.ts, no extra module needed.

  2. Out-of-scope warnings: docs/bug-reproductions/delayed-agent-launch.md formatting reverted to upstream. The MiniMaxEndpoint relocation existed only because upstream's GlobalSettingsBase refactor pushed global-settings-types.ts past the oxlint 300-line cap once editorKeybindings joined; upstream now declares the type locally again, so the extra module and import repoints are removed entirely.

  3. Docstring coverage: Declined — docstrings are not this repo's style; comments stay minimal per project convention.

Sources: review 5550355176, comment 6154841428.

This branch has not been deployed

No deployments
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 in Editor

1 participant