Skip to content

Commit dd81f17

Browse files
committed
feat: implement unified connection-aware @ mention system
Introduces a robust, centralized architecture for @ mention functionality that intelligently handles Claude Code connection states and provides seamless UX. Key Features: • Unified API: Single `send_at_mention()` function for all @ mention operations • Smart connection detection: Automatically detects if Claude Code is connected • Intelligent queueing: Queues @ mentions when offline, processes when connected • Automatic terminal management: Launches terminal when needed, shows when connected • Robust error handling: Proper timeouts, error propagation, and retry logic Architecture Improvements: • Centralized all @ mention logic from scattered command implementations • Applied DRY principles to eliminate code duplication • Added connection state management with configurable timeouts • Improved terminal visibility logic with connection awareness • Enhanced queue management for offline @ mentions All commands (ClaudeCodeSend, ClaudeCodeAdd, ClaudeCodeTreeAdd, selection module) now use the unified system, providing consistent behavior and better UX. Includes comprehensive test updates to support the new architecture. Change-Id: Ie4201162be96e066bbe9af4349228ef068f3a963 Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent 1410af5 commit dd81f17

14 files changed

+653
-199
lines changed

README.md

Lines changed: 121 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,26 @@ For deep technical details, see [ARCHITECTURE.md](./ARCHITECTURE.md).
214214

215215
See [DEVELOPMENT.md](./DEVELOPMENT.md) for build instructions and development guidelines. Tests can be run with `make test`.
216216

217-
## Advanced Setup
217+
## Configuration
218+
219+
### Quick Setup
220+
221+
For most users, the default configuration is sufficient:
222+
223+
```lua
224+
{
225+
"coder/claudecode.nvim",
226+
dependencies = {
227+
"folke/snacks.nvim", -- optional
228+
},
229+
config = true,
230+
}
231+
```
232+
233+
### Advanced Configuration
218234

219235
<details>
220-
<summary>Full configuration with all options</summary>
236+
<summary>Complete configuration options</summary>
221237

222238
```lua
223239
{
@@ -226,65 +242,128 @@ See [DEVELOPMENT.md](./DEVELOPMENT.md) for build instructions and development gu
226242
"folke/snacks.nvim", -- Optional for enhanced terminal
227243
},
228244
opts = {
229-
-- Server options
230-
port_range = { min = 10000, max = 65535 },
231-
auto_start = true,
232-
log_level = "info",
233-
234-
-- Terminal options
245+
-- Server Configuration
246+
port_range = { min = 10000, max = 65535 }, -- WebSocket server port range
247+
auto_start = true, -- Auto-start server on Neovim startup
248+
log_level = "info", -- "trace", "debug", "info", "warn", "error"
249+
terminal_cmd = nil, -- Custom terminal command (default: "claude")
250+
251+
-- Selection Tracking
252+
track_selection = true, -- Enable real-time selection tracking
253+
visual_demotion_delay_ms = 50, -- Delay before demoting visual selection (ms)
254+
255+
-- Connection Management
256+
connection_wait_delay = 200, -- Wait time after connection before sending queued @ mentions (ms)
257+
connection_timeout = 10000, -- Max time to wait for Claude Code connection (ms)
258+
queue_timeout = 3000, -- Max time to keep @ mentions in queue (ms)
259+
260+
-- Terminal Configuration
235261
terminal = {
236-
split_side = "right",
237-
split_width_percentage = 0.3,
238-
provider = "auto", -- "auto" (default), "snacks", or "native"
239-
auto_close = true, -- Auto-close terminal after command completion
262+
split_side = "right", -- "left" or "right"
263+
split_width_percentage = 0.30, -- Width as percentage (0.0 to 1.0)
264+
provider = "auto", -- "auto", "snacks", or "native"
265+
show_native_term_exit_tip = true, -- Show exit tip for native terminal
266+
auto_close = true, -- Auto-close terminal after command completion
240267
},
241268

242-
-- Diff options
269+
-- Diff Integration
243270
diff_opts = {
244-
auto_close_on_accept = true,
245-
vertical_split = true,
271+
auto_close_on_accept = true, -- Close diff view after accepting changes
272+
show_diff_stats = true, -- Show diff statistics
273+
vertical_split = true, -- Use vertical split for diffs
274+
open_in_current_tab = true, -- Open diffs in current tab vs new tab
246275
},
247276
},
248277
config = true,
249-
keys = {
250-
{ "<leader>a", nil, desc = "AI/Claude Code" },
251-
{ "<leader>ac", "<cmd>ClaudeCode<cr>", desc = "Toggle Claude" },
252-
{ "<leader>af", "<cmd>ClaudeCodeFocus<cr>", desc = "Focus Claude" },
253-
{ "<leader>as", "<cmd>ClaudeCodeSend<cr>", mode = "v", desc = "Send to Claude" },
254-
{
255-
"<leader>as",
256-
"<cmd>ClaudeCodeTreeAdd<cr>",
257-
desc = "Add file",
258-
ft = { "NvimTree", "neo-tree" },
259-
},
260-
{ "<leader>ao", "<cmd>ClaudeCodeOpen<cr>", desc = "Open Claude" },
261-
{ "<leader>ax", "<cmd>ClaudeCodeClose<cr>", desc = "Close Claude" },
262-
},
263278
}
264279
```
265280

266281
</details>
267282

268-
### Terminal Auto-Close Behavior
283+
### Configuration Options Explained
284+
285+
#### Server Options
286+
287+
- **`port_range`**: Port range for the WebSocket server that Claude connects to
288+
- **`auto_start`**: Whether to automatically start the integration when Neovim starts
289+
- **`terminal_cmd`**: Override the default "claude" command (useful for custom Claude installations)
290+
- **`log_level`**: Controls verbosity of plugin logs
291+
292+
#### Selection Tracking
293+
294+
- **`track_selection`**: Enables real-time selection updates sent to Claude
295+
- **`visual_demotion_delay_ms`**: Time to wait before switching from visual selection to cursor position tracking
269296

270-
The `auto_close` option controls what happens when Claude commands finish:
297+
#### Connection Management
271298

272-
**When `auto_close = true` (default):**
299+
- **`connection_wait_delay`**: Prevents overwhelming Claude with rapid @ mentions after connection
300+
- **`connection_timeout`**: How long to wait for Claude to connect before giving up
301+
- **`queue_timeout`**: How long to keep queued @ mentions before discarding them
273302

274-
- Terminal automatically closes after command completion
275-
- Error notifications shown for failed commands (non-zero exit codes)
276-
- Clean workflow for quick command execution
303+
#### Terminal Configuration
277304

278-
**When `auto_close = false`:**
305+
- **`split_side`**: Which side to open the terminal split (`"left"` or `"right"`)
306+
- **`split_width_percentage`**: Terminal width as a fraction of screen width (0.1 = 10%, 0.5 = 50%)
307+
- **`provider`**: Terminal implementation to use:
308+
- `"auto"`: Try snacks.nvim, fallback to native
309+
- `"snacks"`: Force snacks.nvim (requires folke/snacks.nvim)
310+
- `"native"`: Use built-in Neovim terminal
311+
- **`show_native_term_exit_tip`**: Show help text for exiting native terminal
312+
- **`auto_close`**: Automatically close terminal when commands finish
279313

280-
- Terminal stays open after command completion
281-
- Allows reviewing command output and any error messages
282-
- Useful for debugging or when you want to see detailed output
314+
#### Diff Options
315+
316+
- **`auto_close_on_accept`**: Close diff view after accepting changes with `:w` or `<leader>da`
317+
- **`show_diff_stats`**: Display diff statistics (lines added/removed)
318+
- **`vertical_split`**: Use vertical split layout for diffs
319+
- **`open_in_current_tab`**: Open diffs in current tab instead of creating new tabs
320+
321+
### Example Configurations
322+
323+
#### Minimal Configuration
283324

284325
```lua
285-
terminal = {
286-
provider = "snacks",
287-
auto_close = false, -- Keep terminal open to review output
326+
{
327+
"coder/claudecode.nvim",
328+
opts = {
329+
log_level = "warn", -- Reduce log verbosity
330+
auto_start = false, -- Manual startup only
331+
},
332+
}
333+
```
334+
335+
#### Power User Configuration
336+
337+
```lua
338+
{
339+
"coder/claudecode.nvim",
340+
opts = {
341+
log_level = "debug",
342+
visual_demotion_delay_ms = 100, -- Slower selection demotion
343+
connection_wait_delay = 500, -- Longer delay for @ mention batching
344+
terminal = {
345+
split_side = "left",
346+
split_width_percentage = 0.4, -- Wider terminal
347+
provider = "snacks",
348+
auto_close = false, -- Keep terminal open to review output
349+
},
350+
diff_opts = {
351+
vertical_split = false, -- Horizontal diffs
352+
open_in_current_tab = false, -- New tabs for diffs
353+
},
354+
},
355+
}
356+
```
357+
358+
#### Custom Claude Installation
359+
360+
```lua
361+
{
362+
"coder/claudecode.nvim",
363+
opts = {
364+
terminal_cmd = "/opt/claude/bin/claude", -- Custom Claude path
365+
port_range = { min = 20000, max = 25000 }, -- Different port range
366+
},
288367
}
289368
```
290369

dev-config.lua

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,42 @@ return {
3333
{ "<leader>aQ", "<cmd>ClaudeCodeStop<cr>", desc = "Stop Claude Server" },
3434
},
3535

36-
-- Development configuration
36+
-- Development configuration - all options shown with defaults commented out
3737
opts = {
38-
-- auto_start = true,
38+
-- Server Configuration
39+
-- port_range = { min = 10000, max = 65535 }, -- WebSocket server port range
40+
-- auto_start = true, -- Auto-start server on Neovim startup
41+
-- log_level = "info", -- "trace", "debug", "info", "warn", "error"
42+
-- terminal_cmd = nil, -- Custom terminal command (default: "claude")
43+
44+
-- Selection Tracking
45+
-- track_selection = true, -- Enable real-time selection tracking
46+
-- visual_demotion_delay_ms = 50, -- Delay before demoting visual selection (ms)
47+
48+
-- Connection Management
49+
-- connection_wait_delay = 200, -- Wait time after connection before sending queued @ mentions (ms)
50+
-- connection_timeout = 10000, -- Max time to wait for Claude Code connection (ms)
51+
-- queue_timeout = 3000, -- Max time to keep @ mentions in queue (ms)
52+
53+
-- Diff Integration
54+
-- diff_opts = {
55+
-- auto_close_on_accept = true, -- Close diff view after accepting changes
56+
-- show_diff_stats = true, -- Show diff statistics
57+
-- vertical_split = true, -- Use vertical split for diffs
58+
-- open_in_current_tab = true, -- Open diffs in current tab vs new tab
59+
-- },
60+
61+
-- Terminal Configuration
62+
-- terminal = {
63+
-- split_side = "right", -- "left" or "right"
64+
-- split_width_percentage = 0.30, -- Width as percentage (0.0 to 1.0)
65+
-- provider = "auto", -- "auto", "snacks", or "native"
66+
-- show_native_term_exit_tip = true, -- Show exit tip for native terminal
67+
-- auto_close = true, -- Auto-close terminal after command completion
68+
-- },
69+
70+
-- Development overrides (uncomment as needed)
3971
-- log_level = "debug",
40-
-- terminal_cmd = "claude --debug",
4172
-- terminal = {
4273
-- provider = "native",
4374
-- auto_close = false, -- Keep terminals open to see output

lua/claudecode/config.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ M.defaults = {
99
log_level = "info",
1010
track_selection = true,
1111
visual_demotion_delay_ms = 50, -- Milliseconds to wait before demoting a visual selection
12+
connection_wait_delay = 200, -- Milliseconds to wait after connection before sending queued @ mentions
13+
connection_timeout = 10000, -- Maximum time to wait for Claude Code to connect (milliseconds)
14+
queue_timeout = 5000, -- Maximum time to keep @ mentions in queue (milliseconds)
1215
diff_opts = {
1316
auto_close_on_accept = true,
1417
show_diff_stats = true,
@@ -53,6 +56,18 @@ function M.validate(config)
5356
"visual_demotion_delay_ms must be a non-negative number"
5457
)
5558

59+
assert(
60+
type(config.connection_wait_delay) == "number" and config.connection_wait_delay >= 0,
61+
"connection_wait_delay must be a non-negative number"
62+
)
63+
64+
assert(
65+
type(config.connection_timeout) == "number" and config.connection_timeout > 0,
66+
"connection_timeout must be a positive number"
67+
)
68+
69+
assert(type(config.queue_timeout) == "number" and config.queue_timeout > 0, "queue_timeout must be a positive number")
70+
5671
assert(type(config.diff_opts) == "table", "diff_opts must be a table")
5772
assert(type(config.diff_opts.auto_close_on_accept) == "boolean", "diff_opts.auto_close_on_accept must be a boolean")
5873
assert(type(config.diff_opts.show_diff_stats) == "boolean", "diff_opts.show_diff_stats must be a boolean")

0 commit comments

Comments
 (0)