Skip to content

feat: make diff keymaps adjustable via LazyVim spec #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ Using [lazy.nvim](https://github.com/folke/lazy.nvim):
desc = "Add file",
ft = { "NvimTree", "neo-tree", "oil" },
},
-- Diff management
{ "<leader>da", "<cmd>ClaudeCodeDiffAccept<cr>", desc = "Accept diff" },
{ "<leader>dq", "<cmd>ClaudeCodeDiffDeny<cr>", desc = "Deny diff" },
},
}
```
Expand Down Expand Up @@ -88,6 +91,8 @@ That's it! For more configuration options, see [Advanced Setup](#advanced-setup)
- `:ClaudeCodeSend` - Send current visual selection to Claude, or add files from tree explorer
- `:ClaudeCodeTreeAdd` - Add selected file(s) from tree explorer to Claude context (also available via ClaudeCodeSend)
- `:ClaudeCodeAdd <file-path> [start-line] [end-line]` - Add a specific file or directory to Claude context by path with optional line range
- `:ClaudeCodeDiffAccept` - Accept the current diff changes (equivalent to `<leader>da`)
- `:ClaudeCodeDiffDeny` - Deny/reject the current diff changes (equivalent to `<leader>dq`)

### Toggle Behavior

Expand Down Expand Up @@ -137,7 +142,7 @@ When Claude proposes changes to your files, the plugin opens a native Neovim dif
### Accepting Changes

- **`:w` (save)** - Accept the changes and apply them to your file
- **`<leader>da`** - Accept the changes using the dedicated keymap
- **`<leader>da`** - Accept the changes using the dedicated keymap (configured in LazyVim spec)

You can edit the proposed changes in the right-hand diff buffer before accepting them. This allows you to modify Claude's suggestions or make additional tweaks before applying the final version to your file.

Expand All @@ -146,7 +151,7 @@ Both methods signal Claude Code to apply the changes to your file, after which t
### Rejecting Changes

- **`:q` or `:close`** - Close the diff view to reject the changes
- **`<leader>dq`** - Reject changes using the dedicated keymap
- **`<leader>dq`** - Reject changes using the dedicated keymap (configured in LazyVim spec)
- **`:bdelete` or `:bwipeout`** - Delete the diff buffer to reject changes

When you reject changes, the diff view closes and the original file remains unchanged.
Expand All @@ -155,6 +160,28 @@ When you reject changes, the diff view closes and the original file remains unch

You can also navigate to the Claude Code terminal window and accept or reject diffs directly from within Claude's interface. This provides an alternative way to manage diffs without using the Neovim-specific keymaps.

### Customizing Diff Keymaps

The diff keymaps are configured in the LazyVim spec and can be customized by modifying the `keys` table:

```lua
{
"coder/claudecode.nvim",
config = true,
keys = {
-- ... other keymaps ...

-- Customize diff keymaps to avoid conflicts (e.g., with debugger)
{ "<leader>ya", "<cmd>ClaudeCodeDiffAccept<cr>", desc = "Accept diff" },
{ "<leader>yn", "<cmd>ClaudeCodeDiffDeny<cr>", desc = "Deny diff" },

-- Or disable them entirely by omitting them from the keys table
},
}
```

The commands `ClaudeCodeDiffAccept` and `ClaudeCodeDiffDeny` work only in diff buffers created by the plugin and will show a warning if used elsewhere.

### How It Works

The plugin uses a signal-based approach where accepting or rejecting a diff sends a message to Claude Code rather than directly modifying files. This ensures consistency and allows Claude Code to handle the actual file operations while the plugin manages the user interface and buffer reloading.
Expand Down
4 changes: 4 additions & 0 deletions dev-config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ return {
{ "<leader>ai", "<cmd>ClaudeCodeStatus<cr>", desc = "Claude Status" },
{ "<leader>aS", "<cmd>ClaudeCodeStart<cr>", desc = "Start Claude Server" },
{ "<leader>aQ", "<cmd>ClaudeCodeStop<cr>", desc = "Stop Claude Server" },

-- Diff management (buffer-local, only active in diff buffers)
{ "<leader>aa", "<cmd>ClaudeCodeDiffAccept<cr>", desc = "Accept diff" },
{ "<leader>ad", "<cmd>ClaudeCodeDiffDeny<cr>", desc = "Deny diff" },
},

-- Development configuration - all options shown with defaults commented out
Expand Down
60 changes: 43 additions & 17 deletions lua/claudecode/diff.lua
Original file line number Diff line number Diff line change
Expand Up @@ -578,23 +578,10 @@ function M._create_diff_view_from_window(target_window, old_file_path, new_buffe
vim.cmd("wincmd =")
vim.api.nvim_set_current_win(new_win)

local keymap_opts = { buffer = new_buffer, silent = true }

vim.keymap.set("n", "<leader>da", function()
M._resolve_diff_as_saved(tab_name, new_buffer)
end, keymap_opts)

vim.keymap.set("n", "<leader>dq", function()
if vim.api.nvim_win_is_valid(new_win) then
vim.api.nvim_win_close(new_win, true)
end
if vim.api.nvim_win_is_valid(target_window) then
vim.api.nvim_set_current_win(target_window)
vim.cmd("diffoff")
end

M._resolve_diff_as_rejected(tab_name)
end, keymap_opts)
-- Store diff context in buffer variables for user commands
vim.b[new_buffer].claudecode_diff_tab_name = tab_name
vim.b[new_buffer].claudecode_diff_new_win = new_win
vim.b[new_buffer].claudecode_diff_target_win = target_window

-- Return window information for later storage
return {
Expand Down Expand Up @@ -899,4 +886,43 @@ function M.reload_file_buffers_manual(file_path, original_cursor_pos)
return reload_file_buffers(file_path, original_cursor_pos)
end

--- Accept the current diff (user command version)
-- This function reads the diff context from buffer variables
function M.accept_current_diff()
local current_buffer = vim.api.nvim_get_current_buf()
local tab_name = vim.b[current_buffer].claudecode_diff_tab_name

if not tab_name then
vim.notify("No active diff found in current buffer", vim.log.levels.WARN)
return
end

M._resolve_diff_as_saved(tab_name, current_buffer)
end

--- Deny/reject the current diff (user command version)
-- This function reads the diff context from buffer variables
function M.deny_current_diff()
local current_buffer = vim.api.nvim_get_current_buf()
local tab_name = vim.b[current_buffer].claudecode_diff_tab_name
local new_win = vim.b[current_buffer].claudecode_diff_new_win
local target_window = vim.b[current_buffer].claudecode_diff_target_win

if not tab_name then
vim.notify("No active diff found in current buffer", vim.log.levels.WARN)
return
end

-- Close windows and clean up (same logic as the original keymap)
if new_win and vim.api.nvim_win_is_valid(new_win) then
vim.api.nvim_win_close(new_win, true)
end
if target_window and vim.api.nvim_win_is_valid(target_window) then
vim.api.nvim_set_current_win(target_window)
vim.cmd("diffoff")
end

M._resolve_diff_as_rejected(tab_name)
end

return M
15 changes: 15 additions & 0 deletions lua/claudecode/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,21 @@ function M._create_commands()
"Terminal module not found. Terminal commands (ClaudeCode, ClaudeCodeOpen, ClaudeCodeClose) not registered."
)
end

-- Diff management commands
vim.api.nvim_create_user_command("ClaudeCodeDiffAccept", function()
local diff = require("claudecode.diff")
diff.accept_current_diff()
end, {
desc = "Accept the current diff changes",
})

vim.api.nvim_create_user_command("ClaudeCodeDiffDeny", function()
local diff = require("claudecode.diff")
diff.deny_current_diff()
end, {
desc = "Deny/reject the current diff changes",
})
end

--- Get version information
Expand Down
19 changes: 19 additions & 0 deletions tests/mocks/vim.lua
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,25 @@ local vim = {
end,
}),

b = setmetatable({}, {
__index = function(_, bufnr)
-- Return buffer-local variables for the given buffer
if vim._buffers[bufnr] then
if not vim._buffers[bufnr].b_vars then
vim._buffers[bufnr].b_vars = {}
end
return vim._buffers[bufnr].b_vars
end
return {}
end,
__newindex = function(_, bufnr, vars)
-- Set buffer-local variables for the given buffer
if vim._buffers[bufnr] then
vim._buffers[bufnr].b_vars = vars
end
end,
}),

deepcopy = function(tbl)
if type(tbl) ~= "table" then
return tbl
Expand Down