Skip to content

Commit 095bff6

Browse files
committed
refactor: enhance logging, improve temp file handling, clean up comments
Change-Id: I28d3cce0c41312fa18c25645194461cc9614bf5d Signed-off-by: Thomas Kosiewski <[email protected]>
1 parent c0b9b32 commit 095bff6

File tree

16 files changed

+807
-887
lines changed

16 files changed

+807
-887
lines changed

lua/claudecode/diff.lua

Lines changed: 31 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
-- Manages different diff providers (native Neovim and diffview.nvim) with automatic detection and fallback.
33
local M = {}
44

5-
-- Internal state with safe defaults
65
local diff_config = {
76
diff_provider = "auto",
87
diff_opts = {
@@ -29,7 +28,7 @@ function M.get_current_provider()
2928
if M.is_diffview_available() then
3029
return "diffview"
3130
else
32-
vim.notify("diffview.nvim not found, falling back to native diff", vim.log.levels.WARN)
31+
vim.notify("diffview.nvim not found, falling back to native diff", vim.log.levels.WARN) -- Explain fallback
3332
return "native"
3433
end
3534
else
@@ -40,7 +39,6 @@ end
4039
--- Setup the diff module with configuration
4140
-- @param user_diff_config table|nil User configuration for diff functionality
4241
function M.setup(user_diff_config)
43-
-- Simple setup without config module dependency for now
4442
if user_diff_config then
4543
diff_config = {
4644
diff_provider = user_diff_config.diff_provider or diff_config.diff_provider,
@@ -70,13 +68,35 @@ end
7068
-- @param filename string Base filename for the temporary file
7169
-- @return string|nil, string|nil The temporary file path and error message
7270
function M._create_temp_file(content, filename)
73-
local tmp_dir = vim.fn.tempname() .. "_claudecode_diff"
74-
local ok, err = pcall(vim.fn.mkdir, tmp_dir, "p")
75-
if not ok then
76-
return nil, "Failed to create temporary directory: " .. tostring(err)
71+
local base_dir_cache = vim.fn.stdpath("cache") .. "/claudecode_diffs"
72+
local mkdir_ok_cache, mkdir_err_cache = pcall(vim.fn.mkdir, base_dir_cache, "p")
73+
74+
local final_base_dir
75+
if mkdir_ok_cache then
76+
final_base_dir = base_dir_cache
77+
else
78+
local base_dir_temp = vim.fn.stdpath("temp") .. "/claudecode_diffs"
79+
local mkdir_ok_temp, mkdir_err_temp = pcall(vim.fn.mkdir, base_dir_temp, "p")
80+
if not mkdir_ok_temp then
81+
local err_to_report = mkdir_err_temp or mkdir_err_cache or "unknown error creating base temp dir"
82+
return nil, "Failed to create base temporary directory: " .. tostring(err_to_report)
83+
end
84+
final_base_dir = base_dir_temp
85+
end
86+
87+
local session_id_base = vim.fn.fnamemodify(vim.fn.tempname(), ":t") .. "_" .. tostring(os.time()) .. "_" .. tostring(math.random(1000, 9999))
88+
local session_id = session_id_base:gsub("[^A-Za-z0-9_-]", "")
89+
if session_id == "" then -- Fallback if all characters were problematic, ensuring a directory can be made.
90+
session_id = "claudecode_session"
7791
end
7892

79-
local tmp_file = tmp_dir .. "/" .. filename
93+
local tmp_session_dir = final_base_dir .. "/" .. session_id
94+
local mkdir_session_ok, mkdir_session_err = pcall(vim.fn.mkdir, tmp_session_dir, "p")
95+
if not mkdir_session_ok then
96+
return nil, "Failed to create temporary session directory: " .. tostring(mkdir_session_err)
97+
end
98+
99+
local tmp_file = tmp_session_dir .. "/" .. filename
80100
local file = io.open(tmp_file, "w")
81101
if not file then
82102
return nil, "Failed to create temporary file: " .. tmp_file
@@ -105,82 +125,40 @@ end
105125
-- @param tab_name string Name for the diff tab/view
106126
-- @return table Result with provider, tab_name, and success status
107127
function M._open_native_diff(old_file_path, new_file_path, new_file_contents, tab_name)
108-
-- Create temporary file for new content
109128
local new_filename = vim.fn.fnamemodify(new_file_path, ":t") .. ".new"
110129
local tmp_file, err = M._create_temp_file(new_file_contents, new_filename)
111130
if not tmp_file then
112131
return { provider = "native", tab_name = tab_name, success = false, error = err }
113132
end
114133

115-
-- Choose whether to open in current tab or new tab based on configuration
116134
if diff_config and diff_config.diff_opts and diff_config.diff_opts.open_in_current_tab then
117-
-- Save current buffer info for restoration later if needed
118135
local original_buf = vim.api.nvim_get_current_buf()
119-
local _ = vim.api.nvim_buf_get_name(original_buf) -- unused for now but may be needed later
120-
121-
-- Open the original file in the current buffer
136+
local _ = vim.api.nvim_buf_get_name(original_buf) -- Storing original buffer name, though not currently used, might be useful for future enhancements.
122137
vim.cmd("edit " .. vim.fn.fnameescape(old_file_path))
123138
else
124-
-- Create a new tab for the diff (old behavior)
125139
vim.cmd("tabnew")
126-
127-
-- Set the tab name
128140
vim.api.nvim_buf_set_name(0, tab_name)
129-
130-
-- Open the original file
131141
vim.cmd("edit " .. vim.fn.fnameescape(old_file_path))
132142
end
133143

134-
-- Enable diff mode
135144
vim.cmd("diffthis")
136145

137-
-- Create split based on configuration
138146
if diff_config and diff_config.diff_opts and diff_config.diff_opts.vertical_split then
139147
vim.cmd("vertical split")
140148
else
141149
vim.cmd("split")
142150
end
143151

144-
-- Open the temporary file with new content
145152
vim.cmd("edit " .. vim.fn.fnameescape(tmp_file))
146153
vim.api.nvim_buf_set_name(0, new_file_path .. " (New)")
147154

148-
-- Configure the new content buffer
149155
local new_buf = vim.api.nvim_get_current_buf()
150156
vim.api.nvim_set_option_value("buftype", "nofile", { buf = new_buf })
151157
vim.api.nvim_set_option_value("bufhidden", "wipe", { buf = new_buf })
152158
vim.api.nvim_set_option_value("swapfile", false, { buf = new_buf })
153159

154-
-- Enable diff mode
155160
vim.cmd("diffthis")
156161

157-
-- Set up buffer-local keymaps for diff navigation and exit (only in current tab mode)
158-
if diff_config and diff_config.diff_opts and diff_config.diff_opts.open_in_current_tab then
159-
local function setup_diff_keymaps()
160-
-- Map <leader>dq to quit diff mode
161-
vim.keymap.set("n", "<leader>dq", function()
162-
vim.cmd("diffoff!")
163-
vim.cmd("wincmd o") -- Close other windows (the diff split)
164-
M._cleanup_temp_file(tmp_file)
165-
vim.notify("Diff mode exited", vim.log.levels.INFO)
166-
end, { buffer = true, desc = "Exit diff mode" })
167-
168-
-- Map <leader>da to accept all changes (replace current buffer with new content)
169-
vim.keymap.set("n", "<leader>da", function()
170-
vim.cmd("diffoff!")
171-
vim.cmd("wincmd o") -- Close other windows
172-
-- Load the new content into the current buffer
173-
local lines = vim.split(new_file_contents, "\n")
174-
vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
175-
M._cleanup_temp_file(tmp_file)
176-
vim.notify("All changes accepted", vim.log.levels.INFO)
177-
end, { buffer = true, desc = "Accept all changes" })
178-
end
179-
180-
setup_diff_keymaps()
181-
end
182-
183-
-- Set up autocmd for cleanup when buffers are deleted
184162
local cleanup_group = vim.api.nvim_create_augroup("ClaudeCodeDiffCleanup", { clear = false })
185163
vim.api.nvim_create_autocmd({ "BufDelete", "BufWipeout" }, {
186164
group = cleanup_group,
@@ -191,18 +169,6 @@ function M._open_native_diff(old_file_path, new_file_path, new_file_contents, ta
191169
once = true,
192170
})
193171

194-
-- Show diff info with helpful keymaps
195-
vim.defer_fn(function()
196-
local message
197-
if diff_config and diff_config.diff_opts and diff_config.diff_opts.open_in_current_tab then
198-
message =
199-
string.format("Diff: %s | Use ]c/[c to navigate, <leader>da to accept all, <leader>dq to exit", tab_name)
200-
else
201-
message = string.format("Diff: %s | Use ]c/[c to navigate changes, close tab when done", tab_name)
202-
end
203-
vim.notify(message, vim.log.levels.INFO)
204-
end, 100)
205-
206172
return {
207173
provider = "native",
208174
tab_name = tab_name,
@@ -218,8 +184,8 @@ end
218184
-- @param tab_name string Name for the diff tab/view
219185
-- @return table Result with provider, tab_name, and success status
220186
function M._open_diffview_diff(old_file_path, new_file_path, new_file_contents, tab_name)
221-
-- For now, fall back to native implementation
222-
-- This will be properly implemented in Phase 4
187+
-- TODO: Implement full diffview.nvim integration (Phase 4)
188+
-- For now, fall back to native implementation. This notification informs the user about the current behavior.
223189
vim.notify("diffview.nvim integration not yet implemented, using native diff", vim.log.levels.INFO)
224190
return M._open_native_diff(old_file_path, new_file_path, new_file_contents, tab_name)
225191
end

lua/claudecode/init.lua

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ M.state = {
7575
function M.setup(opts)
7676
opts = opts or {}
7777

78-
-- Separate terminal config from main config
7978
local terminal_opts = nil
8079
if opts.terminal then
8180
terminal_opts = opts.terminal
@@ -84,23 +83,26 @@ function M.setup(opts)
8483

8584
local config = require("claudecode.config")
8685
M.state.config = config.apply(opts)
87-
vim.g.claudecode_user_config = vim.deepcopy(M.state.config) -- Make config globally accessible
88-
89-
if terminal_opts then
90-
local terminal_setup_ok, terminal_module = pcall(require, "claudecode.terminal")
91-
if terminal_setup_ok then
92-
terminal_module.setup(terminal_opts)
93-
else
94-
vim.notify("Failed to load claudecode.terminal module for setup.", vim.log.levels.ERROR)
95-
end
86+
-- vim.g.claudecode_user_config is no longer needed as config values are passed directly.
87+
88+
local logger = require("claudecode.logger")
89+
logger.setup(M.state.config)
90+
91+
-- Setup terminal module: always try to call setup to pass terminal_cmd,
92+
-- even if terminal_opts (for split_side etc.) are not provided.
93+
local terminal_setup_ok, terminal_module = pcall(require, "claudecode.terminal")
94+
if terminal_setup_ok then
95+
-- terminal_opts might be nil if user only configured top-level terminal_cmd
96+
-- and not specific terminal appearance options.
97+
-- The terminal.setup function handles nil for its first argument.
98+
terminal_module.setup(terminal_opts, M.state.config.terminal_cmd)
99+
else
100+
logger.error("init", "Failed to load claudecode.terminal module for setup.")
96101
end
97102

98-
-- Setup diff module with configuration
99103
local diff = require("claudecode.diff")
100104
diff.setup(M.state.config)
101105

102-
-- TODO: Set up logger with configured log level
103-
104106
if M.state.config.auto_start then
105107
M.start(false) -- Suppress notification on auto-start
106108
end
@@ -150,7 +152,6 @@ function M.start(show_startup_notification)
150152
local lock_success, lock_result = lockfile.create(M.state.port)
151153

152154
if not lock_success then
153-
-- Stop server if lock file creation fails
154155
server.stop()
155156
M.state.server = nil
156157
M.state.port = nil
@@ -161,7 +162,7 @@ function M.start(show_startup_notification)
161162

162163
if M.state.config.track_selection then
163164
local selection = require("claudecode.selection")
164-
selection.enable(server)
165+
selection.enable(server, M.state.config.visual_demotion_delay_ms)
165166
end
166167

167168
if show_startup_notification then
@@ -211,6 +212,8 @@ end
211212
--- Set up user commands
212213
---@private
213214
function M._create_commands()
215+
local logger = require("claudecode.logger")
216+
214217
vim.api.nvim_create_user_command("ClaudeCodeStart", function()
215218
M.start()
216219
end, {
@@ -235,19 +238,73 @@ function M._create_commands()
235238

236239
vim.api.nvim_create_user_command("ClaudeCodeSend", function(opts)
237240
if not M.state.server then
241+
logger.error("command", "ClaudeCodeSend: Claude Code integration is not running.")
238242
vim.notify("Claude Code integration is not running", vim.log.levels.ERROR)
239243
return
240244
end
245+
logger.debug(
246+
"command",
247+
"ClaudeCodeSend (new logic) invoked. Mode: "
248+
.. vim.fn.mode(1)
249+
.. ", Neovim's reported range: "
250+
.. tostring(opts and opts.range)
251+
)
252+
-- We now ignore opts.range and rely on the selection module's state,
253+
-- as opts.range was found to be 0 even when in visual mode for <cmd> mappings.
241254

242-
-- The selection.send_at_mention_for_visual_selection() function itself
243-
-- will check for a valid visual selection and show an error if none exists.
244-
-- This simplifies handling calls from keymaps vs. direct :'<,'>Cmd invocations.
245-
local selection_module = require("claudecode.selection")
246-
selection_module.send_at_mention_for_visual_selection()
255+
if not M.state.server then
256+
logger.error("command", "ClaudeCodeSend: Claude Code integration is not running.")
257+
vim.notify("Claude Code integration is not running", vim.log.levels.ERROR, { title = "ClaudeCode Error" })
258+
return
259+
end
260+
261+
local selection_module_ok, selection_module = pcall(require, "claudecode.selection")
262+
if selection_module_ok then
263+
local sent_successfully = selection_module.send_at_mention_for_visual_selection()
264+
if sent_successfully then
265+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Esc>", true, false, true), "n", false)
266+
logger.debug("command", "ClaudeCodeSend: Exited visual mode after successful send.")
267+
end
268+
else
269+
logger.error("command", "ClaudeCodeSend: Failed to load selection module.")
270+
vim.notify("Failed to send selection: selection module not loaded.", vim.log.levels.ERROR)
271+
end
247272
end, {
248273
desc = "Send current visual selection as an at_mention to Claude Code",
249274
range = true, -- Important: This makes the command expect a range (visual selection)
250275
})
276+
277+
local terminal_ok, terminal = pcall(require, "claudecode.terminal")
278+
if terminal_ok then
279+
vim.api.nvim_create_user_command("ClaudeCode", function(_opts)
280+
local current_mode = vim.fn.mode()
281+
if current_mode == "v" or current_mode == "V" or current_mode == "\22" then -- \22 is CTRL-V (blockwise visual mode)
282+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Esc>", true, false, true), "n", false)
283+
end
284+
terminal.toggle({}) -- `opts.fargs` can be used for future enhancements.
285+
end, {
286+
nargs = "?",
287+
desc = "Toggle the Claude Code terminal window",
288+
})
289+
290+
vim.api.nvim_create_user_command("ClaudeCodeOpen", function(_opts)
291+
terminal.open({})
292+
end, {
293+
nargs = "?",
294+
desc = "Open the Claude Code terminal window",
295+
})
296+
297+
vim.api.nvim_create_user_command("ClaudeCodeClose", function()
298+
terminal.close()
299+
end, {
300+
desc = "Close the Claude Code terminal window",
301+
})
302+
else
303+
logger.error(
304+
"init",
305+
"Terminal module not found. Terminal commands (ClaudeCode, ClaudeCodeOpen, ClaudeCodeClose) not registered."
306+
)
307+
end
251308
end
252309

253310
--- Get version information

0 commit comments

Comments
 (0)