Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lua/opencode/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ M.defaults = {
text = {
wrap = false,
},
min_height = nil,
max_height = nil,
-- Auto-hide input window when prompt is submitted or focus switches to output window
auto_hide = false,
},
Expand Down
36 changes: 36 additions & 0 deletions lua/opencode/health.lua
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,42 @@ local function check_configuration()
health.ok(string.format('Input height: %s', config.ui.input_height))
end

local min_height = config.ui.input.min_height
local max_height = config.ui.input.max_height
if min_height ~= nil or max_height ~= nil then
if type(min_height) ~= 'number' or type(max_height) ~= 'number' then
health.warn(
'Input min/max height configuration incomplete',
{ 'Set both ui.input.min_height and ui.input.max_height to enable auto-resize' }
)
else
if min_height <= 0 or min_height > 1 then
health.warn(
string.format('Invalid input min height: %s', min_height),
{ 'Input min height should be between 0 and 1 (percentage of screen)' }
)
else
health.ok(string.format('Input min height: %s', min_height))
end

if max_height <= 0 or max_height > 1 then
health.warn(
string.format('Invalid input max height: %s', max_height),
{ 'Input max height should be between 0 and 1 (percentage of screen)' }
)
else
health.ok(string.format('Input max height: %s', max_height))
end

if min_height > max_height then
health.warn(
'Input min height exceeds max height',
{ 'Ensure ui.input.min_height is less than or equal to ui.input.max_height' }
)
end
end
end

health.ok('Configuration loaded successfully')
end

Expand Down
8 changes: 7 additions & 1 deletion lua/opencode/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,17 @@
---@field icons { preset: 'text'|'nerdfonts', overrides: table<string,string> }
---@field loading_animation OpencodeLoadingAnimationConfig
---@field output OpencodeUIOutputConfig
---@field input { text: { wrap: boolean } }
---@field input OpencodeUIInputConfig
---@field completion OpencodeCompletionConfig
---@field highlights? OpencodeHighlightConfig
---@field picker OpencodeUIPickerConfig

---@class OpencodeUIInputConfig
---@field text { wrap: boolean }
---@field min_height? number
---@field max_height? number
---@field auto_hide boolean

---@class OpencodeHighlightConfig
---@field vertical_borders? { tool?: { fg?: string, bg?: string }, user?: { fg?: string, bg?: string }, assistant?: { fg?: string, bg?: string } }

Expand Down
81 changes: 74 additions & 7 deletions lua/opencode/ui/input_window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,62 @@ local M = {}
M._hidden = false
-- Flag to prevent WinClosed autocmd from closing all windows during toggle
M._toggling = false
M._resize_scheduled = false

local function auto_resize_enabled()
return type(config.ui.input.min_height) == 'number' and type(config.ui.input.max_height) == 'number'
end

local function get_content_height(windows)
local line_count = vim.api.nvim_buf_line_count(windows.input_buf)
if line_count <= 0 then
return 1
end
if config.ui.input.text.wrap then
local ok, result = pcall(vim.api.nvim_win_text_height, windows.input_win, {
start_row = 0,
end_row = math.max(0, line_count - 1),
})
if ok and result and result.all then
return result.all
end
end

return line_count
end

local function get_winbar_height(windows)
local ok, winbar = pcall(vim.api.nvim_get_option_value, 'winbar', { win = windows.input_win })
if ok and type(winbar) == 'string' and winbar ~= '' then
return 1
end

return 0
end

local function calculate_height(windows)
local total_height = vim.api.nvim_get_option_value('lines', {})
if auto_resize_enabled() then
local min_height = math.max(1, math.floor(total_height * config.ui.input.min_height))
local max_height = math.max(min_height, math.floor(total_height * config.ui.input.max_height))
local content_height = get_content_height(windows) + get_winbar_height(windows)
return math.min(max_height, math.max(min_height, content_height))
end

return math.max(1, math.floor(total_height * config.ui.input_height))
end

local function apply_dimensions(windows, height)
if config.ui.position == 'current' then
pcall(vim.api.nvim_win_set_height, windows.input_win, height)
return
end

local total_width = vim.api.nvim_get_option_value('columns', {})
local width = math.floor(total_width * config.ui.window_width)

vim.api.nvim_win_set_config(windows.input_win, { width = width, height = height })
end

function M.create_buf()
local input_buf = vim.api.nvim_create_buf(false, true)
Expand Down Expand Up @@ -226,18 +282,27 @@ function M.update_dimensions(windows)
return
end

local total_height = vim.api.nvim_get_option_value('lines', {})
local height = math.floor(total_height * config.ui.input_height)
local height = calculate_height(windows)
apply_dimensions(windows, height)
end

if config.ui.position == 'current' then
pcall(vim.api.nvim_win_set_height, windows.input_win, height)
function M.schedule_resize(windows)
if not auto_resize_enabled() then
return
end

local total_width = vim.api.nvim_get_option_value('columns', {})
local width = math.floor(total_width * config.ui.window_width)
windows = windows or state.windows
if not M.mounted(windows) or M._resize_scheduled then
return
end

vim.api.nvim_win_set_config(windows.input_win, { width = width, height = height })
M._resize_scheduled = true
vim.schedule(function()
M._resize_scheduled = false
if M.mounted(windows) then
M.update_dimensions(windows)
end
end)
end

function M.refresh_placeholder(windows, input_lines)
Expand Down Expand Up @@ -289,6 +354,7 @@ end
function M.recover_input(windows)
M.set_content(state.input_content, windows)
require('opencode.ui.mention').highlight_all_mentions(windows.input_buf)
M.update_dimensions(windows)
end

function M.focus_input()
Expand Down Expand Up @@ -406,6 +472,7 @@ function M.setup_autocmds(windows, group)
state.input_content = input_lines
M.refresh_placeholder(windows, input_lines)
require('opencode.ui.context_bar').render()
M.schedule_resize(windows)
end,
})
end
Expand Down