Skip to content

Commit b2fb303

Browse files
authored
fix(renderer): skip hidden-messages notice in message navigation (#461)
Problem: when max_messages truncates older messages, the synthetic hidden-messages notice (appended to state.messages via on_message_updated) is matched by get_prev_rendered_message, so [[ yanks the cursor to the buffer top. Solution: skip entries where is_renderer_synthetic_message is true in both get_prev_rendered_message and get_next_rendered_message.
1 parent 3f1baf4 commit b2fb303

2 files changed

Lines changed: 69 additions & 7 deletions

File tree

lua/opencode/ui/renderer.lua

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -619,10 +619,12 @@ function M.get_next_rendered_message(current_line)
619619
local next_message = nil
620620

621621
for _, message in ipairs(state.messages or {}) do
622-
local rendered = message.info and message.info.id and ctx.render_state:get_message(message.info.id) or nil
623-
if rendered and rendered.line_start and rendered.line_start + 1 > current_line then
624-
next_message = rendered
625-
break
622+
if not is_renderer_synthetic_message(message) then
623+
local rendered = message.info and message.info.id and ctx.render_state:get_message(message.info.id) or nil
624+
if rendered and rendered.line_start and rendered.line_start + 1 > current_line then
625+
next_message = rendered
626+
break
627+
end
626628
end
627629
end
628630

@@ -634,9 +636,11 @@ end
634636
function M.get_prev_rendered_message(current_line)
635637
for i = #(state.messages or {}), 1, -1 do
636638
local message = state.messages[i]
637-
local rendered = message and message.info and message.info.id and ctx.render_state:get_message(message.info.id)
638-
if rendered and rendered.line_start and rendered.line_start + 1 < current_line then
639-
return rendered
639+
if message and not is_renderer_synthetic_message(message) then
640+
local rendered = message.info and message.info.id and ctx.render_state:get_message(message.info.id)
641+
if rendered and rendered.line_start and rendered.line_start + 1 < current_line then
642+
return rendered
643+
end
640644
end
641645
end
642646

tests/unit/navigation_spec.lua

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,3 +656,61 @@ describe('navigation jumplist preservation', function()
656656
assert.equals(0, mark[2])
657657
end)
658658
end)
659+
660+
describe('navigation hidden-messages-notice handling', function()
661+
local output_buf, output_win
662+
local original_windows
663+
664+
before_each(function()
665+
original_windows = state.store.get('windows')
666+
state.ui.clear_hidden_window_state()
667+
668+
output_buf = vim.api.nvim_create_buf(false, true)
669+
output_win = vim.api.nvim_open_win(output_buf, true, {
670+
relative = 'editor',
671+
width = 80,
672+
height = 20,
673+
row = 0,
674+
col = 0,
675+
})
676+
state.ui.set_windows({ output_buf = output_buf, output_win = output_win })
677+
end)
678+
679+
after_each(function()
680+
state.ui.clear_hidden_window_state()
681+
pcall(vim.api.nvim_win_close, output_win, true)
682+
pcall(vim.api.nvim_buf_delete, output_buf, { force = true })
683+
684+
if original_windows ~= nil then
685+
state.ui.set_windows(original_windows)
686+
else
687+
state.ui.clear_windows()
688+
end
689+
end)
690+
691+
it('does not jump [[ to the hidden-messages notice when max_messages truncates', function()
692+
local ctx = require('opencode.ui.renderer.ctx')
693+
-- Simulate `on_message_updated` appending the hidden notice to `state.messages` after a `max_messages` truncation.
694+
state.renderer.set_messages({
695+
{ info = { id = 'real_old', role = 'assistant', sessionID = 's1' } },
696+
{ info = { id = 'real_mid', role = 'user', sessionID = 's1' } },
697+
{ info = { id = '__opencode_hidden_messages_notice__', role = 'system', sessionID = 's1' } },
698+
})
699+
ctx.render_state:set_message(
700+
{ info = { id = '__opencode_hidden_messages_notice__', role = 'system', sessionID = 's1' } },
701+
1,
702+
2
703+
)
704+
ctx.render_state:set_message({ info = { id = 'real_old', role = 'assistant', sessionID = 's1' } }, 4, 8)
705+
ctx.render_state:set_message({ info = { id = 'real_mid', role = 'user', sessionID = 's1' } }, 10, 18)
706+
707+
vim.api.nvim_buf_set_lines(output_buf, 0, -1, false, vim.fn['repeat']({ 'line' }, 25))
708+
-- Without the fix, [[ from line 11 would match the notice (line 1) instead of `real_old` (line 4).
709+
vim.api.nvim_win_set_cursor(output_win, { 11, 0 })
710+
711+
navigation.goto_prev_message()
712+
713+
local cursor = vim.api.nvim_win_get_cursor(output_win)
714+
assert.equals(5, cursor[1])
715+
end)
716+
end)

0 commit comments

Comments
 (0)