Skip to content
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
28 changes: 24 additions & 4 deletions lua/CopilotChat/config/mappings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,10 @@ return {

local path = block.header.filename
local bufnr = prepare_diff_buffer(path, source)
local new_lines = diff.apply_diff(block, bufnr)
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local new_lines = diff.apply_diff(block, lines)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, new_lines)
local first, last = diff.get_diff_region(block, bufnr)
local first, last = diff.get_diff_region(block, lines)
if first and last then
select.set(bufnr, source.winnr, first, last)
select.highlight(bufnr)
Expand All @@ -192,7 +193,8 @@ return {

local path = block.header.filename
local bufnr = prepare_diff_buffer(path, source)
local first, last = diff.get_diff_region(block, bufnr)
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local first, last = diff.get_diff_region(block, lines)
if first and last and bufnr then
select.set(bufnr, source.winnr, first, last)
select.highlight(bufnr)
Expand Down Expand Up @@ -223,7 +225,25 @@ return {

local path = block.header.filename
local bufnr = prepare_diff_buffer(path, source)
local new_lines = diff.apply_diff(block, bufnr)

-- Collect all blocks for the same filename
local message = copilot.chat:get_message(constants.ROLE.ASSISTANT, true)
local blocks = {}
if message and message.section and message.section.blocks then
for _, b in ipairs(message.section.blocks) do
if b.header.filename == path then
table.insert(blocks, b)
end
end
else
blocks = { block }
end

-- Apply all diffs for the filename
local new_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
for i = #blocks, 1, -1 do
new_lines = diff.apply_diff(blocks[i], new_lines)
end

local opts = {
filetype = vim.bo[bufnr].filetype,
Expand Down
23 changes: 11 additions & 12 deletions lua/CopilotChat/utils/diff.lua
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ function M.apply_unified_diff(diff_text, original_content)
new_content = patched
applied = applied or ok
end
local original_lines = vim.split(original_content, '\n')
local new_lines = vim.split(new_content, '\n')
local original_lines = vim.split(original_content, '\n', { trimempty = true })
local new_lines = vim.split(new_content, '\n', { trimempty = true })
local first, last
local max_len = math.max(#original_lines, #new_lines)
for i = 1, max_len do
Expand All @@ -137,10 +137,9 @@ end

--- Get diff from block content and buffer lines
---@param block CopilotChat.ui.chat.Block Block containing diff info
---@param bufnr integer Buffer number
---@param lines table table of lines
---@return string diff, string content
function M.get_diff(block, bufnr)
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
function M.get_diff(block, lines)
local content = table.concat(lines, '\n')
if block.header.filetype == 'diff' then
return block.content, content
Expand All @@ -161,18 +160,18 @@ function M.get_diff(block, bufnr)
vim.diff(
table.concat(original_lines, '\n'),
table.concat(patched_lines, '\n'),
{ algorithm = 'myers', ctxlen = 20, interhunkctxlen = 50, ignore_whitespace_change = true }
{ algorithm = 'myers', ctxlen = 10, interhunkctxlen = 10, ignore_whitespace_change = true }
)
),
content
end

--- Apply a diff (unified or indices) to buffer lines
---@param block CopilotChat.ui.chat.Block Block containing diff info
---@param bufnr integer Buffer number
---@param lines table table of lines
---@return table new_lines
function M.apply_diff(block, bufnr)
local diff, content = M.get_diff(block, bufnr)
function M.apply_diff(block, lines)
local diff, content = M.get_diff(block, lines)
local new_lines, applied, _, _ = M.apply_unified_diff(diff, content)
if not applied then
log.debug('Diff for ' .. block.header.filename .. ' failed to apply cleanly for:\n' .. diff)
Expand All @@ -183,10 +182,10 @@ end

--- Get changed region for diff (unified or indices)
---@param block CopilotChat.ui.chat.Block Block containing diff info
---@param bufnr integer Buffer number
---@param lines table table of lines
---@return number? first, number? last
function M.get_diff_region(block, bufnr)
local diff, content = M.get_diff(block, bufnr)
function M.get_diff_region(block, lines)
local diff, content = M.get_diff(block, lines)
local _, _, first, last = M.apply_unified_diff(diff, content)
return first, last
end
Expand Down
2 changes: 1 addition & 1 deletion tests/diff_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ describe('CopilotChat.utils.diff', function()
local original_content = table.concat(original, '\n')
local result, applied = diff.apply_unified_diff(diff_text, original_content)
assert.is_true(applied)
assert.are.same({ '' }, result)
assert.are.same({}, result)
end)

it('applies unified diff with all lines added to empty file', function()
Expand Down
Loading