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)