@@ -2,6 +2,11 @@ local state = require('opencode.state')
22local config = require (' opencode.config' )
33local M = {}
44
5+ -- Track hidden state
6+ M ._hidden = false
7+ -- Flag to prevent WinClosed autocmd from closing all windows during toggle
8+ M ._toggling = false
9+
510function M .create_buf ()
611 local input_buf = vim .api .nvim_create_buf (false , true )
712 vim .api .nvim_set_option_value (' filetype' , ' opencode' , { buf = input_buf })
@@ -48,10 +53,12 @@ function M.close()
4853 pcall (vim .api .nvim_buf_delete , state .windows .input_buf , { force = true })
4954end
5055
56+ --- Handle submit action from input window
57+ --- @return boolean true if a message was sent to the AI , false otherwise
5158function M .handle_submit ()
5259 local windows = state .windows
5360 if not windows or not M .mounted (windows ) then
54- return
61+ return false
5562 end
5663 --- @cast windows { input_buf : integer }
5764
@@ -63,21 +70,22 @@ function M.handle_submit()
6370 })
6471
6572 if input_content == ' ' then
66- return
73+ return false
6774 end
6875
6976 if input_content :match (' ^!' ) then
7077 M ._execute_shell_command (input_content :sub (2 ))
71- return
78+ return false
7279 end
7380
7481 local key = config .get_key_for_function (' input_window' , ' slash_commands' ) or ' /'
7582 if input_content :match (' ^' .. key ) then
7683 M ._execute_slash_command (input_content )
77- return
84+ return false
7885 end
7986
8087 require (' opencode.core' ).send_message (input_content )
88+ return true
8189end
8290
8391M ._execute_shell_command = function (command )
@@ -267,6 +275,11 @@ function M.recover_input(windows)
267275end
268276
269277function M .focus_input ()
278+ if M ._hidden then
279+ M ._show ()
280+ return
281+ end
282+
270283 if not M .mounted () then
271284 return
272285 end
@@ -350,6 +363,18 @@ function M.setup_autocmds(windows, group)
350363 end ,
351364 })
352365
366+ vim .api .nvim_create_autocmd (' WinLeave' , {
367+ group = group ,
368+ buffer = windows .input_buf ,
369+ callback = function ()
370+ -- Auto-hide input window when auto_hide is enabled and focus leaves
371+ -- Don't hide if displaying a route (slash command output like /help)
372+ if config .ui .input .auto_hide and not M .is_hidden () and not state .display_route then
373+ M ._hide ()
374+ end
375+ end ,
376+ })
377+
353378 vim .api .nvim_create_autocmd ({ ' TextChanged' , ' TextChangedI' }, {
354379 buffer = windows .input_buf ,
355380 callback = function ()
@@ -365,4 +390,103 @@ function M.setup_autocmds(windows, group)
365390 end )
366391end
367392
393+ --- Toggle the input window visibility (hide/show)
394+ --- When hidden, the input window is closed entirely
395+ --- When shown, the input window is recreated
396+ function M .toggle ()
397+ local windows = state .windows
398+ if not windows then
399+ return
400+ end
401+
402+ if M ._hidden then
403+ -- Show: recreate the input window
404+ M ._show ()
405+ else
406+ -- Hide: close the input window
407+ M ._hide ()
408+ end
409+ end
410+
411+ --- Hide the input window by closing it
412+ function M ._hide ()
413+ local windows = state .windows
414+ if not M .mounted (windows ) then
415+ return
416+ end
417+
418+ local output_window = require (' opencode.ui.output_window' )
419+ local was_at_bottom = output_window .viewport_at_bottom
420+
421+ M ._hidden = true
422+ M ._toggling = true
423+
424+ -- Close the input window (but keep the buffer)
425+ pcall (vim .api .nvim_win_close , windows .input_win , false )
426+ windows .input_win = nil
427+
428+ -- Reset toggling flag after the WinClosed event has been processed
429+ vim .schedule (function ()
430+ M ._toggling = false
431+ end )
432+
433+ -- Focus output window
434+ output_window .focus_output (true )
435+
436+ if was_at_bottom then
437+ vim .schedule (function ()
438+ require (' opencode.ui.renderer' ).scroll_to_bottom ()
439+ end )
440+ end
441+ end
442+
443+ --- Show the input window by recreating it
444+ function M ._show ()
445+ local windows = state .windows
446+ if not windows or not windows .input_buf or not windows .output_win then
447+ return
448+ end
449+
450+ -- Don't recreate if already visible
451+ if windows .input_win and vim .api .nvim_win_is_valid (windows .input_win ) then
452+ M ._hidden = false
453+ return
454+ end
455+
456+ local output_window = require (' opencode.ui.output_window' )
457+ local was_at_bottom = output_window .viewport_at_bottom
458+
459+ -- Create a new split for the input window
460+ local output_win = windows .output_win
461+ vim .api .nvim_set_current_win (output_win )
462+
463+ local input_position = config .ui .input_position or ' bottom'
464+ vim .cmd ((input_position == ' top' and ' aboveleft' or ' belowright' ) .. ' split' )
465+ local input_win = vim .api .nvim_get_current_win ()
466+
467+ -- Set the buffer
468+ vim .api .nvim_win_set_buf (input_win , windows .input_buf )
469+ windows .input_win = input_win
470+
471+ -- Re-apply window settings
472+ M .setup (windows )
473+
474+ M ._hidden = false
475+
476+ -- Focus the input window
477+ M .focus_input ()
478+
479+ if was_at_bottom then
480+ vim .schedule (function ()
481+ require (' opencode.ui.renderer' ).scroll_to_bottom ()
482+ end )
483+ end
484+ end
485+
486+ --- Check if the input window is currently hidden
487+ --- @return boolean
488+ function M .is_hidden ()
489+ return M ._hidden
490+ end
491+
368492return M
0 commit comments