Skip to content
Open
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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,13 @@ require('opencode').setup({
},
output = {
filetype = 'opencode_output', -- Filetype assigned to the output buffer (default: 'opencode_output')
compact_assistant_headers = false, -- 'full' (default), 'minimal' (compact if same mode), or 'hidden' (no headers for assistant)
compact_assistant_headers = false, -- 'full' (default), 'minimal' (compact if same mode), or 'hidden' (no headers for assistant)
tools = {
show_output = true, -- Show tools output [diffs, cmd output, etc.] (default: true)
show_reasoning_output = true, -- Show reasoning/thinking steps output (default: true)
use_folds = true, -- Use folds for tool output (default: true)
folding_threshold = 5, -- Number of lines to show before folding when show_output is true (default: 5)
only_show_latest_n = nil, -- Keep the latest N lines visible below a closed fold; nil keeps the current behavior (default: nil)
folding_threshold = 25, -- Number of leading lines to keep visible before folding when show_output is true (default: 25)
},
rendering = {
markdown_debounce_ms = 250, -- Debounce time for markdown rendering on new data (default: 250ms)
Expand Down
2 changes: 2 additions & 0 deletions lua/opencode/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ M.defaults = {
show_output = true,
show_reasoning_output = true,
use_folds = true,
-- Keep the latest N lines visible below folds for long-running progress.
only_show_latest_n = 3,
-- Reduced default threshold to make small tool outputs foldable by default.
-- Users can override this in their config if they prefer the previous value.
folding_threshold = 25,
Expand Down
2 changes: 1 addition & 1 deletion lua/opencode/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@

---@class OpencodeUIOutputConfig
---@field time_format string|nil # Custom os.date format for timestamps, e.g. '%m/%d %H:%M'. Uses fixed default when nil.
---@field tools { show_output: boolean, show_reasoning_output: boolean, use_folds: boolean, folding_threshold: number }
---@field tools { show_output: boolean, show_reasoning_output: boolean, use_folds: boolean, folding_threshold: number, only_show_latest_n: integer|nil }
---@field rendering OpencodeUIOutputRenderingConfig
---@field max_messages integer|nil
---@field always_scroll_to_bottom boolean
Expand Down
18 changes: 15 additions & 3 deletions lua/opencode/ui/output.lua
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,26 @@ function Output:add_fold_with_threshold(start_line, show, use_folds)
end

local threshold = config.ui.output.tools.folding_threshold or 5
local only_show_latest_n = config.ui.output.tools.only_show_latest_n
if type(only_show_latest_n) ~= 'number' or only_show_latest_n < 1 then
only_show_latest_n = 0
else
only_show_latest_n = math.floor(only_show_latest_n)
end

local end_line = self:get_line_count()

if not show then
if end_line > start_line then
self:add_fold(start_line, end_line)
local fold_end = end_line - only_show_latest_n
if fold_end >= start_line then
self:add_fold(start_line, fold_end)
end
elseif end_line > start_line + threshold then
self:add_fold(start_line + threshold, end_line)
local fold_start = start_line + threshold
local fold_end = end_line - only_show_latest_n
if fold_end >= fold_start then
self:add_fold(fold_start, fold_end)
end
end
end

Expand Down
14 changes: 13 additions & 1 deletion lua/opencode/ui/output_window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,13 @@ function M.fold_text()
local windows = state.windows
local output_buf = windows and windows.output_buf
local line = vim.v.foldstart
local latest_n = config.ui.output.tools.only_show_latest_n

if type(latest_n) ~= 'number' or latest_n < 1 then
latest_n = nil
else
latest_n = math.floor(latest_n)
end

if not output_buf or not vim.api.nvim_buf_is_valid(output_buf) then
return vim.fn.foldtext()
Expand All @@ -355,7 +362,12 @@ function M.fold_text()
end

if line_count > 0 then
local text = string.format('▶ %d lines hidden (zo open, zc close) ◀', line_count)
local text
if latest_n then
text = string.format('▶ %d lines hidden, latest %d below (zo open, zc close) ◀', line_count, latest_n)
else
text = string.format('▶ %d lines hidden (zo open, zc close) ◀', line_count)
end
local width = vim.api.nvim_win_get_width(0)
local padding = math.max(0, math.floor((width - #text) / 2))
return string.rep('-', padding) .. text .. string.rep('-', padding)
Expand Down
94 changes: 94 additions & 0 deletions tests/unit/output_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
local config = require('opencode.config')
local Output = require('opencode.ui.output')

describe('output fold thresholds', function()
local original_config

before_each(function()
original_config = vim.deepcopy(config.values)
config.values = vim.deepcopy(config.defaults)
end)

after_each(function()
config.values = original_config
end)

it('uses the default latest-line preview when only_show_latest_n is not overridden', function()
config.setup({
ui = {
output = {
tools = {
folding_threshold = 3,
},
},
},
})

local output = Output.new()
output:add_lines({ '1', '2', '3', '4', '5', '6', '7' })

output:add_fold_with_threshold(1, true, true)

assert.same({ { from = 4, to = 4 } }, output.fold_ranges)
end)

it('preserves the current fold behavior when only_show_latest_n is explicitly disabled', function()
config.setup({
ui = {
output = {
tools = {
folding_threshold = 3,
only_show_latest_n = 0,
},
},
},
})

local output = Output.new()
output:add_lines({ '1', '2', '3', '4', '5', '6', '7' })

output:add_fold_with_threshold(1, true, true)

assert.same({ { from = 4, to = 7 } }, output.fold_ranges)
end)

it('keeps the latest lines visible below folds when output is shown', function()
config.setup({
ui = {
output = {
tools = {
folding_threshold = 3,
only_show_latest_n = 2,
},
},
},
})

local output = Output.new()
output:add_lines({ '1', '2', '3', '4', '5', '6', '7' })

output:add_fold_with_threshold(1, true, true)

assert.same({ { from = 4, to = 5 } }, output.fold_ranges)
end)

it('keeps the latest lines visible when output is otherwise hidden', function()
config.setup({
ui = {
output = {
tools = {
show_output = false,
only_show_latest_n = 2,
},
},
},
})

local output = Output.new()
output:add_lines({ '1', '2', '3', '4', '5', '6', '7' })

output:add_fold_with_threshold(1, false, true)

assert.same({ { from = 1, to = 5 } }, output.fold_ranges)
end)
end)
46 changes: 46 additions & 0 deletions tests/unit/output_window_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,52 @@ describe('output_window.setup', function()
end)
end)

describe('output_window.fold_text', function()
local buf
local win

before_each(function()
buf = vim.api.nvim_create_buf(false, true)
win = vim.api.nvim_open_win(buf, true, {
relative = 'editor',
width = 100,
height = 10,
row = 0,
col = 0,
})
state.ui.set_windows({ output_buf = buf, output_win = win })
output_window.setup({ output_buf = buf, output_win = win })
output_window.set_lines({ 'a', 'b', 'c', 'd', 'e', 'f' })
end)

after_each(function()
state.ui.set_windows(nil)
pcall(vim.api.nvim_win_close, win, true)
pcall(vim.api.nvim_buf_delete, buf, { force = true })
end)

it('mentions visible latest lines when latest preview is enabled', function()
config.setup({
ui = {
output = {
tools = {
only_show_latest_n = 2,
},
},
},
})

output_window.set_folds({ { from = 2, to = 4 } })

local text = vim.api.nvim_win_call(win, function()
vim.v.foldstart = 2
return output_window.fold_text()
end)

assert.is_truthy(text:find('3 lines hidden, latest 2 below', 1, true))
end)
end)

describe('output_window extmarks', function()
local buf

Expand Down
Loading