Skip to content

Commit 6baeebf

Browse files
committed
feat: add <leader>oy mapping to add visual selection to context across buffers
- Add add_visual_selection and command This should fix #248
1 parent f6f5f77 commit 6baeebf

6 files changed

Lines changed: 64 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ require('opencode').setup({
131131
['<leader>oR'] = { 'rename_session' }, -- Rename current session
132132
['<leader>op'] = { 'configure_provider' }, -- Quick provider and model switch from predefined list
133133
['<leader>oV'] = { 'configure_variant' }, -- Switch model variant for the current model
134+
['<leader>oy'] = { 'add_visual_selection' },
134135
['<leader>oz'] = { 'toggle_zoom' }, -- Zoom in/out on the Opencode windows
135136
['<leader>ov'] = { 'paste_image'}, -- Paste image from clipboard into current session
136137
['<leader>od'] = { 'diff_open' }, -- Opens a diff tab of a modified file since the last opencode prompt

lua/opencode/api.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,18 @@ M.review = Promise.async(function(args)
10131013
end)
10141014
end)
10151015

1016+
--- Add the current visual selection to the context without opening/focusing the panel.
1017+
--- Can be called from any buffer. Selections accumulate across files.
1018+
M.add_visual_selection = Promise.async(
1019+
---@param _ any Unused
1020+
---@param range OpencodeSelectionRange
1021+
function(_, range)
1022+
local context = require('opencode.context')
1023+
context.add_visual_selection(range)
1024+
M.open_input():await()
1025+
end
1026+
)
1027+
10161028
---@type table<string, OpencodeUICommand>
10171029
M.commands = {
10181030
open = {
@@ -1369,6 +1381,11 @@ M.commands = {
13691381
desc = 'Browse code references from conversation',
13701382
fn = M.references,
13711383
},
1384+
1385+
add_visual_selection = {
1386+
desc = 'Add current visual selection to context',
1387+
fn = M.add_visual_selection,
1388+
},
13721389
}
13731390

13741391
M.slash_commands_map = {
@@ -1449,6 +1466,7 @@ M.legacy_command_map = {
14491466

14501467
function M.route_command(opts)
14511468
local args = vim.split(opts.args or '', '%s+', { trimempty = true })
1469+
---@type OpencodeSelectionRange|nil
14521470
local range = nil
14531471

14541472
if opts.range and opts.range > 0 then

lua/opencode/config.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ M.defaults = {
2828
['<leader>oR'] = { 'rename_session', desc = 'Rename session' },
2929
['<leader>op'] = { 'configure_provider', desc = 'Configure provider' },
3030
['<leader>oV'] = { 'configure_variant', desc = 'Configure model variant' },
31+
['<leader>oy'] = { 'add_visual_selection', desc = 'Add visual selection to context', mode = { 'v' } },
3132
['<leader>oz'] = { 'toggle_zoom', desc = 'Toggle zoom' },
3233
['<leader>ov'] = { 'paste_image', desc = 'Paste image from clipboard' },
3334
['<leader>od'] = { 'diff_open', desc = 'Open diff view' },

lua/opencode/context.lua

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,43 @@ function M.clear_selections()
8282
ChatContext.clear_selections()
8383
end
8484

85+
--- Captures the current visual selection and adds it to the context.
86+
--- This can be called from any buffer at any time, even when the panel is already open.
87+
--- Selections persist across file switches and accumulate across buffers.
88+
---@param range? OpencodeSelectionRange
89+
---@return boolean success Whether a selection was successfully added
90+
function M.add_visual_selection(range)
91+
local buf = vim.api.nvim_get_current_buf()
92+
93+
if not util.is_buf_a_file(buf) then
94+
vim.notify('Cannot add selection: not a file buffer', vim.log.levels.WARN)
95+
return false
96+
end
97+
98+
local current_selection = BaseContext.get_current_selection(nil, range)
99+
if not current_selection then
100+
vim.notify('No visual selection found', vim.log.levels.WARN)
101+
return false
102+
end
103+
104+
local file = BaseContext.get_current_file_for_selection(buf)
105+
if not file then
106+
vim.notify('Cannot determine file for selection', vim.log.levels.WARN)
107+
return false
108+
end
109+
110+
local selection = BaseContext.new_selection(file, current_selection.text, current_selection.lines)
111+
M.add_selection(selection)
112+
113+
vim.notify(
114+
string.format('Selection added from %s (lines %s)', file.name, current_selection.lines),
115+
vim.log.levels.INFO
116+
)
117+
118+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Esc>', true, false, true), 'n', true)
119+
return true
120+
end
121+
85122
function M.add_file(file)
86123
local is_file = vim.fn.filereadable(file) == 1
87124
local is_dir = vim.fn.isdirectory(file) == 1

lua/opencode/context/base_context.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,15 @@ function M.get_current_cursor_data(buf, win, context_config)
188188
end
189189

190190
---@param context_config? OpencodeContextConfig
191+
---@param range? OpencodeSelectionRange
191192
---@return table|nil
192-
function M.get_current_selection(context_config)
193+
function M.get_current_selection(context_config, range)
193194
if not M.is_context_enabled('selection', context_config) then
194195
return nil
195196
end
196197

197198
-- Return nil if not in a visual mode
198-
if not vim.fn.mode():match('[vV\022]') then
199+
if not vim.fn.mode():match('[vV\022]') and not range then
199200
return nil
200201
end
201202

lua/opencode/types.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,7 @@
556556
---@field messages number Number of messages reverted
557557
---@field tool_calls number Number of tool calls reverted
558558
---@field files table<string, {additions: number, deletions: number}> Summary of file changes reverted
559+
560+
---@class OpencodeSelectionRange
561+
---@field start number Starting line number (inclusive)
562+
---@field stop number Ending line number (inclusive)

0 commit comments

Comments
 (0)