Skip to content

Commit 4759ecd

Browse files
authored
fix(core): resolve various bugs and improve robustness (#1547)
- Fix incorrect format string in RESOURCE_SHORT_FORMAT - Correct tool call key usage and merging in client - Use correct filetype to mimetype conversion in functions - Simplify and fix buffer finding/creation logic in mappings - Correct logic for loading GitHub token from gh CLI - Fix prompt selection and sticky line processing in init - Add notify.clear to setup for proper listener management - Add clear method to notify to reset listeners - Fix tool call highlighting in chat UI - Use proper BufEnter autocmd invocation in overlay - Fix diff hunk variable naming in utils.diff - Remove unnecessary quoting of grep patterns in utils.files These changes address several bugs, improve code clarity, and enhance the reliability of buffer, prompt, and notification handling. Closes #1515 Closes #1455
1 parent e168290 commit 4759ecd

10 files changed

Lines changed: 53 additions & 41 deletions

File tree

lua/CopilotChat/client.lua

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ local orderedmap = require('CopilotChat.utils.orderedmap')
6565
local stringbuffer = require('CopilotChat.utils.stringbuffer')
6666

6767
--- Constants
68-
local RESOURCE_SHORT_FORMAT = '# %s\n```%s start_line=% end_line=%s\n%s\n```'
68+
local RESOURCE_SHORT_FORMAT = '# %s\n```%s start_line=%s end_line=%s\n%s\n```'
6969
local RESOURCE_LONG_FORMAT = '# %s\n```%s path=%s start_line=%s end_line=%s\n%s\n```'
7070
local CACHE_TTL = 300 -- 5 minutes
7171

@@ -445,9 +445,10 @@ function Client:ask(opts)
445445

446446
if out.tool_calls then
447447
for _, tool_call in ipairs(out.tool_calls) do
448-
local val = tool_calls:get(tool_call.index)
448+
local key = tool_call.id or tool_call.index
449+
local val = tool_calls:get(key)
449450
if not val then
450-
tool_calls:set(tool_call.index, tool_call)
451+
tool_calls:set(key, tool_call)
451452
else
452453
val.arguments = val.arguments .. tool_call.arguments
453454
end
@@ -573,12 +574,10 @@ function Client:ask(opts)
573574
end
574575

575576
error(error_msg)
576-
return
577577
end
578578

579579
if errored then
580580
error(errored)
581-
return
582581
end
583582

584583
local response_text = response_content_buffer:tostring()

lua/CopilotChat/config/functions.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ return {
247247
{
248248
uri = 'neovim://selection',
249249
name = selection.filename,
250-
mimetype = files.mimetype_to_filetype(selection.filetype),
250+
mimetype = files.filetype_to_mimetype(selection.filetype),
251251
data = data,
252252
annotations = {
253253
start_line = selection.start_line,

lua/CopilotChat/config/mappings.lua

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,19 @@ local function prepare_diff_buffer(filename, source)
1414
filename = vim.api.nvim_buf_get_name(source.bufnr)
1515
end
1616

17+
-- Try to find matching buffer first
1718
local diff_bufnr = nil
18-
19-
-- If buffer is not found, try to load it
20-
if not diff_bufnr then
21-
-- Try to find matching buffer first
22-
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
23-
if files.filename_same(vim.api.nvim_buf_get_name(buf), filename) then
24-
diff_bufnr = buf
25-
break
26-
end
19+
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
20+
if files.filename_same(vim.api.nvim_buf_get_name(buf), filename) then
21+
diff_bufnr = buf
22+
break
2723
end
24+
end
2825

29-
-- If still not found, create a new buffer
30-
if not diff_bufnr then
31-
diff_bufnr = vim.fn.bufadd(filename)
32-
vim.fn.bufload(diff_bufnr)
33-
end
26+
-- If not found, create a new buffer
27+
if not diff_bufnr then
28+
diff_bufnr = vim.fn.bufadd(filename)
29+
vim.fn.bufload(diff_bufnr)
3430
end
3531

3632
-- If source exists, update it to point to the diff buffer
@@ -243,10 +239,10 @@ return {
243239
})
244240
end
245241
end
246-
247-
vim.fn.setqflist(items)
248-
vim.cmd('copen')
249242
end
243+
244+
vim.fn.setqflist(items)
245+
vim.cmd('copen')
250246
end,
251247
},
252248

lua/CopilotChat/config/providers.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ local function get_github_models_token(tag)
183183
end
184184

185185
-- loading token from gh cli if available
186-
if vim.fn.executable('gh') == 0 then
186+
if vim.fn.executable('gh') == 1 then
187187
local result = utils.system({ 'gh', 'auth', 'token', '-h', 'github.com' })
188188
if result and result.code == 0 and result.stdout then
189189
local gh_token = vim.trim(result.stdout)
@@ -400,9 +400,10 @@ local function prepare_responses_output(output)
400400
-- Complete output item (including tool calls)
401401
local item = output.item
402402
if item and item.type == 'function_call' then
403+
local index = output.output_index or (#tool_calls + 1)
403404
table.insert(tool_calls, {
404-
id = item.call_id or ('tooluse_' .. (#tool_calls + 1)),
405-
index = #tool_calls + 1,
405+
id = item.call_id or ('tooluse_' .. index),
406+
index = index,
406407
name = item.name or '',
407408
arguments = item.arguments or '',
408409
})

lua/CopilotChat/init.lua

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ local M = setmetatable({}, {
2222
-- Lazy initialize
2323
local initialized = rawget(t, 'initialized')
2424
if not initialized then
25-
rawset(t, 'initialized', true)
26-
rawget(t, 'setup')()
25+
local ok, err = pcall(rawget(t, 'setup'))
26+
if ok then
27+
rawset(t, 'initialized', true)
28+
else
29+
require('plenary.log').error('CopilotChat setup failed:', err)
30+
end
2731
end
2832

2933
return rawget(t, key)
@@ -54,8 +58,12 @@ local function process_sticky(prompt, config)
5458
end
5559

5660
-- Find sticky lines in new prompt to remove them
61+
in_code_block = false
5762
for i, line in ipairs(lines) do
58-
if vim.startswith(line, '> ') then
63+
if line:match('^```') then
64+
in_code_block = not in_code_block
65+
end
66+
if vim.startswith(line, '> ') and not in_code_block then
5967
table.insert(sticky_indices, i)
6068
end
6169
end
@@ -349,17 +357,17 @@ end
349357
--- Select a prompt template to use.
350358
---@param config CopilotChat.config.Shared?
351359
function M.select_prompt(config)
352-
local prompts = prompts.list_prompts()
353-
local keys = vim.tbl_keys(prompts)
360+
local prompt_list = prompts.list_prompts()
361+
local keys = vim.tbl_keys(prompt_list)
354362
table.sort(keys)
355363

356364
local choices = vim
357365
.iter(keys)
358366
:map(function(name)
359367
return {
360368
name = name,
361-
description = prompts[name].description,
362-
prompt = prompts[name].prompt,
369+
description = prompt_list[name].description,
370+
prompt = prompt_list[name].prompt,
363371
}
364372
end)
365373
:filter(function(choice)
@@ -696,6 +704,7 @@ function M.setup(config)
696704
end)
697705

698706
-- Initialize chat
707+
require('CopilotChat.notify').clear()
699708
if M.chat then
700709
M.chat:close()
701710
M.chat:delete()

lua/CopilotChat/notify.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,9 @@ function M.listen(event_name, callback)
3232
table.insert(M.listeners[event_name], callback)
3333
end
3434

35+
--- Clear all listeners
36+
function M.clear()
37+
M.listeners = {}
38+
end
39+
3540
return M

lua/CopilotChat/ui/chat.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,10 +863,10 @@ function Chat:render()
863863
-- Highlight tools in the last user message
864864
local assistant_msg = self:get_message(constants.ROLE.ASSISTANT)
865865
if assistant_msg and assistant_msg.tool_calls and #assistant_msg.tool_calls > 0 then
866-
for i, line in ipairs(utils.split_lines(message.content)) do
866+
for j, line in ipairs(utils.split_lines(message.content)) do
867867
for _, tool_call in ipairs(assistant_msg.tool_calls) do
868868
if line:match(string.format('#%s:%s', tool_call.name, vim.pesc(tool_call.id))) then
869-
local l = message.section.start_line + i
869+
local l = message.section.start_line + j
870870
vim.api.nvim_buf_add_highlight(self.bufnr, highlight_ns, 'CopilotChatAnnotationHeader', l, 0, #line)
871871
if not utils.empty(tool_call.arguments) then
872872
vim.api.nvim_buf_set_extmark(self.bufnr, highlight_ns, l, 0, {

lua/CopilotChat/ui/overlay.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ function Overlay:restore(winnr, bufnr)
128128

129129
-- Manually trigger BufEnter event as nvim_win_set_buf does not trigger it
130130
vim.schedule(function()
131-
vim.cmd(string.format('doautocmd <nomodeline> BufEnter %s', bufnr))
131+
if vim.api.nvim_buf_is_valid(bufnr) then
132+
vim.api.nvim_exec_autocmds('BufEnter', { buffer = bufnr })
133+
end
132134
end)
133135
end
134136

lua/CopilotChat/utils/diff.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,16 @@ function M.apply_unified_diff(diff_text, original_content)
161161
end
162162

163163
local new_lines = vim.split(new_content, '\n', { trimempty = true })
164-
local hunks = vim.diff(
164+
local diff_hunks = vim.diff(
165165
original_content,
166166
new_content,
167167
{ algorithm = 'myers', ctxlen = 10, interhunkctxlen = 10, ignore_whitespace_change = true, result_type = 'indices' }
168168
)
169-
if not hunks or #hunks == 0 then
169+
if not diff_hunks or #diff_hunks == 0 then
170170
return new_lines, applied, nil, nil
171171
end
172172
local first, last
173-
for _, hunk in ipairs(hunks) do
173+
for _, hunk in ipairs(diff_hunks) do
174174
local hunk_start = hunk[1]
175175
local hunk_end = hunk[1] + hunk[2] - 1
176176
if not first or hunk_start < first then

lua/CopilotChat/utils/files.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,15 @@ M.grep = async.wrap(function(path, opts, callback)
164164

165165
if opts.pattern then
166166
table.insert(cmd, '-e')
167-
table.insert(cmd, "'" .. opts.pattern .. "'")
167+
table.insert(cmd, opts.pattern)
168168
end
169169
elseif vim.fn.executable('grep') == 1 then
170170
table.insert(cmd, 'grep')
171171
table.insert(cmd, '-rli')
172172

173173
if opts.pattern then
174174
table.insert(cmd, '-e')
175-
table.insert(cmd, "'" .. opts.pattern .. "'")
175+
table.insert(cmd, opts.pattern)
176176
end
177177
end
178178

0 commit comments

Comments
 (0)