Skip to content

Commit 879c59d

Browse files
committed
Increase flexibility of diff selectors
This change allows selecting different diffs by simply navigating cursor to the diff codeblock. Potentionally closes #318 Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
1 parent 76bfba5 commit 879c59d

1 file changed

Lines changed: 55 additions & 26 deletions

File tree

lua/CopilotChat/init.lua

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -86,37 +86,61 @@ local function get_error_message(err)
8686
return dedupe_strings(vim.inspect(err))
8787
end
8888

89-
local function find_lines_between_separator(lines, pattern, at_least_one)
89+
local function find_lines_between_separator(
90+
lines,
91+
start_line,
92+
start_pattern,
93+
end_pattern,
94+
allow_end_of_file
95+
)
96+
if not end_pattern then
97+
end_pattern = start_pattern
98+
end
99+
90100
local line_count = #lines
101+
local current_line = vim.api.nvim_win_get_cursor(0)[1] - start_line
91102
local separator_line_start = 1
92103
local separator_line_finish = line_count
93104
local found_one = false
94105

95-
-- Find the last occurrence of the separator
96-
for i = line_count, 1, -1 do -- Reverse the loop to start from the end
106+
-- Find starting separator line
107+
for i = current_line, 1, -1 do
97108
local line = lines[i]
98-
if string.find(line, pattern) then
99-
if i < (separator_line_finish + 1) and (not at_least_one or found_one) then
100-
separator_line_start = i + 1
101-
break -- Exit the loop as soon as the condition is met
109+
110+
if line and string.match(line, start_pattern) then
111+
separator_line_start = i + 1
112+
113+
for x = separator_line_start, line_count do
114+
local next_line = lines[x]
115+
if next_line and string.match(next_line, end_pattern) then
116+
separator_line_finish = x - 1
117+
found_one = true
118+
break
119+
end
120+
if allow_end_of_file and x == line_count then
121+
separator_line_finish = x
122+
found_one = true
123+
break
124+
end
102125
end
103126

104-
found_one = true
105-
separator_line_finish = i - 1
127+
if found_one then
128+
break
129+
end
106130
end
107131
end
108132

109-
if at_least_one and not found_one then
110-
return {}, 1, 1, 0
133+
if not found_one then
134+
return {}, 1, 1
111135
end
112136

113-
-- Extract everything between the last and next separator
137+
-- Extract everything between the last and next separator or end of file
114138
local result = {}
115139
for i = separator_line_start, separator_line_finish do
116140
table.insert(result, lines[i])
117141
end
118142

119-
return result, separator_line_start, separator_line_finish, line_count
143+
return result, separator_line_start, separator_line_finish
120144
end
121145

122146
local function update_prompts(prompt, system_prompt)
@@ -790,14 +814,15 @@ function M.setup(config)
790814

791815
map_key(M.config.mappings.submit_prompt, bufnr, function()
792816
local chat_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
793-
local lines, start_line, end_line, line_count =
794-
find_lines_between_separator(chat_lines, M.config.separator .. '$')
817+
local lines, start_line, end_line =
818+
find_lines_between_separator(chat_lines, 0, M.config.separator .. '$', nil, true)
795819
local input = vim.trim(table.concat(lines, '\n'))
796820
if input ~= '' then
797821
-- If we are entering the input at the end, replace it
798-
if line_count == end_line then
822+
if #chat_lines == end_line then
799823
vim.api.nvim_buf_set_lines(bufnr, start_line, end_line, false, { '' })
800824
end
825+
801826
M.ask(input, state.config, state.source)
802827
end
803828
end)
@@ -809,9 +834,10 @@ function M.setup(config)
809834
end
810835

811836
local chat_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
812-
local section_lines =
813-
find_lines_between_separator(chat_lines, M.config.separator .. '$', true)
814-
local lines = find_lines_between_separator(section_lines, '^```%w*$', true)
837+
local section_lines, start_line =
838+
find_lines_between_separator(chat_lines, 0, M.config.separator .. '$')
839+
local lines =
840+
find_lines_between_separator(section_lines, start_line - 1, '^```%w+$', '^```$')
815841
if #lines > 0 then
816842
vim.api.nvim_buf_set_text(
817843
state.source.bufnr,
@@ -831,9 +857,10 @@ function M.setup(config)
831857
end
832858

833859
local chat_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
834-
local section_lines =
835-
find_lines_between_separator(chat_lines, M.config.separator .. '$', true)
836-
local lines = find_lines_between_separator(section_lines, '^```%w*$', true)
860+
local section_lines, start_line =
861+
find_lines_between_separator(chat_lines, 0, M.config.separator .. '$')
862+
local lines =
863+
find_lines_between_separator(section_lines, start_line - 1, '^```%w+$', '^```$')
837864
if #lines > 0 then
838865
local content = table.concat(lines, '\n')
839866
vim.fn.setreg(M.config.mappings.yank_diff.register, content)
@@ -847,10 +874,12 @@ function M.setup(config)
847874
end
848875

849876
local chat_lines = vim.api.nvim_buf_get_lines(state.chat.bufnr, 0, -1, false)
850-
local section_lines =
851-
find_lines_between_separator(chat_lines, M.config.separator .. '$', true)
852-
local lines =
853-
table.concat(find_lines_between_separator(section_lines, '^```%w*$', true), '\n')
877+
local section_lines, start_line =
878+
find_lines_between_separator(chat_lines, 0, M.config.separator .. '$')
879+
local lines = table.concat(
880+
find_lines_between_separator(section_lines, start_line - 1, '^```%w+$', '^```$'),
881+
'\n'
882+
)
854883
if vim.trim(lines) ~= '' then
855884
state.last_code_output = lines
856885

0 commit comments

Comments
 (0)