Skip to content

Commit 472ec4c

Browse files
committed
Merge with main
2 parents 30576eb + d73a464 commit 472ec4c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1337
-965
lines changed

.luarc.json

Lines changed: 0 additions & 19 deletions
This file was deleted.

ARCHITECTURE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ Manual testing with real Neovim configurations in the `fixtures/` directory:
245245
source fixtures/nvim-aliases.sh
246246
vv nvim-tree # Test with nvim-tree integration
247247
vv oil # Test with oil.nvim integration
248+
vv mini-files # Test with mini.files integration
248249
vv netrw # Test with built-in netrw
249-
vv mini-files # Test with built-in mini.files
250250

251251
# Each fixture provides:
252252
# - Complete Neovim configuration

CLAUDE.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ The `fixtures/` directory contains test Neovim configurations for verifying plug
5151
- `netrw` - Tests with Neovim's built-in file explorer
5252
- `nvim-tree` - Tests with nvim-tree.lua file explorer
5353
- `oil` - Tests with oil.nvim file explorer
54+
- `mini-files` - Tests with mini.files file explorer
5455

5556
**Usage**: `source fixtures/nvim-aliases.sh && vv oil` starts Neovim with oil.nvim configuration
5657

@@ -274,7 +275,32 @@ Enable detailed authentication logging by setting:
274275

275276
```lua
276277
require("claudecode").setup({
277-
log_level = "debug" -- Shows auth token generation, validation, and failures
278+
log_level = "debug", -- Shows auth token generation, validation, and failures
279+
diff_opts = {
280+
keep_terminal_focus = true, -- If true, moves focus back to terminal after diff opens
281+
},
282+
})
283+
```
284+
285+
### Configuration Options
286+
287+
#### Diff Options
288+
289+
The `diff_opts` configuration allows you to customize diff behavior:
290+
291+
- `keep_terminal_focus` (boolean, default: `false`) - When enabled, keeps focus in the Claude Code terminal when a diff opens instead of moving focus to the diff buffer. This allows you to continue using terminal keybindings like `<CR>` for accepting/rejecting diffs without accidentally triggering other mappings.
292+
293+
**Example use case**: If you frequently use `<CR>` or arrow keys in the Claude Code terminal to accept/reject diffs, enable this option to prevent focus from moving to the diff buffer where `<CR>` might trigger unintended actions.
294+
295+
```lua
296+
require("claudecode").setup({
297+
diff_opts = {
298+
keep_terminal_focus = true, -- If true, moves focus back to terminal after diff opens
299+
auto_close_on_accept = true,
300+
show_diff_stats = true,
301+
vertical_split = true,
302+
open_in_current_tab = true,
303+
},
278304
})
279305
```
280306

@@ -315,7 +341,7 @@ Log levels for authentication events:
315341
### Integration Support
316342

317343
- Terminal integration supports both snacks.nvim and native Neovim terminal
318-
- Compatible with popular file explorers (nvim-tree, oil.nvim)
344+
- Compatible with popular file explorers (nvim-tree, oil.nvim, neo-tree, mini.files)
319345
- Visual selection tracking across different selection modes
320346

321347
## Release Process

DEVELOPMENT.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ source fixtures/nvim-aliases.sh
148148
# Test with specific integration
149149
vv nvim-tree # Start Neovim with nvim-tree configuration
150150
vv oil # Start Neovim with oil.nvim configuration
151+
vv mini-files # Start Neovim with mini.files configuration
151152
vv netrw # Start Neovim with built-in netrw configuration
152153

153154
# List available configurations

README.md

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ When Anthropic released Claude Code, they only supported VS Code and JetBrains.
4040
"<leader>as",
4141
"<cmd>ClaudeCodeTreeAdd<cr>",
4242
desc = "Add file",
43-
ft = { "NvimTree", "neo-tree", "oil" },
43+
ft = { "NvimTree", "neo-tree", "oil", "minifiles" },
4444
},
4545
-- Diff management
4646
{ "<leader>aa", "<cmd>ClaudeCodeDiffAccept<cr>", desc = "Accept diff" },
@@ -182,7 +182,7 @@ Configure the plugin with the detected path:
182182
1. **Launch Claude**: Run `:ClaudeCode` to open Claude in a split terminal
183183
2. **Send context**:
184184
- Select text in visual mode and use `<leader>as` to send it to Claude
185-
- In `nvim-tree`/`neo-tree`/`oil.nvim`, press `<leader>as` on a file to add it to Claude's context
185+
- In `nvim-tree`/`neo-tree`/`oil.nvim`/`mini.nvim`, press `<leader>as` on a file to add it to Claude's context
186186
3. **Let Claude work**: Claude can now:
187187
- See your current file and selections in real-time
188188
- Open files in your editor
@@ -267,6 +267,7 @@ For deep technical details, see [ARCHITECTURE.md](./ARCHITECTURE.md).
267267
auto_close_on_accept = true,
268268
vertical_split = true,
269269
open_in_current_tab = true,
270+
keep_terminal_focus = false, -- If true, moves focus back to terminal after diff opens
270271
},
271272
},
272273
keys = {
@@ -572,6 +573,87 @@ Provides convenient Claude interaction history management and access for enhance
572573

573574
> **Disclaimer**: These community extensions are developed and maintained by independent contributors. The authors and their extensions are not affiliated with Coder. Use at your own discretion and refer to their respective repositories for installation instructions, documentation, and support.
574575
576+
## Auto-Save Plugin Issues
577+
578+
Using auto-save plugins can cause diff windows opened by Claude to immediately accept without waiting for input. You can avoid this using a custom condition:
579+
580+
<details>
581+
<summary>Pocco81/auto-save.nvim</summary>
582+
583+
```lua
584+
opts = {
585+
-- ... other options
586+
condition = function(buf)
587+
local fn = vim.fn
588+
local utils = require("auto-save.utils.data")
589+
590+
-- First check the default conditions
591+
if not (fn.getbufvar(buf, "&modifiable") == 1 and utils.not_in(fn.getbufvar(buf, "&filetype"), {})) then
592+
return false
593+
end
594+
595+
-- Exclude claudecode diff buffers by buffer name patterns
596+
local bufname = vim.api.nvim_buf_get_name(buf)
597+
if bufname:match("%(proposed%)") or
598+
bufname:match("%(NEW FILE %- proposed%)") or
599+
bufname:match("%(New%)") then
600+
return false
601+
end
602+
603+
-- Exclude by buffer variables (claudecode sets these)
604+
if vim.b[buf].claudecode_diff_tab_name or
605+
vim.b[buf].claudecode_diff_new_win or
606+
vim.b[buf].claudecode_diff_target_win then
607+
return false
608+
end
609+
610+
-- Exclude by buffer type (claudecode diff buffers use "acwrite")
611+
local buftype = fn.getbufvar(buf, "&buftype")
612+
if buftype == "acwrite" then
613+
return false
614+
end
615+
616+
return true -- Safe to auto-save
617+
end,
618+
},
619+
```
620+
621+
</details>
622+
<details>
623+
<summary>okuuva/auto-save.nvim</summary>
624+
625+
```lua
626+
opts = {
627+
-- ... other options
628+
condition = function(buf)
629+
-- Exclude claudecode diff buffers by buffer name patterns
630+
local bufname = vim.api.nvim_buf_get_name(buf)
631+
if bufname:match('%(proposed%)') or bufname:match('%(NEW FILE %- proposed%)') or bufname:match('%(New%)') then
632+
return false
633+
end
634+
635+
-- Exclude by buffer variables (claudecode sets these)
636+
if
637+
vim.b[buf].claudecode_diff_tab_name
638+
or vim.b[buf].claudecode_diff_new_win
639+
or vim.b[buf].claudecode_diff_target_win
640+
then
641+
return false
642+
end
643+
644+
-- Exclude by buffer type (claudecode diff buffers use "acwrite")
645+
local buftype = vim.fn.getbufvar(buf, '&buftype')
646+
if buftype == 'acwrite' then
647+
return false
648+
end
649+
650+
return true -- Safe to auto-save
651+
end,
652+
},
653+
```
654+
655+
</details>
656+
575657
## Troubleshooting
576658

577659
- **Claude not connecting?** Check `:ClaudeCodeStatus` and verify lock file exists in `~/.claude/ide/` (or `$CLAUDE_CONFIG_DIR/ide/` if `CLAUDE_CONFIG_DIR` is set)

dev-config.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ return {
1818
{ "<leader>am", "<cmd>ClaudeCodeSelectModel<cr>", desc = "Select Claude model" },
1919

2020
-- Context sending
21-
{ "<leader>ab", "<cmd>ClaudeCodeAdd %<cr>", desc = "Add current buffer" },
21+
{ "<leader>as", "<cmd>ClaudeCodeAdd %<cr>", mode = "n", desc = "Add current buffer" },
2222
{ "<leader>as", "<cmd>ClaudeCodeSend<cr>", mode = "v", desc = "Send to Claude" },
2323
{
2424
"<leader>as",
2525
"<cmd>ClaudeCodeTreeAdd<cr>",
2626
desc = "Add file from tree",
27-
ft = { "NvimTree", "neo-tree", "oil" },
27+
ft = { "NvimTree", "neo-tree", "oil", "minifiles" },
2828
},
2929

3030
-- Development helpers
@@ -62,6 +62,7 @@ return {
6262
-- show_diff_stats = true, -- Show diff statistics
6363
-- vertical_split = true, -- Use vertical split for diffs
6464
-- open_in_current_tab = true, -- Open diffs in current tab vs new tab
65+
-- keep_terminal_focus = false, -- If true, moves focus back to terminal after diff opens
6566
-- },
6667

6768
-- Terminal Configuration

fixtures/nvim-tree/lazy-lock.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" },
3-
"nvim-tree.lua": { "branch": "master", "commit": "65bae449224b8a3bc149471b96587b23b13a9946" },
4-
"nvim-web-devicons": { "branch": "master", "commit": "4a8369f4c78ef6f6f895f0cec349e48f74330574" },
3+
"nvim-tree.lua": { "branch": "master", "commit": "0a7fcdf3f8ba208f4260988a198c77ec11748339" },
4+
"nvim-web-devicons": { "branch": "master", "commit": "3362099de3368aa620a8105b19ed04c2053e38c0" },
55
"tokyonight.nvim": { "branch": "main", "commit": "057ef5d260c1931f1dffd0f052c685dcd14100a3" }
66
}

lua/claudecode/config.lua

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
---@brief [[
12
--- Manages configuration for the Claude Code Neovim integration.
2-
-- Provides default settings, validation, and application of user-defined configurations.
3+
--- Provides default settings, validation, and application of user-defined configurations.
4+
---@brief ]]
5+
---@module 'claudecode.config'
6+
37
local M = {}
48

9+
---@type ClaudeCodeConfig
510
M.defaults = {
611
port_range = { min = 10000, max = 65535 },
712
auto_start = true,
@@ -18,20 +23,23 @@ M.defaults = {
1823
show_diff_stats = true,
1924
vertical_split = true,
2025
open_in_current_tab = true, -- Use current tab instead of creating new tab
26+
keep_terminal_focus = false, -- If true, moves focus back to terminal after diff opens
2127
},
2228
models = {
2329
{ name = "Claude Opus 4 (Latest)", value = "opus" },
2430
{ name = "Claude Sonnet 4 (Latest)", value = "sonnet" },
2531
},
2632
terminal = {
27-
external_terminal_cmd = nil, -- Command template for external terminal (e.g., "alacritty -e %s")
33+
provider_opts = {
34+
external_terminal_cmd = nil, -- Command template for external terminal (e.g., "alacritty -e %s")
35+
},
2836
},
2937
}
3038

31-
--- Validates the provided configuration table.
32-
-- @param config table The configuration table to validate.
33-
-- @return boolean true if the configuration is valid.
34-
-- @error string if any configuration option is invalid.
39+
---Validates the provided configuration table.
40+
---Throws an error if any validation fails.
41+
---@param config table The configuration table to validate.
42+
---@return boolean true if the configuration is valid.
3543
function M.validate(config)
3644
assert(
3745
type(config.port_range) == "table"
@@ -49,15 +57,24 @@ function M.validate(config)
4957

5058
-- Validate terminal config
5159
assert(type(config.terminal) == "table", "terminal must be a table")
52-
assert(
53-
config.terminal.external_terminal_cmd == nil or type(config.terminal.external_terminal_cmd) == "string",
54-
"terminal.external_terminal_cmd must be nil or a string"
55-
)
56-
if config.terminal.external_terminal_cmd and config.terminal.external_terminal_cmd ~= "" then
57-
assert(
58-
config.terminal.external_terminal_cmd:find("%%s"),
59-
"terminal.external_terminal_cmd must contain '%s' placeholder for the Claude command"
60-
)
60+
61+
-- Validate provider_opts if present
62+
if config.terminal.provider_opts then
63+
assert(type(config.terminal.provider_opts) == "table", "terminal.provider_opts must be a table")
64+
65+
-- Validate external_terminal_cmd in provider_opts
66+
if config.terminal.provider_opts.external_terminal_cmd then
67+
assert(
68+
type(config.terminal.provider_opts.external_terminal_cmd) == "string",
69+
"terminal.provider_opts.external_terminal_cmd must be a string"
70+
)
71+
if config.terminal.provider_opts.external_terminal_cmd ~= "" then
72+
assert(
73+
config.terminal.provider_opts.external_terminal_cmd:find("%%s"),
74+
"terminal.provider_opts.external_terminal_cmd must contain '%s' placeholder for the Claude command"
75+
)
76+
end
77+
end
6178
end
6279

6380
local valid_log_levels = { "trace", "debug", "info", "warn", "error" }
@@ -94,6 +111,7 @@ function M.validate(config)
94111
assert(type(config.diff_opts.show_diff_stats) == "boolean", "diff_opts.show_diff_stats must be a boolean")
95112
assert(type(config.diff_opts.vertical_split) == "boolean", "diff_opts.vertical_split must be a boolean")
96113
assert(type(config.diff_opts.open_in_current_tab) == "boolean", "diff_opts.open_in_current_tab must be a boolean")
114+
assert(type(config.diff_opts.keep_terminal_focus) == "boolean", "diff_opts.keep_terminal_focus must be a boolean")
97115

98116
-- Validate env
99117
assert(type(config.env) == "table", "env must be a table")
@@ -111,17 +129,34 @@ function M.validate(config)
111129
assert(type(model.name) == "string" and model.name ~= "", "models[" .. i .. "].name must be a non-empty string")
112130
assert(type(model.value) == "string" and model.value ~= "", "models[" .. i .. "].value must be a non-empty string")
113131
end
132+
114133
return true
115134
end
116135

117-
--- Applies user configuration on top of default settings and validates the result.
118-
-- @param user_config table|nil The user-provided configuration table.
119-
-- @return table The final, validated configuration table.
136+
---Applies user configuration on top of default settings and validates the result.
137+
---@param user_config table|nil The user-provided configuration table.
138+
---@return ClaudeCodeConfig config The final, validated configuration table.
120139
function M.apply(user_config)
121140
local config = vim.deepcopy(M.defaults)
122141

142+
-- Lazy-load terminal defaults to avoid circular dependency
143+
if config.terminal == nil then
144+
local terminal_ok, terminal_module = pcall(require, "claudecode.terminal")
145+
if terminal_ok and terminal_module.defaults then
146+
config.terminal = terminal_module.defaults
147+
end
148+
end
149+
123150
if user_config then
124-
config = vim.tbl_deep_extend("force", config, user_config)
151+
-- Use vim.tbl_deep_extend if available, otherwise simple merge
152+
if vim.tbl_deep_extend then
153+
config = vim.tbl_deep_extend("force", config, user_config)
154+
else
155+
-- Simple fallback for testing environment
156+
for k, v in pairs(user_config) do
157+
config[k] = v
158+
end
159+
end
125160
end
126161

127162
M.validate(config)

0 commit comments

Comments
 (0)