claude-baseline-1752128767

This commit is contained in:
zolinthecow 2025-07-09 23:26:07 -07:00
parent 2c74a4bba7
commit 4d82324eca
3 changed files with 182 additions and 56 deletions

View File

@ -17,3 +17,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
test line added by user
TEST: This line should trigger inline diff automatically via hooks!

View File

@ -227,24 +227,38 @@ function M.test_inline_diff()
local relative_path = buf_name:gsub(git_root .. '/', '') local relative_path = buf_name:gsub(git_root .. '/', '')
vim.notify('Testing inline diff for: ' .. relative_path, vim.log.levels.INFO) vim.notify('Testing inline diff for: ' .. relative_path, vim.log.levels.INFO)
-- Get baseline content -- Get baseline content - check for updated baseline first
local inline_diff = require 'nvim-claude.inline-diff'
local original_content = nil
-- Check if we have an updated baseline in memory
vim.notify('DEBUG: Checking for baseline in buffer ' .. bufnr, vim.log.levels.INFO)
vim.notify('DEBUG: Available baselines: ' .. vim.inspect(vim.tbl_keys(inline_diff.original_content)), vim.log.levels.INFO)
if inline_diff.original_content[bufnr] then
original_content = inline_diff.original_content[bufnr]
vim.notify('Using updated baseline from memory (length: ' .. #original_content .. ')', vim.log.levels.INFO)
else
-- Fall back to git baseline
local baseline_ref = utils.read_file '/tmp/claude-baseline-commit' or 'HEAD' local baseline_ref = utils.read_file '/tmp/claude-baseline-commit' or 'HEAD'
baseline_ref = baseline_ref:gsub('%s+', '') baseline_ref = baseline_ref:gsub('%s+', '')
local baseline_cmd = string.format('cd "%s" && git show %s:%s 2>/dev/null', git_root, baseline_ref, relative_path) local baseline_cmd = string.format('cd "%s" && git show %s:%s 2>/dev/null', git_root, baseline_ref, relative_path)
local original_content, orig_err = utils.exec(baseline_cmd) local git_err
original_content, git_err = utils.exec(baseline_cmd)
if orig_err then if git_err then
vim.notify('Failed to get baseline content: ' .. orig_err, vim.log.levels.ERROR) vim.notify('Failed to get baseline content: ' .. git_err, vim.log.levels.ERROR)
return return
end end
vim.notify('Using git baseline', vim.log.levels.INFO)
end
-- Get current content -- Get current content
local current_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) local current_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local current_content = table.concat(current_lines, '\n') local current_content = table.concat(current_lines, '\n')
-- Show inline diff -- Show inline diff
local inline_diff = require 'nvim-claude.inline-diff'
inline_diff.show_inline_diff(bufnr, original_content, current_content) inline_diff.show_inline_diff(bufnr, original_content, current_content)
end end
@ -387,6 +401,19 @@ function M.setup_commands()
desc = 'Test Claude keymap functionality', desc = 'Test Claude keymap functionality',
}) })
vim.api.nvim_create_user_command('ClaudeUpdateBaseline', function()
local bufnr = vim.api.nvim_get_current_buf()
local current_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local current_content = table.concat(current_lines, '\n')
local inline_diff = require 'nvim-claude.inline-diff'
inline_diff.original_content[bufnr] = current_content
vim.notify('Baseline updated to current buffer state', vim.log.levels.INFO)
end, {
desc = 'Update Claude baseline to current buffer state',
})
vim.api.nvim_create_user_command('ClaudeTestDiff', function() vim.api.nvim_create_user_command('ClaudeTestDiff', function()
local utils = require 'nvim-claude.utils' local utils = require 'nvim-claude.utils'
@ -494,4 +521,3 @@ function M.cleanup_old_commits()
end end
return M return M

View File

@ -118,34 +118,45 @@ function M.apply_diff_visualization(bufnr)
-- Apply highlights for each hunk -- Apply highlights for each hunk
for i, hunk in ipairs(diff_data.hunks) do for i, hunk in ipairs(diff_data.hunks) do
-- Track additions and deletions separately with proper line mapping
local current_new_line = hunk.new_start - 1 -- 0-indexed, tracks position in current buffer -- Track which lines in the current buffer correspond to additions/deletions
local current_old_line = hunk.old_start - 1 -- 0-indexed, tracks position in old content local additions = {}
local deletions = {} local deletions = {}
-- Start from the beginning of the hunk and track line numbers
local new_line_num = hunk.new_start -- 1-indexed line number in new file
local old_line_num = hunk.old_start -- 1-indexed line number in old file
for _, diff_line in ipairs(hunk.lines) do for _, diff_line in ipairs(hunk.lines) do
if diff_line:match('^%+') then if diff_line:match('^%+') then
-- This is an added line - highlight it in the current buffer -- This is an added line - it exists in the current buffer at new_line_num
if current_new_line >= 0 and current_new_line < #buf_lines then table.insert(additions, new_line_num - 1) -- Convert to 0-indexed for extmarks
vim.api.nvim_buf_set_extmark(bufnr, ns_id, current_new_line, 0, { new_line_num = new_line_num + 1
line_hl_group = 'DiffAdd', -- Don't advance old_line_num for additions
id = 4000 + i * 1000 + current_new_line
})
end
current_new_line = current_new_line + 1
-- Don't advance old_line for additions
elseif diff_line:match('^%-') then elseif diff_line:match('^%-') then
-- This is a deleted line - show as virtual text above current position -- This is a deleted line - show as virtual text above current position
table.insert(deletions, { table.insert(deletions, {
line = current_new_line, -- Show deletion above current position line = new_line_num - 1, -- 0-indexed, show above current position
text = diff_line:sub(2), text = diff_line:sub(2),
}) })
current_old_line = current_old_line + 1 old_line_num = old_line_num + 1
-- Don't advance new_line for deletions -- Don't advance new_line_num for deletions
else elseif diff_line:match('^%s') then
-- Context line - advance both -- Context line - advance both
current_new_line = current_new_line + 1 new_line_num = new_line_num + 1
current_old_line = current_old_line + 1 old_line_num = old_line_num + 1
end
end
-- Apply highlighting for additions
for _, line_idx in ipairs(additions) do
if line_idx >= 0 and line_idx < #buf_lines then
vim.api.nvim_buf_set_extmark(bufnr, ns_id, line_idx, 0, {
line_hl_group = 'DiffAdd',
id = 4000 + i * 1000 + line_idx
})
else
vim.notify('Line ' .. line_idx .. ' out of range (buf has ' .. #buf_lines .. ' lines)', vim.log.levels.WARN)
end end
end end
@ -167,8 +178,16 @@ function M.apply_diff_visualization(bufnr)
end end
end end
-- Add sign in gutter for hunk -- Add sign in gutter for hunk (use first addition or deletion line)
local sign_line = hunk.new_start - 1 local sign_line = nil
if #additions > 0 then
sign_line = additions[1]
elseif #deletions > 0 then
sign_line = deletions[1].line
else
sign_line = hunk.new_start - 1
end
local sign_text = '>' local sign_text = '>'
local sign_hl = 'DiffAdd' local sign_hl = 'DiffAdd'
@ -178,7 +197,7 @@ function M.apply_diff_visualization(bufnr)
sign_hl = 'DiffChange' sign_hl = 'DiffChange'
end end
if sign_line >= 0 and sign_line < #buf_lines then if sign_line and sign_line >= 0 and sign_line < #buf_lines then
vim.api.nvim_buf_set_extmark(bufnr, ns_id, sign_line, 0, { vim.api.nvim_buf_set_extmark(bufnr, ns_id, sign_line, 0, {
sign_text = sign_text, sign_text = sign_text,
sign_hl_group = sign_hl, sign_hl_group = sign_hl,
@ -186,9 +205,9 @@ function M.apply_diff_visualization(bufnr)
}) })
end end
-- Add subtle hunk info at end of first line -- Add subtle hunk info at end of first changed line
local info_line = hunk.new_start - 1 local info_line = sign_line
if info_line >= 0 and info_line < #buf_lines then if info_line and info_line >= 0 and info_line < #buf_lines then
vim.api.nvim_buf_set_extmark(bufnr, ns_id, info_line, 0, { vim.api.nvim_buf_set_extmark(bufnr, ns_id, info_line, 0, {
virt_text = {{' [Hunk ' .. i .. '/' .. #diff_data.hunks .. ']', 'Comment'}}, virt_text = {{' [Hunk ' .. i .. '/' .. #diff_data.hunks .. ']', 'Comment'}},
virt_text_pos = 'eol', virt_text_pos = 'eol',
@ -233,8 +252,32 @@ function M.jump_to_hunk(bufnr, hunk_idx)
local hunk = diff_data.hunks[hunk_idx] local hunk = diff_data.hunks[hunk_idx]
diff_data.current_hunk = hunk_idx diff_data.current_hunk = hunk_idx
-- Move cursor to hunk start -- Find the first actual changed line (addition or deletion) in this hunk
vim.api.nvim_win_set_cursor(0, {hunk.old_start, 0}) local jump_line = nil
local new_line_num = hunk.new_start -- 1-indexed line number in new file
for _, diff_line in ipairs(hunk.lines) do
if diff_line:match('^%+') then
-- Found an addition - jump here
jump_line = new_line_num
break
elseif diff_line:match('^%-') then
-- Found a deletion - jump here
jump_line = new_line_num
break
elseif diff_line:match('^%s') then
-- Context line - advance
new_line_num = new_line_num + 1
end
end
-- Fallback to hunk start if no changes found
if not jump_line then
jump_line = hunk.new_start
end
-- Move cursor to the actual changed line
vim.api.nvim_win_set_cursor(0, {jump_line, 0})
-- Update status -- Update status
vim.notify(string.format('Hunk %d/%d', hunk_idx, #diff_data.hunks), vim.log.levels.INFO) vim.notify(string.format('Hunk %d/%d', hunk_idx, #diff_data.hunks), vim.log.levels.INFO)
@ -274,19 +317,31 @@ function M.accept_current_hunk(bufnr)
local hunk = diff_data.hunks[diff_data.current_hunk] local hunk = diff_data.hunks[diff_data.current_hunk]
if not hunk then return end if not hunk then return end
-- Apply the hunk changes -- Update the baseline to include this accepted change
M.apply_hunk_changes(bufnr, hunk) M.update_baseline_after_accept(bufnr, hunk)
-- Mark as applied -- Mark as applied (the changes are already in the buffer)
diff_data.applied_hunks[diff_data.current_hunk] = true diff_data.applied_hunks[diff_data.current_hunk] = true
-- Refresh visualization -- Remove this hunk from the diff data since it's accepted
table.remove(diff_data.hunks, diff_data.current_hunk)
-- Adjust current hunk index
if diff_data.current_hunk > #diff_data.hunks then
diff_data.current_hunk = math.max(1, #diff_data.hunks)
end
vim.notify(string.format('Accepted hunk - %d hunks remaining', #diff_data.hunks), vim.log.levels.INFO)
if #diff_data.hunks == 0 then
-- No more hunks to review
vim.notify('All hunks processed! Closing inline diff.', vim.log.levels.INFO)
M.close_inline_diff(bufnr, true) -- Keep baseline for future diffs
else
-- Refresh visualization and move to current hunk
M.apply_diff_visualization(bufnr) M.apply_diff_visualization(bufnr)
M.jump_to_hunk(bufnr, diff_data.current_hunk)
vim.notify(string.format('Accepted hunk %d/%d', diff_data.current_hunk, #diff_data.hunks), vim.log.levels.INFO) end
-- Move to next hunk
M.next_hunk(bufnr)
end end
-- Reject current hunk -- Reject current hunk
@ -300,10 +355,31 @@ function M.reject_current_hunk(bufnr)
-- Revert the hunk by applying original content -- Revert the hunk by applying original content
M.revert_hunk_changes(bufnr, hunk) M.revert_hunk_changes(bufnr, hunk)
vim.notify(string.format('Rejected hunk %d/%d', diff_data.current_hunk, #diff_data.hunks), vim.log.levels.INFO) -- Update baseline to the state after rejection
local current_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local current_content = table.concat(current_lines, '\n')
M.original_content[bufnr] = current_content
vim.notify('Baseline updated after rejection', vim.log.levels.INFO)
-- Move to next hunk -- Remove this hunk from the diff data since it's rejected
M.next_hunk(bufnr) table.remove(diff_data.hunks, diff_data.current_hunk)
-- Adjust current hunk index
if diff_data.current_hunk > #diff_data.hunks then
diff_data.current_hunk = math.max(1, #diff_data.hunks)
end
vim.notify(string.format('Rejected hunk - %d hunks remaining', #diff_data.hunks), vim.log.levels.INFO)
if #diff_data.hunks == 0 then
-- No more hunks to review
vim.notify('All hunks processed! Closing inline diff.', vim.log.levels.INFO)
M.close_inline_diff(bufnr, true) -- Keep baseline after rejection too
else
-- Refresh visualization and move to current hunk
M.apply_diff_visualization(bufnr)
M.jump_to_hunk(bufnr, diff_data.current_hunk)
end
end end
-- Revert hunk changes (restore original content) -- Revert hunk changes (restore original content)
@ -418,22 +494,26 @@ function M.reject_all_hunks(bufnr)
end end
-- Close inline diff mode -- Close inline diff mode
function M.close_inline_diff(bufnr) function M.close_inline_diff(bufnr, keep_baseline)
-- Clear highlights and virtual text -- Clear highlights and virtual text
vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1) vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
-- Remove buffer-local keymaps -- Remove buffer-local keymaps
vim.keymap.del('n', ']h', { buffer = bufnr }) pcall(vim.keymap.del, 'n', ']h', { buffer = bufnr })
vim.keymap.del('n', '[h', { buffer = bufnr }) pcall(vim.keymap.del, 'n', '[h', { buffer = bufnr })
vim.keymap.del('n', '<leader>ia', { buffer = bufnr }) pcall(vim.keymap.del, 'n', '<leader>ia', { buffer = bufnr })
vim.keymap.del('n', '<leader>ir', { buffer = bufnr }) pcall(vim.keymap.del, 'n', '<leader>ir', { buffer = bufnr })
vim.keymap.del('n', '<leader>iA', { buffer = bufnr }) pcall(vim.keymap.del, 'n', '<leader>iA', { buffer = bufnr })
vim.keymap.del('n', '<leader>iR', { buffer = bufnr }) pcall(vim.keymap.del, 'n', '<leader>iR', { buffer = bufnr })
vim.keymap.del('n', '<leader>iq', { buffer = bufnr }) pcall(vim.keymap.del, 'n', '<leader>iq', { buffer = bufnr })
-- Clean up state -- Clean up state
M.active_diffs[bufnr] = nil M.active_diffs[bufnr] = nil
-- Only clear baseline if not explicitly told to keep it
if not keep_baseline then
M.original_content[bufnr] = nil M.original_content[bufnr] = nil
end
vim.notify('Inline diff closed', vim.log.levels.INFO) vim.notify('Inline diff closed', vim.log.levels.INFO)
end end
@ -443,6 +523,22 @@ function M.has_active_diff(bufnr)
return M.active_diffs[bufnr] ~= nil return M.active_diffs[bufnr] ~= nil
end end
-- Update baseline content after accepting a hunk
function M.update_baseline_after_accept(bufnr, hunk)
-- Get current content (which now includes the accepted change)
local current_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local current_content = table.concat(current_lines, '\n')
vim.notify('DEBUG: Updating baseline for buffer ' .. bufnr, vim.log.levels.INFO)
vim.notify('DEBUG: New baseline content length: ' .. #current_content, vim.log.levels.INFO)
-- Update the stored original content to match current content
-- This way, future diffs will compare against this new baseline
M.original_content[bufnr] = current_content
vim.notify('Baseline updated to include accepted changes', vim.log.levels.INFO)
end
-- Test keymap functionality -- Test keymap functionality
function M.test_keymap() function M.test_keymap()
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()