@@ -3,6 +3,7 @@ local util = require('opencode.util')
33local session = require (' opencode.session' )
44local config_file = require (' opencode.config_file' )
55local state = require (' opencode.state' )
6+ local quick_chat = require (' opencode.quick_chat' )
67
78local input_window = require (' opencode.ui.input_window' )
89local ui = require (' opencode.ui.ui' )
@@ -59,6 +60,8 @@ M.toggle = Promise.async(function(new_session)
5960 end
6061end )
6162
63+ --- @param new_session boolean ?
64+ --- @return nil
6265function M .toggle_focus (new_session )
6366 if not ui .is_opencode_focused () then
6467 local focus = state .last_focused_opencode_window or ' input' --- @cast focus ' input' | ' output'
@@ -107,6 +110,39 @@ function M.select_history()
107110 require (' opencode.ui.history_picker' ).pick ()
108111end
109112
113+ function M .quick_chat (message , range )
114+ if not range then
115+ if vim .fn .mode ():match (' [vV\022 ]' ) then
116+ local visual_range = util .get_visual_range ()
117+ if visual_range then
118+ range = {
119+ start = visual_range .start_line ,
120+ stop = visual_range .end_line ,
121+ }
122+ end
123+ end
124+ end
125+
126+ if type (message ) == ' table' then
127+ message = table.concat (message , ' ' )
128+ end
129+
130+ if not message or # message == 0 then
131+ local scope = range and (' [selection: ' .. range .start .. ' -' .. range .stop .. ' ]' )
132+ or ' [line: ' .. tostring (vim .api .nvim_win_get_cursor (0 )[1 ]) .. ' ]'
133+ vim .ui .input ({ prompt = ' Quick Chat Message: ' .. scope , win = { relative = ' cursor' } }, function (input )
134+ if input and input ~= ' ' then
135+ local prompt , ctx = util .parse_quick_context_args (input )
136+ quick_chat .quick_chat (prompt , { context_config = ctx }, range )
137+ end
138+ end )
139+ return
140+ end
141+
142+ local prompt , ctx = util .parse_quick_context_args (message )
143+ quick_chat .quick_chat (prompt , { context_config = ctx }, range )
144+ end
145+
110146function M .toggle_pane ()
111147 return core .open ({ new_session = false , focus = ' output' }):and_then (function ()
112148 ui .toggle_pane ()
@@ -970,6 +1006,14 @@ M.commands = {
9701006 fn = M .toggle_zoom ,
9711007 },
9721008
1009+ quick_chat = {
1010+ desc = ' Quick chat with current buffer or visual selection' ,
1011+ fn = M .quick_chat ,
1012+ range = true , -- Enable range support for visual selections
1013+ nargs = ' +' , -- Allow multiple arguments
1014+ complete = false , -- No completion for custom messages
1015+ },
1016+
9731017 swap = {
9741018 desc = ' Swap pane position left/right' ,
9751019 fn = M .swap_position ,
@@ -1011,7 +1055,7 @@ M.commands = {
10111055 local title = table.concat (vim .list_slice (args , 2 ), ' ' )
10121056 M .rename_session (state .active_session , title )
10131057 else
1014- local valid_subcmds = table.concat (M .commands .session .completions , ' , ' )
1058+ local valid_subcmds = table.concat (M .commands .session .completions or {} , ' , ' )
10151059 vim .notify (' Invalid session subcommand. Use: ' .. valid_subcmds , vim .log .levels .ERROR )
10161060 end
10171061 end ,
@@ -1041,7 +1085,7 @@ M.commands = {
10411085 elseif subcmd == ' close' then
10421086 M .diff_close ()
10431087 else
1044- local valid_subcmds = table.concat (M .commands .diff .completions , ' , ' )
1088+ local valid_subcmds = table.concat (M .commands .diff .completions or {} , ' , ' )
10451089 vim .notify (' Invalid diff subcommand. Use: ' .. valid_subcmds , vim .log .levels .ERROR )
10461090 end
10471091 end ,
@@ -1120,7 +1164,7 @@ M.commands = {
11201164 elseif subcmd == ' select' then
11211165 M .select_agent ()
11221166 else
1123- local valid_subcmds = table.concat (M .commands .agent .completions , ' , ' )
1167+ local valid_subcmds = table.concat (M .commands .agent .completions or {} , ' , ' )
11241168 vim .notify (' Invalid agent subcommand. Use: ' .. valid_subcmds , vim .log .levels .ERROR )
11251169 end
11261170 end ,
@@ -1208,7 +1252,7 @@ M.commands = {
12081252 elseif subcmd == ' deny' then
12091253 M .permission_deny ()
12101254 else
1211- local valid_subcmds = table.concat (M .commands .permission .completions , ' , ' )
1255+ local valid_subcmds = table.concat (M .commands .permission .completions or {} , ' , ' )
12121256 vim .notify (' Invalid permission subcommand. Use: ' .. valid_subcmds , vim .log .levels .ERROR )
12131257 end
12141258 end ,
@@ -1309,6 +1353,14 @@ M.legacy_command_map = {
13091353
13101354function M .route_command (opts )
13111355 local args = vim .split (opts .args or ' ' , ' %s+' , { trimempty = true })
1356+ local range = nil
1357+
1358+ if opts .range and opts .range > 0 then
1359+ range = {
1360+ start = opts .line1 ,
1361+ stop = opts .line2 ,
1362+ }
1363+ end
13121364
13131365 if # args == 0 then
13141366 M .toggle ()
@@ -1319,7 +1371,7 @@ function M.route_command(opts)
13191371 local subcmd_def = M .commands [subcommand ]
13201372
13211373 if subcmd_def and subcmd_def .fn then
1322- subcmd_def .fn (vim .list_slice (args , 2 ))
1374+ subcmd_def .fn (vim .list_slice (args , 2 ), range )
13231375 else
13241376 vim .notify (' Unknown subcommand: ' .. subcommand , vim .log .levels .ERROR )
13251377 end
@@ -1413,6 +1465,7 @@ function M.setup()
14131465 vim .api .nvim_create_user_command (' Opencode' , M .route_command , {
14141466 desc = ' Opencode.nvim main command with nested subcommands' ,
14151467 nargs = ' *' ,
1468+ range = true , -- Enable range support
14161469 complete = M .complete_command ,
14171470 })
14181471
0 commit comments