feat(diff): add layout = "inline" for VS Code-style unified diff#195
Conversation
|
Bumping ➕ , this is a feature I'd love as well. |
|
+1 need this! |
|
+1 |
Add a new inline diff layout that shows deleted (red/strikethrough) and
added (green) lines interleaved in a single read-only buffer, similar to
VS Code's inline diff view. This complements the existing "vertical" and
"horizontal" two-panel diff layouts.
Key changes:
- New `diff_inline.lua` module with pure diff computation, rendering via
extmarks, and resolution/cleanup functions
- Dispatch logic in `diff.lua` routes to inline module when configured
- Config/types updated to accept `layout = "inline"`
- `close_all_diff_tabs` detects inline diff buffers
- Customizable highlight groups: ClaudeCodeInlineDiff{Add,Delete,*Sign}
- Requires Neovim >= 0.9.0 (for vim.diff); base plugin remains 0.8.0+
- 23 new tests covering computation, rendering, MCP responses, cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
- closeAllDiffTabs: call _resolve_diff_as_rejected before cleanup so pending coroutines are properly resumed instead of hanging on yield - closeAllDiffTabs: include resolved diffs in CLOSED_N_DIFF_TABS count - diff_inline: in open_in_new_tab mode, pick editor window from current tab via nvim_tabpage_list_wins instead of global search which could return a window from the original tab - Add tests for new-tab window selection and cleanup - Add nvim_tabpage_list_wins to vim mock Issues found by Codex 5.3 code review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
Two small refinements to the inline diff layout while rebasing onto main: - Resolve the diff function at call time as `vim.text.diff or vim.diff`. Neovim 0.12 renamed `vim.diff` to `vim.text.diff` (old name kept as a deprecated alias), so prefer the new name and have the version guard check the function actually used. Keeps `layout = "inline"` working across the supported range and forward-compatible. - Store `client_id` in the inline diff state so `close_diffs_for_client` tears the diff down if its MCP client disconnects, matching the native path (coder#261). Without it, orphaned inline diffs would linger. Change-Id: I59e3d29729e9b7d7838da25c53c23dc335f784c5 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
|
Nice feature! However it still opens a new Also let's beware of potential breaking changes in the layout options, as this sounds more like "inline_vertical" (or "vertical_inline") whereas the true overlay+extmarks mode (once we implement that) should deserve "inline". |
|
Thanks @wookayin — you're right on both counts. The shipped Since it hasn't gone out in a tagged release yet, we're renaming it now: I opened #294 to track that real overlay — the prototype direction is proposed lines as real, editable text + deleted lines as |
) ## Summary Renames the `diff_opts.layout = "inline"` option (added in coder#195, queued for v0.4.0 via release-please coder#279) to **`"unified"`**, before it ships in a tagged release. Tracked in coder#293. [@wookayin pointed out](coder#195 (comment)) that the shipped `"inline"` mode isn't a true "inline" diff in the VS Code sense — it renders a unified diff in a separate `rightbelow vsplit` pane, not an in-place virtual-text overlay in the same window. Naming it `"inline"` now would force a breaking rename later, once we add the real in-place overlay (the mode that most deserves the name `"inline"`). Renaming is free now (not yet released) and a breaking change after coder#279 merges. ## What changed - **Config value** `"inline"` → `"unified"`: validation + error message (`config.lua`), the `ClaudeCodeDiffLayout` type alias (`types.lua`), all four dispatch sites (`diff.lua`), and the stored `layout` value (`diff_inline.lua`). - **User-facing buffer name**: `<file> (inline diff)` → `<file> (unified diff)`. - **Docs**: README layout enum + label; a `CHANGELOG.md` `[Unreleased]` entry for `layout = "unified"`. - **Tests**: the accept test now expects `"unified"`; a new test asserts the former `"inline"` is rejected. ## Decisions - **No deprecated alias.** `"inline"` was never in a tagged release, so there's no backward-compat obligation, and rejecting it cleanly reserves the name for the future in-place overlay (coder#294). The validation error names `'unified'`, so anyone tracking `main` is pointed at the new value. - **Internal names kept.** The `diff_inline.lua` module, its functions, the `claudecode_inline_diff` buffer variable, and the `ClaudeCodeInlineDiff*` highlight groups are unchanged — they describe the inline-*style* rendering, not the layout value (coder#293 noted the buffer var can stay). This keeps the diff small and low-risk. - **coder#279 changelog** regenerates from commits via Communique on the next push to `main`, so the v0.4.0 entry reflects "unified" automatically; I did not hand-edit the bot branch. ## Validation - `mise run all`: treefmt clean, luacheck **0/0**, **703/703** tests pass (baseline 702 + the new rejection test). - Headless Neovim smoke test: `layout = "unified"` accepted, `"inline"` rejected (error names `'unified'`), `"vertical"` still works. The true in-place overlay (the future `"inline"`) is tracked in coder#294. Refs coder#293, coder#195, coder#82 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Thomas Kosiewski <tk@coder.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Add a new
layout = "inline"option fordiff_optsthat renders a VS Code-style unified inline diff - a single read-only buffer with deleted (red/strikethrough) and added (green) lines interleaved. This complements the existing"vertical"and"horizontal"two-panel diff layouts.Closes #82
Motivation
The existing diff layouts use Neovim's built-in
diffthisto show old and new content side by side. While effective, this uses significant screen real estate with two panels. An inline unified diff provides a more compact view that's familiar to VSCode users, showing changes in context within a single buffer.
Changes
lua/claudecode/diff_inline.lua— self-contained inline diff implementation with:vim.diff()(indices mode)+/-)diff.lua— routes to inline module whenlayout = "inline"is configured; exposes shared utilities asM._members following existing patterns"inline"as a valid layout valueclose_all_diff_tabs— detects inline diff buffers viaclaudecode_inline_diffbuffer variablevim.diffmock with LCS-based hunk computation totests/mocks/vim.luaConfiguration
Highlight groups are customizable:
Requirements
Design Decisions
Test Plan