11--- @module ' snacks.picker'
22
3+ local NS_ID = vim .api .nvim_create_namespace (" OpencodeContext" )
4+
35--- The context a prompt is being made in.
46--- Particularly useful when inputting or selecting a prompt
57--- because that changes the active mode, window, etc.
1214local Context = {}
1315Context .__index = Context
1416
15- local ns_id = vim .api .nvim_create_namespace (" OpencodeContext" )
16-
1717--- @class opencode.context.Range
1818--- @field from integer[] { line , col } (1, 0-based )
1919--- @field to integer[] { line , col } (1, 0-based )
@@ -64,7 +64,7 @@ local function highlight(buf, range)
6464 local line = vim .api .nvim_buf_get_lines (buf , row , row + 1 , false )[1 ] or " "
6565 local clamp_col = math.min (end_col + 1 , # line )
6666 if clamp_col > start_col then
67- vim .api .nvim_buf_set_extmark (buf , ns_id , row , start_col , {
67+ vim .api .nvim_buf_set_extmark (buf , NS_ID , row , start_col , {
6868 end_col = clamp_col ,
6969 hl_group = " Visual" ,
7070 })
@@ -77,7 +77,7 @@ local function highlight(buf, range)
7777 local line = vim .api .nvim_buf_get_lines (buf , end_row , end_row + 1 , false )[1 ] or " "
7878 end_col = math.min (range .to [2 ] + 1 , # line )
7979 end
80- vim .api .nvim_buf_set_extmark (buf , ns_id , from_row , from_col , {
80+ vim .api .nvim_buf_set_extmark (buf , NS_ID , from_row , from_col , {
8181 end_row = end_row ,
8282 end_col = end_col ,
8383 hl_group = " Visual" ,
@@ -108,7 +108,7 @@ function Context.new(range)
108108end
109109
110110function Context :clear ()
111- vim .api .nvim_buf_clear_namespace (self .buf , ns_id , 0 , - 1 )
111+ vim .api .nvim_buf_clear_namespace (self .buf , NS_ID , 0 , - 1 )
112112end
113113
114114function Context :resume ()
@@ -257,45 +257,77 @@ function Context.input_highlight(rendered)
257257 end , Context .extmarks (rendered ))
258258end
259259
260+ --- Get the literal text of a buffer range, trimmed to columns.
261+ --- @param bufnr integer
262+ --- @param start_line integer 1-indexed
263+ --- @param start_col ? integer 1-indexed
264+ --- @param end_line integer 1-indexed
265+ --- @param end_col ? integer 1-indexed
266+ --- @return string
267+ local function get_buffer_range_text (bufnr , start_line , start_col , end_line , end_col )
268+ end_line = end_line or start_line
269+ local lines = vim .api .nvim_buf_get_lines (bufnr , start_line - 1 , end_line , false )
270+ if # lines == 0 then
271+ return " "
272+ end
273+ if start_col then
274+ lines [1 ] = lines [1 ]:sub (start_col )
275+ end
276+ if end_col then
277+ lines [# lines ] = lines [# lines ]:sub (1 , end_col )
278+ end
279+ return table.concat (lines , " \n " )
280+ end
281+
260282--- Format a location for `opencode`.
283+ --- e.g. `opencode.lua:L21:C10-L65:C11` when backed by a file.
284+ --- When not backed by a file it returns the literal text of the range (if present) or the entire buffer.
261285--- @param loc string | integer A buffer number or filepath.
262- --- @param args ? { start_line ?: integer , start_col ?: integer , end_line ?: integer , end_col ?: integer } Location is a buffer number or filepath. Lines and cols are 1-based
263- --- @return string ? location e.g. ` opencode.lua:L21:C10-L65:C11 `
286+ --- @param args ? { start_line ?: integer , start_col ?: integer , end_line ?: integer , end_col ?: integer } 1-based
287+ --- @return string ?
264288function Context .format (loc , args )
265- assert (type (loc ) ~= " string" or # loc > 0 , " Filepath cannot be an empty string" )
266-
267289 local filepath = (type (loc ) == " string" and loc ) or (type (loc ) == " number" and vim .api .nvim_buf_get_name (loc )) or nil
268290 if not filepath or filepath == " " then
269291 return nil
270292 end
271293
272- local result = " "
294+ local start_line = args and args .start_line
295+ local start_col = args and args .start_col
296+ local end_line = args and args .end_line
297+ local end_col = args and args .end_col
273298
274- local absolute_path = vim .fn .fnamemodify (filepath , " :p" )
275- result = result .. absolute_path
299+ -- Normalize start/end (for reversed visual selections)
300+ if start_line and end_line and start_line > end_line then
301+ start_line , end_line = end_line , start_line
302+ if start_col and end_col then
303+ start_col , end_col = end_col , start_col
304+ end
305+ end
276306
277- if args and args .start_line then
278- if args .end_line and args .start_line > args .end_line then
279- -- Ensure start is before end (for reversed visual selections)
280- args .start_line , args .end_line = args .end_line , args .start_line
281- if args .start_col and args .end_col then
282- -- Can happen in visual block mode
283- args .start_col , args .end_col = args .end_col , args .start_col
284- end
307+ -- For buffers not backed by a real file, return inline text
308+ if type (loc ) == " number" then
309+ local filestat = vim .uv .fs_stat (filepath )
310+ if not filestat or filestat .type ~= " file" then
311+ return get_buffer_range_text (
312+ loc ,
313+ start_line or 1 ,
314+ start_col ,
315+ end_line or vim .api .nvim_buf_line_count (loc ),
316+ end_col
317+ )
285318 end
319+ end
286320
287- -- Previously we'd need a space here so `opencode` would recognize the file reference and insert the context,
288- -- but that has regressed with the v1.0.0 `opentui` update :/
289- -- There's a GH issue somewhere.
290- result = result .. " :"
291- result = result .. string.format (" L%d" , args .start_line )
292- if args .start_col then
293- result = result .. string.format (" :C%d" , args .start_col )
321+ local result = vim .fn .fnamemodify (filepath , " :p" )
322+ if start_line then
323+ result = result .. " :" .. string.format (" L%d" , start_line )
324+ if start_col then
325+ result = result .. string.format (" :C%d" , start_col )
294326 end
295- if args . end_line then
296- result = result .. string.format (" -L%d" , args . end_line )
297- if args . end_col then
298- result = result .. string.format (" :C%d" , args . end_col )
327+ if end_line then
328+ result = result .. string.format (" -L%d" , end_line )
329+ if end_col then
330+ result = result .. string.format (" :C%d" , end_col )
299331 end
300332 end
301333 end
0 commit comments