Skip to content

diff: add a true in-place "inline" overlay (virtual text) as the future layout = "inline" #294

Description

@ThomasK33

Summary

Follow-up to #293 / #195. The diff_opts.layout = "unified" option (renamed from "inline" before v0.4.0) renders a unified diff in a separate vsplit pane — a single read-only buffer with interleaved red/green lines. This issue tracks adding a true in-place inline overlay: the diff shown as virtual text layered onto the file in the same window, the way users typically picture a "VS Code-style inline" diff (cf. mini.diff, gitsigns preview, sidekick NES, Cursor inline edits).

When implemented, this mode is the one that should claim layout = "inline" — which is exactly why we reserved that name in #293.

"unified" vs the proposed "inline"

  • "unified" (shipped): single read-only buffer in a rightbelow vsplit, deleted (red/strikethrough) + added (green) lines interleaved. Compact, but it's a separate pane and not editable before accept.
  • "inline" (this issue): no extra window — proposed changes rendered in place over the real file.

Suggested approach (keeps pre-accept editability)

The unified/read-only path forfeits editing the proposal before accepting. A prototype pattern that keeps it (the codecompanion/sidekick model):

  • Proposed/added lines = real, editable buffer lines, highlighted (e.g. ClaudeCodeInlineDiffAdd) with a + sign.
  • Deleted lines = virtual text via nvim_buf_set_extmark virt_lines (strikethrough/red), so they're visible but not part of the editable content.
  • On accept, the buffer content already is the new file (deleted lines were never real text), so edits made during review are captured. On reject, clear the extmarks / restore.

A pure-Lua, zero-dependency engine (not mini.diff/diffview — see #169) keeps this aligned with the project's philosophy. Bonus: a single-buffer extmark view sets no &diff windows, which sidesteps the closeAllDiffTabs foreign-diff class (#277) and the stale-diff repaint issues (#205).

Notes

Refs #293, #195, #82

🤖 Generated with Claude Code

Activity

  1. ThomasK33 commented on Jun 25, 2026

    @ThomasK33
    MemberAuthor

    Note

    This triage report is AI-generated using Mux

    Triage report

    Classification: feature request.

    This is a valid follow-up to the current layout = "unified" work rather than a bug in the shipped unified layout. The requested behavior is a new in-place review mode: proposed content is shown in the original file window without opening an extra diff pane, while deleted old content is rendered as virtual lines/extmarks.

    What I verified

    • The current configuration accepts diff_opts.layout = "vertical", "horizontal", or "unified"; "inline" is intentionally rejected right now.
    • The existing "unified" path dispatches to lua/claudecode/diff_inline.lua, creates a scratch buffer, opens it with rightbelow vsplit, renders additions/deletions in that buffer, and sets it non-modifiable. That matches the issue's description of the current behavior and confirms that a true in-place overlay mode does not exist yet.
    • The requested design is meaningfully different from the current unified split: to preserve pre-accept editability, added/proposed lines should become real editable buffer lines, while deleted lines should be virtual-only display state such as virt_lines extmarks.
    • The zero-dependency direction fits the existing implementation style: the current unified path already uses pure Lua plus Neovim APIs rather than adding mini.diff/diffview as dependencies.

    Recommendation

    Keep this open and implement it as a new layout = "inline" feature, while preserving layout = "unified" for the existing single-buffer split view. A good implementation slice would include:

    1. Extend config/types/docs/tests to accept diff_opts.layout = "inline" with wording that clearly distinguishes it from "unified".
    2. Add a separate in-place engine instead of mutating the current read-only unified split path too much.
    3. For existing-file edits, apply the proposed buffer content into the real target buffer for review, mark added/proposed regions with highlights/signs, and render deleted old lines with virtual lines/extmarks.
    4. On accept, return the current reviewed buffer content so user edits made during review are preserved.
    5. On reject/cleanup, restore the original file content, clear extmarks/signs/autocmds, and avoid leaving modified or hidden buffers behind.
    6. Ensure the inline mode emits the same diff lifecycle events as the native layouts.
    7. Keep foreign-diff safety explicit: the new mode should not set &diff or call diffthis, so it should avoid the class of issues where Claude diffs interact with diffview/vimdiff tabs.

    Suggested acceptance criteria

    • layout = "inline" opens no extra diff window for existing-file edits.
    • Deleted lines are visible but not part of the editable buffer content.
    • Added/proposed lines are editable before accept.
    • Accept preserves any review-time edits made in the buffer.
    • Reject restores the original content and removes all inline diff UI state.
    • New-file, delete-only, mixed-change, and no-trailing-newline cases are covered by tests.
    • ClaudeCodeDiffOpened / ClaudeCodeDiffClosed fire for the inline layout with useful window/buffer metadata.
    • Existing vertical, horizontal, and unified layouts keep their current behavior.

    Adjacent finding

    While checking the lifecycle-event requirement, I found that the current layout = "unified" path appears to skip the documented ClaudeCodeDiffOpened / ClaudeCodeDiffClosed events. I created #296 as a separate, narrower bug so this feature request can stay focused on the in-place overlay.

    Validation performed

  2. added
    featureNew capability or product behavior request
    and removed
    needs-triageAwaiting maintainer triage
    triage:in-progressMux triage workspace has been launched
    on Jun 25, 2026
  3. removed
    featureNew capability or product behavior request
    on Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions