Skip to content

Commit 7ccd8b6

Browse files
deathbeamTomas Slusny
andauthored
feat: Rework how selectors work so only last buffer is remembered (#106)
This allows updating selection without having to call chat.ask or chat.open again Signed-off-by: Tomas Slusny <ts6234@att.com> Signed-off-by: Tomas Slusny <slusnucky@gmail.com> Co-authored-by: Tomas Slusny <ts6234@att.com>
1 parent c28965e commit 7ccd8b6

5 files changed

Lines changed: 112 additions & 154 deletions

File tree

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ chat.close()
113113
-- Toggle chat window
114114
chat.toggle()
115115

116+
-- Toggle chat window with custom options
117+
chat.toggle({
118+
window = {
119+
layout = 'float',
120+
title = 'My Title',
121+
},
122+
})
123+
116124
-- Reset chat window
117125
chat.reset()
118126

@@ -123,6 +131,9 @@ chat.ask("Explain how it works.")
123131
chat.ask("Explain how it works.", {
124132
selection = require("CopilotChat.select").buffer,
125133
})
134+
135+
-- Get all available prompts (can be used for integrations like fzf/telescope)
136+
local prompts = chat.prompts()
126137
```
127138

128139
### Commands
@@ -181,14 +192,14 @@ Also see [here](/lua/CopilotChat/config.lua):
181192
},
182193
CommitStaged = {
183194
prompt = 'Write commit message for the change with commitizen convention. Make sure the title has maximum 50 characters and message is wrapped at 72 characters. Wrap the whole message in code block with language gitcommit.',
184-
selection = function()
185-
return select.gitdiff(true)
195+
selection = function(bufnr)
196+
return select.gitdiff(bufnr, true)
186197
end,
187198
},
188199
},
189200
-- default selection (visual or line)
190-
selection = function()
191-
return select.visual() or select.line()
201+
selection = function(bufnr)
202+
return select.visual(bufnr) or select.line(bufnr)
192203
end,
193204
-- default window options
194205
window = {

lua/CopilotChat/code_actions.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ end
5959
local function show_help_actions(config)
6060
-- Convert diagnostic to a table of actions
6161
local help_actions = {}
62-
local diagnostic = select.diagnostics()
62+
local diagnostic = select.diagnostics(vim.api.nvim_get_current_buf())
6363
if diagnostic then
6464
table.insert(help_actions, {
6565
label = 'Please assist with fixing the following diagnostic issue in file: "'
@@ -99,7 +99,7 @@ end
9999
local function show_prompt_actions(config)
100100
-- Convert user prompts to a table of actions
101101
local user_prompt_actions = {}
102-
for key, prompt in pairs(chat.get_prompts(true)) do
102+
for key, prompt in pairs(chat.prompts(true)) do
103103
table.insert(user_prompt_actions, { name = key, label = prompt.prompt })
104104
end
105105

lua/CopilotChat/config.lua

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ local prompts = require('CopilotChat.prompts')
22
local select = require('CopilotChat.select')
33

44
---@class CopilotChat.config.selection
5-
---@field buffer number
65
---@field lines string
7-
---@field filetype string?
86
---@field start_row number?
97
---@field start_col number?
108
---@field end_row number?
@@ -13,7 +11,7 @@ local select = require('CopilotChat.select')
1311

1412
---@class CopilotChat.config.prompt
1513
---@field prompt string?
16-
---@field selection function|table?
14+
---@field selection nil|fun(bufnr: number?):CopilotChat.config.selection?
1715
---@field mapping string?
1816
---@field description string?
1917

@@ -51,7 +49,7 @@ local select = require('CopilotChat.select')
5149
---@field name string?
5250
---@field separator string?
5351
---@field prompts table<string, CopilotChat.config.prompt|string>?
54-
---@field selection nil|CopilotChat.config.selection|fun():CopilotChat.config.selection?
52+
---@field selection nil|fun(bufnr: number?):CopilotChat.config.selection?
5553
---@field window CopilotChat.config.window?
5654
---@field mappings CopilotChat.config.mappings?
5755
return {
@@ -84,14 +82,14 @@ return {
8482
},
8583
CommitStaged = {
8684
prompt = 'Write commit message for the change with commitizen convention. Make sure the title has maximum 50 characters and message is wrapped at 72 characters. Wrap the whole message in code block with language gitcommit.',
87-
selection = function()
88-
return select.gitdiff(true)
85+
selection = function(bufnr)
86+
return select.gitdiff(bufnr, true)
8987
end,
9088
},
9189
},
9290
-- default selection (visual or line)
93-
selection = function()
94-
return select.visual() or select.line()
91+
selection = function(bufnr)
92+
return select.visual(bufnr) or select.line(bufnr)
9593
end,
9694
-- default window options
9795
window = {

lua/CopilotChat/init.lua

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ local plugin_name = 'CopilotChat.nvim'
1212
--- @class CopilotChat.state
1313
--- @field copilot CopilotChat.Copilot?
1414
--- @field chat CopilotChat.Chat?
15-
--- @field selection CopilotChat.config.selection?
15+
--- @field current_bufnr number?
1616
local state = {
1717
copilot = nil,
1818
chat = nil,
19-
selection = nil,
2019
window = nil,
20+
current_bufnr = nil,
2121
}
2222

2323
function CopilotChatFoldExpr(lnum, separator)
@@ -62,9 +62,8 @@ local function find_lines_between_separator(lines, pattern, at_least_one)
6262
return result, separator_line_start, separator_line_finish, line_count
6363
end
6464

65-
local function show_diff_between_selection_and_copilot()
66-
local selection = state.selection
67-
if not selection or not selection.buffer or not selection.start_row or not selection.end_row then
65+
local function show_diff_between_selection_and_copilot(selection)
66+
if not selection or not selection.start_row or not selection.end_row then
6867
return
6968
end
7069

@@ -91,7 +90,7 @@ local function show_diff_between_selection_and_copilot()
9190
end
9291

9392
local function update_prompts(prompt, system_prompt)
94-
local prompts_to_use = M.get_prompts()
93+
local prompts_to_use = M.prompts()
9594
local try_again = false
9695
local result = string.gsub(prompt, [[/[%w_]+]], function(match)
9796
local found = prompts_to_use[string.sub(match, 2)]
@@ -164,7 +163,7 @@ local function complete()
164163
end
165164

166165
local items = {}
167-
local prompts_to_use = M.get_prompts()
166+
local prompts_to_use = M.prompts()
168167

169168
for name, prompt in pairs(prompts_to_use) do
170169
items[#items + 1] = {
@@ -181,9 +180,16 @@ local function complete()
181180
vim.fn.complete(cmp_start + 1, items)
182181
end
183182

183+
local function get_selection(config, bufnr)
184+
if config and config.selection and vim.api.nvim_buf_is_valid(bufnr) then
185+
return config.selection(bufnr) or {}
186+
end
187+
return {}
188+
end
189+
184190
--- Get the prompts to use.
185191
---@param skip_system boolean|nil
186-
function M.get_prompts(skip_system)
192+
function M.prompts(skip_system)
187193
local function get_prompt_kind(name)
188194
return vim.startswith(name, 'COPILOT_') and 'system' or 'user'
189195
end
@@ -217,18 +223,13 @@ function M.get_prompts(skip_system)
217223
end
218224

219225
--- Open the chat window.
220-
---@param config CopilotChat.config|nil
221-
function M.open(config)
226+
---@param config CopilotChat.config?
227+
---@param current_bufnr number?
228+
function M.open(config, current_bufnr)
222229
local should_reset = config and config.window ~= nil and not vim.tbl_isempty(config.window)
223-
224230
config = vim.tbl_deep_extend('force', M.config, config or {})
225-
local selection = nil
226-
if type(config.selection) == 'function' then
227-
selection = config.selection()
228-
else
229-
selection = config.selection
230-
end
231-
state.selection = selection or {}
231+
state.current_bufnr = current_bufnr or vim.api.nvim_get_current_buf()
232+
local selection = get_selection(config, state.current_bufnr)
232233

233234
local just_created = false
234235

@@ -264,26 +265,24 @@ function M.open(config)
264265
if line_count == end_line then
265266
vim.api.nvim_buf_set_lines(state.chat.bufnr, start_line, end_line, false, { '' })
266267
end
267-
M.ask(input, { selection = state.selection })
268+
M.ask(input, nil, state.current_bufnr)
268269
end
269270
end, { buffer = state.chat.bufnr })
270271
end
271272

272273
if config.mappings.show_diff then
273-
vim.keymap.set('n', config.mappings.show_diff, show_diff_between_selection_and_copilot, {
274+
vim.keymap.set('n', config.mappings.show_diff, function()
275+
local selection = get_selection(config, state.current_bufnr)
276+
show_diff_between_selection_and_copilot(selection)
277+
end, {
274278
buffer = state.chat.bufnr,
275279
})
276280
end
277281

278282
if config.mappings.accept_diff then
279283
vim.keymap.set('n', config.mappings.accept_diff, function()
280-
if
281-
not state.selection
282-
or not state.selection.buffer
283-
or not state.selection.start_row
284-
or not state.selection.end_row
285-
or not vim.api.nvim_buf_is_valid(state.selection.buffer)
286-
then
284+
local selection = get_selection(config, state.current_bufnr)
285+
if not selection.start_row or not selection.end_row then
287286
return
288287
end
289288

@@ -293,11 +292,11 @@ function M.open(config)
293292
local lines = find_lines_between_separator(section_lines, '^```%w*$', true)
294293
if #lines > 0 then
295294
vim.api.nvim_buf_set_text(
296-
state.selection.buffer,
297-
state.selection.start_row - 1,
298-
state.selection.start_col - 1,
299-
state.selection.end_row - 1,
300-
state.selection.end_col,
295+
state.current_bufnr,
296+
selection.start_row - 1,
297+
selection.start_col - 1,
298+
selection.end_row - 1,
299+
selection.end_col,
301300
lines
302301
)
303302
end
@@ -398,19 +397,21 @@ end
398397

399398
--- Toggle the chat window.
400399
---@param config CopilotChat.config|nil
401-
function M.toggle(config)
400+
---@param bufnr number?
401+
function M.toggle(config, bufnr)
402402
if state.window and vim.api.nvim_win_is_valid(state.window) then
403403
M.close()
404404
else
405-
M.open(config)
405+
M.open(config, bufnr)
406406
end
407407
end
408408

409409
--- Ask a question to the Copilot model.
410410
---@param prompt string
411411
---@param config CopilotChat.config|nil
412-
function M.ask(prompt, config)
413-
M.open(config)
412+
---@param bufnr number?
413+
function M.ask(prompt, config, bufnr)
414+
M.open(config, bufnr)
414415

415416
if not prompt or prompt == '' then
416417
return
@@ -428,29 +429,26 @@ function M.ask(prompt, config)
428429
M.reset()
429430
end
430431

431-
if state.selection.prompt_extra then
432-
updated_prompt = updated_prompt .. ' ' .. state.selection.prompt_extra
432+
local selection = get_selection(config, state.current_bufnr)
433+
local filetype = vim.bo[state.current_bufnr].filetype
434+
if selection.prompt_extra then
435+
updated_prompt = updated_prompt .. ' ' .. selection.prompt_extra
433436
end
434437

435438
local finish = false
436439
if config.show_system_prompt then
437440
finish = true
438441
append(' **System prompt** ' .. config.separator .. '\n```\n' .. system_prompt .. '```\n')
439442
end
440-
if
441-
config.show_user_selection
442-
and state.selection
443-
and state.selection.lines
444-
and state.selection.lines ~= ''
445-
then
443+
if config.show_user_selection and selection.lines and selection.lines ~= '' then
446444
finish = true
447445
append(
448446
' **Selection** '
449447
.. config.separator
450448
.. '\n```'
451-
.. (state.selection.filetype or '')
449+
.. (filetype or '')
452450
.. '\n'
453-
.. state.selection.lines
451+
.. selection.lines
454452
.. '\n```'
455453
)
456454
end
@@ -461,8 +459,8 @@ function M.ask(prompt, config)
461459
append(updated_prompt)
462460

463461
return state.copilot:ask(updated_prompt, {
464-
selection = state.selection.lines,
465-
filetype = state.selection.filetype,
462+
selection = selection.lines,
463+
filetype = filetype,
466464
system_prompt = system_prompt,
467465
model = config.model,
468466
temperature = config.temperature,
@@ -498,7 +496,7 @@ end
498496

499497
--- Enables/disables debug
500498
---@param debug boolean
501-
function M.set_debug(debug)
499+
function M.debug(debug)
502500
M.config.debug = debug
503501
local logfile = string.format('%s/%s.log', vim.fn.stdpath('state'), plugin_name)
504502
log.new({
@@ -515,9 +513,9 @@ function M.setup(config)
515513
M.config = vim.tbl_deep_extend('force', default_config, config or {})
516514
state.copilot = Copilot()
517515
debuginfo.setup()
518-
M.set_debug(M.config.debug)
516+
M.debug(M.config.debug)
519517

520-
for name, prompt in pairs(M.get_prompts(true)) do
518+
for name, prompt in pairs(M.prompts(true)) do
521519
vim.api.nvim_create_user_command('CopilotChat' .. name, function(args)
522520
local input = prompt.prompt
523521
if args.args and vim.trim(args.args) ~= '' then

0 commit comments

Comments
 (0)