Skip to content

Comments

feat(diff): add layout = "inline" for VS Code-style unified diff#195

Open
zhao-tong wants to merge 2 commits intocoder:mainfrom
zhao-tong:main
Open

feat(diff): add layout = "inline" for VS Code-style unified diff#195
zhao-tong wants to merge 2 commits intocoder:mainfrom
zhao-tong:main

Conversation

@zhao-tong
Copy link

@zhao-tong zhao-tong commented Feb 20, 2026

Summary

Add a new layout = "inline" option for diff_opts that 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 diffthis to 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 VS
Code users, showing changes in context within a single buffer.

Changes

  • New module lua/claudecode/diff_inline.lua — self-contained inline diff implementation with:
    • Pure diff computation via vim.diff() (indices mode)
    • Extmark-based rendering with sign column markers (+/-)
    • Resolution (accept/reject) and cleanup functions
  • Dispatch in diff.lua — routes to inline module when layout = "inline" is configured; exposes shared utilities as M._ members following existing patterns
  • Config/types — validates "inline" as a valid layout value
  • close_all_diff_tabs — detects inline diff buffers via claudecode_inline_diff buffer variable
  • Test mock — adds vim.diff mock with LCS-based hunk computation to tests/mocks/vim.lua
  • 23 new tests covering diff computation, content extraction, rendering, MCP response format, config validation, and cleanup

Configuration

require("claudecode").setup({
  diff_opts = {
    layout = "inline", -- "vertical" (default), "horizontal", or "inline"
  },
})

Highlight groups are customizable:

  • ClaudeCodeInlineDiffAdd — green background for added lines
  • ClaudeCodeInlineDiffDelete — red background + strikethrough for deleted lines
  • ClaudeCodeInlineDiffAddSign / ClaudeCodeInlineDiffDeleteSign — sign column colors

Requirements

  • layout = "inline" requires Neovim >= 0.9.0 (for vim.diff())
  • The plugin's base requirement remains Neovim >= 0.8.0; only inline layout needs 0.9+

Design Decisions

  1. Separate module rather than inlining into diff.lua — keeps the already-large file manageable; inline diff uses fundamentally different rendering (extmarks vs diffthis)
  2. layout field in diff state — enables dispatch in resolution/cleanup without re-reading config
  3. Read-only buffer — inline diff is review-only; content extraction uses saved line_types array rather than parsing buffer text
  4. Always vsplit — single buffer doesn't need horizontal/vertical choice

Test Plan

  • luacheck lua/ tests/ passes with 0 warnings / 0 errors
  • All 406 tests pass (23 new, 5 pre-existing failures unrelated to this change)
  • Manual: layout = "inline" → single-window diff with colored lines
  • Manual: Accept (aa) → file saved correctly, diff closes
  • Manual: Deny (ad) → file unchanged, diff closes
  • Manual: New file creation → all lines shown as green/added
  • Manual: layout = "vertical" still works unchanged (regression check)

zhao-tong and others added 2 commits February 20, 2026 06:25
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>
- 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>
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] Inline diff

1 participant