Add Vim indent/dedent operators (< and >) to the code editor#14268
Conversation
Implements Vim-style `<` (dedent) and `>` (indent) operators in the code editor only, reusing the existing `CodeEditorModel::indent(shift, ctx)` primitive that Tab/Shift-Tab already use. Shared parser (crates/vim): - Add `VimOperator::Indent` and `VimOperator::Dedent`, mapping `>`/`<`. - Recognize `<`/`>` as normal-mode operators (with motions, counts, and the doubled `>>`/`<<` line forms) and as visual-mode operators. Code editor (CodeEditorView): - `operation` and `visual_operator` route Indent/Dedent to `model.indent`, with `shift=true` for dedent. Indent operators are linewise, so the linewise selection excludes the trailing newline (so the shift primitive does not advance onto the next line) and the cursor lands on the first non-whitespace of the affected line, matching existing linewise operators. Terminal command-input EditorView: - Add explicit no-op arms for Indent/Dedent so the shared parser does not add terminal-input behavior; this feature stays code-editor-only. Tests: - Shared FSA: `>>`, `<<`, `>j`, `>w`, `>G`, `2>>`, `3>j`, visual `V>`/`v<`. - Code editor: `>>`, `<<`, dedent at column zero, one-unit dedent, non-leading text preserved, `>j`, `2>>`, `>G`, visual `V>`/`V<`/`Vj>`, and `u` undo of an indent. Co-Authored-By: Oz <oz-agent@warp.dev>
|
@warp-dev-github-integration[bot] I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds Vim </> indent and dedent operators to the shared Vim parser and wires them into the code editor, with terminal command-input handlers intended to remain no-op.
Concerns
- The shared FSA now recognizes
</>for every Vim consumer, so terminal command input can enter operator-pending mode and consume the next key even though the terminal handler later no-ops the operation. That changes the terminal surface despite the PR being code-editor-only. - Several added app-level assertions appear to expect only the first line to be indented because
unindentignores the first line when computing common indentation; the multi-line operator tests need to assert all affected lines are shifted. - This is a user-facing code-editor Vim behavior change, and the PR description does not include screenshots or a screen recording demonstrating the feature end to end. Per repo guidance, please attach visual evidence before merge.
Verdict
Found: 0 critical, 3 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
There was a problem hiding this comment.
Overview
Reviewed PR #14268 for APP-4963 against the ticket criteria: Vim </> operators in the code editor only, doubled operators, motions/counts, visual selections, dot-repeat/undo behavior, and unchanged terminal command-input behavior. The parser-focused tests reported by the PR cover the new event shapes, but the acceptance gate is not complete and one required behavior is missing in the implementation.
Concerns
- [BLOCKING] Dot-repeat is not implemented for the new indent/dedent operations. The
for_dot_repeatmatch only storesChangeandDeleteoperations;IndentandDedentfall through toNone. After>>,<<, or an indent motion, pressing.therefore does not replay that indent operation (and may replay an older operation instead). See the inline comment at the new operator mapping. - [BLOCKING] The repository formatting gate fails on this head.
cargo fmt --all -- --checkreproduces rustfmt diffs in the changedapp/src/code/editor/model.rsandapp/src/code/editor/view/vim_handler.rslines. The PR'scargo fmt -p vim --checkdoes not cover those app files, and all four Formatting + Clippy CI jobs are failing for this reason. Please run the repository formatter and commit the result. - [BLOCKING / ENVIRONMENTAL] Required user-facing visual proof is missing. The PR states that screenshots/video could not be captured in the sandbox. This is not treated as a code defect, but the code-editor behavior still needs computer-use evidence covering normal
>>/<<, motion/count and visual selection behavior, plus confirmation that terminal command-input is unchanged. - [BLOCKING / ENVIRONMENTAL] The full code-editor test target and
./script/presubmitremain outstanding because the sandbox ran out of memory/disk. The focusedvimparser tests are reported as passing, but the affected app tests and repository gate must pass on a higher-capacity runner before acceptance.
Verdict
Request changes (REJECT). Fix the dot-repeat behavior and formatting, then attach the outstanding higher-capacity test/presubmit results and visual proof. GitHub records this as a comment because the authenticated review identity is the PR author; the factory gate remains blocked.
Review run
https://oz.staging.warp.dev/runs/019f95d2-19e5-7ccb-9967-ab9b6a321f5b
…tting Rework for APP-4963 review (PR #14268). Addresses all addressable review comments in this cycle: 1. Scope violation (terminal command-input): the shared VimFSA now gates the `<`/`>` (indent/dedent) operators behind a per-VimModel flag (`indent_operators_enabled`, default false). Only the code editor's CodeEditorView enables it; the terminal command-input EditorView leaves it disabled, so `<`/`>` fall through to the FSA's catch-all no-op and never enter operator-pending mode or consume the following keystroke. This restores the terminal's pre-indent-operator behavior (a true no-op) while keeping the operators active in the code editor. The terminal's `operation`/`visual_operator` Indent/Dedent arms are kept only for match exhaustiveness. 2. Dot-repeat: `VimEventType::for_dot_repeat` now includes `Indent` and `Dedent` in the repeatable `Operation` branch, so `.` replays the last indent/dedent like other operators. 3. Formatting/CI: ran `cargo fmt --all` (repo config); `cargo fmt --all -- --check` now passes on the changed app files. 4. Multi-line indent test expectations: rewrote the `>j`, `2>>`, `>G`, visual `V>`, and `Vj>` app tests to use clean, explicit input/expected strings (the prior `.unindent()`-based expectations were ambiguous/incorrect because `unindent` ignores the first line when computing common indentation). Every affected line now clearly remains indented. Tests: - crates/vim: added `enter_normal_mode_with_indent`/`enter_visual_mode_with_indent` helpers, updated the existing indent FSA tests to use them, and added regression tests for indent/dedent dot-repeat and for the disabled (terminal) no-op behavior (`>` alone, `>>`, `>j` not consuming the motion, visual `>` staying visual). - app code editor: added `test_vim_indent_dot_repeat_repeats_last_indent`. Co-Authored-By: Oz <oz-agent@warp.dev>
There was a problem hiding this comment.
Overview
Cumulative re-review (cycle 2) of Vim </> indent/dedent operators for the code editor (head d8b6913). All four cycle-1 findings are resolved and verified: the per-VimModel indent_operators_enabled flag (default false) gates </> so only CodeEditorView enables them and the terminal EditorView treats them as true no-ops (no operator-pending, no consumed keystroke); for_dot_repeat now persists Indent/Dedent so . repeats them; the ambiguous unindent-based multi-line test expectations were rewritten; and cargo fmt --all -- --check, cargo clippy -p vim --all-targets --tests -- -D warnings, and cargo nextest run -p vim (72 passed) are green in-sandbox. The indent(shift, …) mapping is correct (>→indent(false), <→indent(true), matching Tab/Shift-Tab in actions.rs), and no un-gated From<char> path can construct Indent/Dedent — </> only reach the operator mappings through the two gated arms, falling through to the catch-all no-op when disabled. All five acceptance criteria are met by the implementation and its tests.
Concerns
No code-level concerns remain. The only outstanding items are environmental, not code defects: this 3.9 GB / no-swap sandbox is OOM-killed compiling the full warp app crate, so the app-level code-editor unit tests (app/src/code/editor/view/vim_handler_tests.rs), ./script/presubmit, cargo clippy -p warp --all-targets, and the required visual proof for this user-facing change could not be captured here. This is an infrastructure gap that needs a higher-memory machine — another automated rework cycle would hit the same OOM and make no progress. Before merging, on a higher-memory machine run: cargo nextest run -p warp test_vim_, cargo clippy -p warp --all-targets --tests -- -D warnings, ./script/presubmit, and manually exercise >>, <<, >j, 2>>, >G, V>, V<, and . in the code editor with Vim mode on, confirming the terminal command input is unaffected by </>. Also confirm CI completes green on the current head — several checks (Linux/Windows/MacOS test runs, Linux/Windows Formatting+Clippy) were still pending at review time; the release-compilation (Linux/Windows/wasm), MacOS/wasm Formatting+Clippy, CodeQL, and Miscellaneous checks already passed.
Verdict
Found: 0 critical, 0 important, 0 suggestions. Prior concerns: none remain.
Approve — the code is sound and every cycle-1 finding is resolved. This approval is for code quality; the app-level tests and visual proof remain unverified pending a higher-memory machine (an environmental gap, not a code fault), and should be confirmed before merge as listed above.
Review run
https://oz.staging.warp.dev/runs/019f960c-a6c6-719d-b321-5c54e4c81ac0
acarl005
left a comment
There was a problem hiding this comment.
None of the comments you added are useful. Delete them
Co-Authored-By: Oz <oz-agent@warp.dev>
Restore the existing register comment and use VimOperator equality for the ToggleComment check.\n\nCo-Authored-By: Oz <oz-agent@warp.dev>
Use the centralized trailing-newline decision for jump-to-line selections.\n\nCo-Authored-By: Oz <oz-agent@warp.dev>
Use VimOperator::includes_trailing_newline() for all code-editor linewise motion selection paths.\n\nCo-Authored-By: Oz <oz-agent@warp.dev>
Description
Adds Vim-style indent (
>) and dedent (<) operators to the code editor only (not the terminal command input), per APP-4963. This update also addresses all review feedback from the first review cycle.crates/vim): addsVimOperator::Indent/Dedentand recognizes</>as normal-mode operators — supporting the doubled line forms (>>/<<), operator + motion, text objects, and counts (e.g.2>>,3>j,>G,>w) — and as visual-mode operators (V>,v<). Indent/dedent are now included in the.(dot-repeat) machinery, so.replays the last indent/dedent like other operators.CodeEditorView): theoperationandvisual_operatorhandlers route Indent/Dedent to the existingCodeEditorModel::indent(shift, ctx)primitive (the same one Tab/Shift-Tab use;shift=trueis dedent). Indent operators are linewise, so the linewise selection excludes the trailing newline (so the shift never advances onto an extra line) and only adjusts leading indentation; the cursor lands on the first non-whitespace of the affected line, matching existing linewise operators likegc.EditorView:</>are a true no-op here. The sharedVimFSAgates the indent/dedent operators behind a per-VimModelflag (indent_operators_enabled, default false); only the code editor enables it, so the terminal's FSA never enters operator-pending mode for</>and never consumes the following keystroke. The terminal'soperation/visual_operatorIndent/Dedent arms are retained only for match exhaustiveness.Review rework (cycle 1)
</>previously entered operator-pending in the shared FSA for every consumer, swallowing the next keystroke in the terminal before its no-op arm ran. Fixed by gating the operators on theVimModelflag so the terminal's FSA treats</>as a true no-op (fall-through), restoring the terminal's pre-feature behavior.for_dot_repeatnow persistsIndent/Dedentoperations, so.repeats them.cargo fmt --all(repo config);cargo fmt --all -- --checknow passes on the changed app files.>j,2>>,>G, visualV>, andVj>app tests with clean, explicit input/expected strings. The prior.unindent()-based expectations were ambiguous/incorrect (unindentignores the first line when computing common indentation); every affected line now clearly remains indented.Linked Issue
Verification
Regression tests added:
crates/vim/src/vim_tests.rs):>>,<<,>j,>w,>G,2>>,3>j, visualV>/v<; indent/dedent dot-repeat (>>then.,<<then.); and disabled-operator (terminal) no-op behavior (>alone,>>,>jnot consuming the motion, visual>staying visual).app/src/code/editor/view/vim_handler_tests.rs):>>,<<, dedent at column zero (no-op), one-unit dedent, non-leading text preserved,>j,2>>,>G, visualV>/V</Vj>,uundo, and indent dot-repeat (>>then move +.).Deterministic checks run in-sandbox (this rework):
cargo nextest run -p vim→ 72 passed, 0 failed (includes the new dot-repeat and disabled-behavior regression tests).cargo clippy -p vim --all-targets --tests -- -D warnings→ clean.cargo fmt --all -- --check(repo config:imports_granularity=Module,group_imports=StdExternalCrate) → clean.Sandbox limitation (requires a higher-memory machine before merge)
This PR was prepared in a memory-constrained cloud sandbox (3.9 GB RAM, no swap). The full
warp(app) crate could not be compiled here —cargo check -p warp --lib -j 1(and the same withCARGO_PROFILE_DEV_DEBUG=0) is OOM-killed (SIGKILL) by the kernel duringrustcon the app lib, identical to the prior cycle. As a result, the following were not run in-sandbox and are NOT claimed to pass:app/src/code/editor/view/vim_handler_tests.rs(including the new dot-repeat test and the corrected multi-line indent expectations)../script/presubmit(which requires the app crate) andcargo clippy -p warp --all-targets.Before merging, please run on a higher-memory machine:
cargo nextest run -p warp test_vim_(the code-editor Vim tests, includingtest_vim_indent_dot_repeat_repeats_last_indentand the corrected>j/2>>/>G/V>/Vj>expectations).cargo clippy -p warp --all-targets --tests -- -D warningsand./script/presubmit.>>,<<,>j,2>>,>G,V>,V<, and.(dot-repeat) in the code editor with Vim mode on, and confirm the terminal command input is unaffected by</>.The editor wiring mirrors the existing, proven
gc/ToggleComment operator (sameselection_change+ primitive-call + cursor-placement shape), and the app diff was self-reviewed for type/exhaustiveness correctness.Screenshots / Videos
Outstanding — see the sandbox limitation note above (the GUI cannot be built/run in this 3.9 GB sandbox).
Agent Mode
Originating thread: https://linear.app/warpdotdev/issue/APP-4963/implement-vim-indent-operators-and-in-the-code-editor
Conversation: https://staging.warp.dev/conversation/1ff09567-30d8-497a-b15c-ce10d3a93c4b
Run: https://oz.staging.warp.dev/runs/019f95dd-e7ec-7af8-a7a9-31b41b29ce67
This PR was generated with Oz.