1010--- @field keymaps ? DialogKeymaps Custom keymap configuration
1111--- @field namespace_prefix ? string Prefix for vim.on_key namespace (default : ' opencode_dialog' )
1212--- @field hide_input ? boolean Whether to hide the input window when dialog is active (default : true )
13- --- @field render_part_id ? string Rendered part ID used to resolve mouse clicks against output lines
14- --- @field mouse_select ? boolean Whether Dialog should register <LeftMouse> for option selection (default : false )
1513
1614--- @class DialogKeymaps
1715--- @field up ? string[] Keys for navigating up (default : { ' k' , ' <Up>' } )
1816--- @field down ? string[] Keys for navigating down (default : { ' j' , ' <Down>' } )
1917--- @field left ? string[] Keys for navigating left between groups
2018--- @field right ? string[] Keys for navigating right between groups
2119--- @field select ? string Key for selecting current option (default : ' <CR>' )
22- --- @field dismiss ? string | string[] Keys for dismissing dialog (default : { ' <Esc>' , ' <C-c> ' } )
20+ --- @field dismiss ? string Key for dismissing dialog (default : ' <Esc>' )
2321--- @field number_shortcuts ? boolean Enable 1-9 number shortcuts (default : true )
2422
2523--- @class Dialog
2927--- @field private _selected_index integer Currently selected option index
3028--- @field private _active boolean Whether dialog is currently active
3129--- @field private _group_index integer Currently selected group index
32- --- @field private _option_local_lines integer[] 0-based output-local lines for each option
3330local Dialog = {}
3431Dialog .__index = Dialog
3532
36- --- @param keymap string | string[] | nil
37- --- @return string[]
38- local function keymap_list (keymap )
39- local keymaps = {}
40- if type (keymap ) == ' string' then
41- if keymap ~= ' ' then
42- table.insert (keymaps , keymap )
43- end
44- elseif type (keymap ) == ' table' then
45- for _ , key in ipairs (keymap ) do
46- if key and key ~= ' ' then
47- table.insert (keymaps , key )
48- end
49- end
50- end
51- return keymaps
52- end
53-
54- --- @param keymaps string[]
55- --- @return string
56- local function keymap_legend (keymaps )
57- local labels = {}
58- for _ , key in ipairs (keymaps ) do
59- table.insert (labels , ' `' .. key .. ' `' )
60- end
61- return table.concat (labels , ' or ' )
62- end
63-
6433--- Create a new dialog instance
6534--- @param config DialogConfig Dialog configuration
6635--- @return Dialog
@@ -74,7 +43,7 @@ function Dialog.new(config)
7443 left = {},
7544 right = {},
7645 select = ' <CR>' ,
77- dismiss = { ' <Esc>' , ' <C-c> ' } ,
46+ dismiss = ' <Esc>' ,
7847 number_shortcuts = true ,
7948 }
8049
@@ -85,15 +54,13 @@ function Dialog.new(config)
8554 return true
8655 end ,
8756 hide_input = true ,
88- mouse_select = false ,
8957 } --[[ @as DialogConfig]] , config )
9058
9159 self ._keymaps = {}
9260 self ._key_capture_ns = nil
9361 self ._selected_index = 1
9462 self ._group_index = 1
9563 self ._active = false
96- self ._option_local_lines = {}
9764
9865 return self
9966end
@@ -281,9 +248,8 @@ function Dialog:format_legend(output, options)
281248 local line = output :add_line (select_text )
282249 end
283250
284- local dismiss_keymaps = keymap_list (keymaps .dismiss )
285- if # dismiss_keymaps > 0 then
286- local line = output :add_line (' Close: ' .. keymap_legend (dismiss_keymaps ))
251+ if keymaps .dismiss and keymaps .dismiss ~= ' ' then
252+ local line = output :add_line (' Close: `<Esc>`' )
287253 end
288254 else
289255 local message = options .unfocused_message or ' Focus Opencode window to interact'
302268--- - progress?: string - Progress indicator (e.g., "(1/3)")
303269--- - content?: string[] - Array of lines to render before options
304270--- - render_content?: function(output: Output) - Custom function to render content before options
305- --- - hide_legend?: boolean - Whether to hide movement/select/dismiss instructions
306271function Dialog :format_dialog (output , config )
307272 if not self ._active then
308273 return
@@ -336,10 +301,9 @@ function Dialog:format_dialog(output, config)
336301
337302 self :format_options (output , config .options or {})
338303
339- if not config .hide_legend then
340- output :add_line (' ' )
341- self :format_legend (output , { unfocused_message = config .unfocused_message })
342- end
304+ output :add_line (' ' )
305+
306+ self :format_legend (output , { unfocused_message = config .unfocused_message })
343307
344308 local end_line = output :get_line_count ()
345309
358322--- @param output Output Output object to write to
359323--- @param options table[] Array of option objects with {label : string , description ?: string }
360324function Dialog :format_options (output , options )
361- self ._option_local_lines = {}
362-
363325 for i , option in ipairs (options ) do
364326 local label = option .label
365327 if option .description and option .description ~= ' ' then
@@ -377,12 +339,11 @@ function Dialog:format_options(output, options)
377339 -- add_line returns a 1-based line index; Output extmarks use 0-based
378340 -- keys, so subtract 1 to get the correct extmark key.
379341 local added_idx = output :add_line (line_text )
380- local option_local_line = added_idx - 1
381- self ._option_local_lines [i ] = option_local_line
382342
383343 if is_selected then
384- output :add_extmark (option_local_line , { line_hl_group = ' OpencodeDialogOptionHover' } --[[ @as OutputExtmark]] )
385- output :add_extmark (option_local_line , {
344+ local extmark_idx = added_idx - 1
345+ output :add_extmark (extmark_idx , { line_hl_group = ' OpencodeDialogOptionHover' } --[[ @as OutputExtmark]] )
346+ output :add_extmark (extmark_idx , {
386347 start_col = 2 ,
387348 virt_text = { { ' › ' , ' OpencodeDialogOptionHover' } },
388349 virt_text_pos = ' overlay' ,
@@ -391,58 +352,6 @@ function Dialog:format_options(output, options)
391352 end
392353end
393354
394- --- @return integer | nil
395- function Dialog :_mouse_option_index ()
396- local render_part_id = self ._config .render_part_id
397- if not render_part_id or render_part_id == ' ' then
398- return nil
399- end
400-
401- local mouse = vim .fn .getmousepos ()
402- local winid = mouse and mouse .winid
403- if not winid or winid == 0 or not vim .api .nvim_win_is_valid (winid ) then
404- return nil
405- end
406-
407- local buf = self ._config .buffer
408- if not buf or vim .api .nvim_win_get_buf (winid ) ~= buf then
409- return nil
410- end
411-
412- local rendered_part = require (' opencode.ui.renderer.ctx' ).render_state :get_part (render_part_id )
413- if not rendered_part or rendered_part .line_start == nil then
414- return nil
415- end
416-
417- local mouse_line = mouse .line
418- if not mouse_line or mouse_line <= 0 then
419- return nil
420- end
421-
422- local clicked_output_line = mouse_line - 1
423- for option_index , option_local_line in ipairs (self ._option_local_lines ) do
424- if clicked_output_line == rendered_part .line_start + option_local_line then
425- return option_index
426- end
427- end
428- end
429-
430- --- @return boolean selected
431- function Dialog :select_mouse_option ()
432- if not self ._active or not self ._config .check_focused () then
433- return false
434- end
435-
436- local option_index = self :_mouse_option_index ()
437- if not option_index then
438- return false
439- end
440-
441- self ._selected_index = option_index
442- self ._config .on_select (option_index )
443- return true
444- end
445-
446355--- Set up buffer-scoped keymaps
447356function Dialog :_setup_keymaps ()
448357 self :_clear_keymaps ()
@@ -541,34 +450,18 @@ function Dialog:_setup_keymaps()
541450 table.insert (self ._keymaps , keymaps .select )
542451 end
543452
544- if self . _config . mouse_select ~= false and self . _config . render_part_id and self . _config . render_part_id ~= ' ' then
453+ if keymaps . dismiss and keymaps . dismiss ~= ' ' then
545454 vim .keymap .set (
546455 ' n' ,
547- ' <LeftMouse> ' ,
456+ keymaps . dismiss ,
548457 function ()
549- self :select_mouse_option ()
458+ self :dismiss ()
550459 end ,
551460 vim .tbl_extend (' force' , keymap_opts , {
552- desc = ' Dialog: select clicked option ' ,
461+ desc = ' Dialog: dismiss ' ,
553462 })
554463 )
555- table.insert (self ._keymaps , ' <LeftMouse>' )
556- end
557-
558- for _ , key in ipairs (keymap_list (keymaps .dismiss )) do
559- if key and key ~= ' ' then
560- vim .keymap .set (
561- ' n' ,
562- key ,
563- function ()
564- self :dismiss ()
565- end ,
566- vim .tbl_extend (' force' , keymap_opts , {
567- desc = ' Dialog: dismiss' ,
568- })
569- )
570- table.insert (self ._keymaps , key )
571- end
464+ table.insert (self ._keymaps , keymaps .dismiss )
572465 end
573466
574467 if keymaps .number_shortcuts then
0 commit comments