From d498eedb93428df02a80ee23744c3c1261f9d4d3 Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Tue, 23 Jun 2026 12:19:40 +0200 Subject: [PATCH] refactor(diff): rename diff_opts.layout "inline" to "unified" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shipped `layout = "inline"` renders a unified diff in a separate vsplit pane, not a true in-place virtual-text overlay. Renaming it to "unified" frees the "inline" name for a future real in-place overlay and avoids a breaking rename after release (flagged by @wookayin on #195). The value was added in #195 and is queued for v0.4.0 (release-please breaking change for any released version. "inline" is now rejected by config validation (no deprecated alias) so the name is cleanly reserved; the validation error names "unified" to guide anyone tracking main. Internal implementation names are intentionally left unchanged — they describe the inline-style rendering, not the layout value: - module lua/claudecode/diff_inline.lua and its functions - the claudecode_inline_diff buffer variable - the ClaudeCodeInlineDiff{Add,Delete,AddSign,DeleteSign} highlight groups The user-facing buffer name is updated from "(inline diff)" to "(unified diff)". Refs #293, #195, #82 Change-Id: I66e00ac960ee3de13ffa135b32dcba0cd171c793 Signed-off-by: Thomas Kosiewski Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 1 + README.md | 4 ++-- lua/claudecode/config.lua | 4 ++-- lua/claudecode/diff.lua | 16 ++++++++-------- lua/claudecode/diff_inline.lua | 6 +++--- lua/claudecode/types.lua | 2 +- tests/unit/diff_inline_spec.lua | 34 +++++++++++++++++++++++++++++---- 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27032f9a..796f6da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `:ClaudeCodeCloseAllDiffs` command to close pending Claude diffs at once (e.g. proposals orphaned by resolving them via Claude remote control). Diffs you have already accepted but whose file has not been written yet are left intact so saved edits are never discarded. ([#248](https://github.com/coder/claudecode.nvim/issues/248)) - `:ClaudeCodeSendText {text}` command (and `require("claudecode.terminal").send_to_terminal(text, opts)` function) to send arbitrary text to the open Claude terminal as if typed at the prompt, submitting it by default. `:ClaudeCodeSendText!` inserts the text without submitting. Handy for scripting and keymaps; multi-line text is sent via bracketed paste. Works with the in-editor `native`/`snacks` providers only — `external`/`none` run Claude outside Neovim, where there is no pane to write to. ([#197](https://github.com/coder/claudecode.nvim/issues/197)) - `terminal.auto_insert` option (default `true`) controlling whether the Claude terminal auto-enters insert/terminal mode when its window gains focus. With the default Snacks provider, switching back into the terminal window (e.g. `l`) previously re-entered terminal mode and jumped to the bottom prompt, discarding your Normal-mode scroll/reading position; set `auto_insert = false` to stay in Normal mode and preserve the scroll position (press `i` to type). Applies to the `native` and `snacks` providers and the new-tab diff terminal. ([#232](https://github.com/coder/claudecode.nvim/issues/232), [#145](https://github.com/coder/claudecode.nvim/issues/145)) +- `diff_opts.layout = "unified"`: a unified diff rendered in a single buffer with deleted (red/strikethrough) and added (green) lines interleaved, as a compact alternative to the two-pane `"vertical"`/`"horizontal"` layouts. Requires Neovim >= 0.9.0; the `ClaudeCodeInlineDiffAdd`/`Delete`/`AddSign`/`DeleteSign` highlight groups are customizable. ([#82](https://github.com/coder/claudecode.nvim/issues/82), [#195](https://github.com/coder/claudecode.nvim/pull/195), [#293](https://github.com/coder/claudecode.nvim/issues/293)) ### Bug Fixes diff --git a/README.md b/README.md index ff161755..4e3f10f2 100644 --- a/README.md +++ b/README.md @@ -376,8 +376,8 @@ For deep technical details, see [ARCHITECTURE.md](./ARCHITECTURE.md). -- Diff Integration diff_opts = { - layout = "vertical", -- "vertical" (default), "horizontal", or "inline" - -- "inline": VS Code-style unified diff in a single buffer with deleted + layout = "vertical", -- "vertical" (default), "horizontal", or "unified" + -- "unified": VS Code-style unified diff in a single buffer with deleted -- (red/strikethrough) and added (green) lines interleaved. Requires -- Neovim >= 0.9.0. Highlight groups are customizable: ClaudeCodeInlineDiffAdd, -- ClaudeCodeInlineDiffDelete, ClaudeCodeInlineDiffAddSign, ClaudeCodeInlineDiffDeleteSign. diff --git a/lua/claudecode/config.lua b/lua/claudecode/config.lua index de0c1626..42fe7131 100644 --- a/lua/claudecode/config.lua +++ b/lua/claudecode/config.lua @@ -132,8 +132,8 @@ function M.validate(config) assert( config.diff_opts.layout == "vertical" or config.diff_opts.layout == "horizontal" - or config.diff_opts.layout == "inline", - "diff_opts.layout must be 'vertical', 'horizontal', or 'inline'" + or config.diff_opts.layout == "unified", + "diff_opts.layout must be 'vertical', 'horizontal', or 'unified'" ) end if config.diff_opts.open_in_new_tab ~= nil then diff --git a/lua/claudecode/diff.lua b/lua/claudecode/diff.lua index a719b8d3..4708ee59 100644 --- a/lua/claudecode/diff.lua +++ b/lua/claudecode/diff.lua @@ -838,8 +838,8 @@ function M._resolve_diff_as_saved(tab_name, buffer_id) return end - -- Dispatch to inline diff handler - if diff_data.layout == "inline" then + -- Dispatch to unified diff handler + if diff_data.layout == "unified" then local inline = require("claudecode.diff_inline") inline.resolve_inline_as_saved(tab_name, diff_data) return @@ -932,8 +932,8 @@ function M._resolve_diff_as_rejected(tab_name) return end - -- Dispatch to inline diff handler - if diff_data.layout == "inline" then + -- Dispatch to unified diff handler + if diff_data.layout == "unified" then local inline = require("claudecode.diff_inline") inline.resolve_inline_as_rejected(tab_name, diff_data) return @@ -1166,8 +1166,8 @@ function M._cleanup_diff_state(tab_name, reason) return end - -- Dispatch to inline diff handler - if diff_data.layout == "inline" then + -- Dispatch to unified diff handler + if diff_data.layout == "unified" then local inline = require("claudecode.diff_inline") inline.cleanup_inline_diff(tab_name, diff_data) active_diffs[tab_name] = nil @@ -1315,8 +1315,8 @@ function M._setup_blocking_diff(params, resolution_callback) end end - -- Dispatch to inline diff if configured - if config and config.diff_opts and config.diff_opts.layout == "inline" then + -- Dispatch to unified diff if configured + if config and config.diff_opts and config.diff_opts.layout == "unified" then local inline = require("claudecode.diff_inline") inline.setup_inline_diff(params, resolution_callback, config) return diff --git a/lua/claudecode/diff_inline.lua b/lua/claudecode/diff_inline.lua index 3a9a8278..9a8919f0 100644 --- a/lua/claudecode/diff_inline.lua +++ b/lua/claudecode/diff_inline.lua @@ -197,7 +197,7 @@ function M.setup_inline_diff(params, resolution_callback, config) error({ code = -32000, message = "Buffer creation failed", data = "Could not create inline diff buffer" }) end - pcall(vim.api.nvim_buf_set_name, buf, tab_name .. " (inline diff)") + pcall(vim.api.nvim_buf_set_name, buf, tab_name .. " (unified diff)") vim.api.nvim_buf_set_option(buf, "buftype", "acwrite") vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe") @@ -330,7 +330,7 @@ function M.setup_inline_diff(params, resolution_callback, config) }) end - -- Register state with layout = "inline" + -- Register state with layout = "unified" diff._register_diff_state(tab_name, { old_file_path = params.old_file_path, new_file_path = params.new_file_path, @@ -345,7 +345,7 @@ function M.setup_inline_diff(params, resolution_callback, config) status = "pending", resolution_callback = resolution_callback, result_content = nil, - layout = "inline", + layout = "unified", -- Track the originating MCP client so close_diffs_for_client can tear this -- diff down if that client disconnects (parity with the native path, #261). client_id = params.client_id, diff --git a/lua/claudecode/types.lua b/lua/claudecode/types.lua index 17c5620a..26e0a6a0 100644 --- a/lua/claudecode/types.lua +++ b/lua/claudecode/types.lua @@ -31,7 +31,7 @@ ---@alias ClaudeCodeLogLevel "trace"|"debug"|"info"|"warn"|"error" -- Diff layout type alias ----@alias ClaudeCodeDiffLayout "vertical"|"horizontal"|"inline" +---@alias ClaudeCodeDiffLayout "vertical"|"horizontal"|"unified" -- Behavior when rejecting new-file diffs ---@alias ClaudeCodeNewFileRejectBehavior "keep_empty"|"close_window" diff --git a/tests/unit/diff_inline_spec.lua b/tests/unit/diff_inline_spec.lua index c77db24d..957f5e98 100644 --- a/tests/unit/diff_inline_spec.lua +++ b/tests/unit/diff_inline_spec.lua @@ -327,7 +327,7 @@ describe("Inline diff module", function() end) describe("config validation", function() - it("should accept layout = 'inline'", function() + it("should accept layout = 'unified'", function() package.loaded["claudecode.config"] = nil package.loaded["claudecode.terminal"] = nil -- Stub terminal module with defaults @@ -347,8 +347,8 @@ describe("Inline diff module", function() ensure_visible = function() end, } local config = require("claudecode.config") - local applied = config.apply({ diff_opts = { layout = "inline" } }) - assert.are.equal("inline", applied.diff_opts.layout) + local applied = config.apply({ diff_opts = { layout = "unified" } }) + assert.are.equal("unified", applied.diff_opts.layout) end) it("should reject invalid layout values", function() @@ -374,7 +374,33 @@ describe("Inline diff module", function() config.apply({ diff_opts = { layout = "invalid" } }) end) assert.is_false(success) - assert_contains(tostring(err), "inline") + assert_contains(tostring(err), "'unified'") + end) + + it("should reject the former layout = 'inline' (renamed to 'unified')", function() + package.loaded["claudecode.config"] = nil + package.loaded["claudecode.terminal"] = nil + package.loaded["claudecode.terminal"] = { + defaults = { + split_side = "right", + split_width_percentage = 0.30, + provider = "auto", + show_native_term_exit_tip = true, + auto_close = true, + env = {}, + snacks_win_opts = {}, + }, + get_active_terminal_bufnr = function() + return nil + end, + ensure_visible = function() end, + } + local config = require("claudecode.config") + local success, err = pcall(function() + config.apply({ diff_opts = { layout = "inline" } }) + end) + assert.is_false(success) + assert_contains(tostring(err), "'unified'") end) end)