Repository navigation
Regression: message navigation jumps to wrong lines after #490 (session tabs) #495
Description
Description
After updating opencode.nvim from 5e89ef9 to 6071fe7, the output-window message navigation actions (prev_message, next_message, prev_user_message, next_user_message) intermittently jump to the wrong place — the cursor lands on a wrong line/message instead of the message adjacent to the current position. Before the update navigation was always accurate.
I bisected by pinning: the problem is gone when pinned to b629972 (the commit immediately before #490) and present at 6071fe7 (#490 "Wip/session tabs"), so the session-tabs rework is the likely culprit.
Suspected cause
From reading the diff of #490, renderer.on_session_changed gained an early return:
function M.on_session_changed(_, new, old)
if state.active_session_tab ~= rendered_session_tab then
return
end
...If state.active_session_tab and the renderer-local rendered_session_tab get out of sync (e.g. session_tabs clears the active tab via store.set_raw('active_session_tab', nil), which does not fire the store subscription), the renderer skips re-rendering on session change. The output buffer and render_state line numbers then still describe the previous session while state.messages holds the new one, so navigation targets computed from render_state:get_message(id).line_start land on stale/wrong lines.
Possibly also related to the renderer context snapshot/restore (ctx:snapshot() / ctx:restore()) added in the same PR.
Steps to reproduce
Intermittent ("sometimes"). In my usage it shows up in longer sessions, seemingly more often after switching sessions via the session tree and scrolling up into older messages:
- Open the opencode windows with a long session (enough messages to trigger lazy rendering)
- Switch between sessions and/or scroll up into older messages
- Trigger
prev_user_message/prev_messagerepeatedly - Occasionally the cursor lands on a wrong line instead of the previous message
Environment
- Neovim version: 0.12.2
- OpenCode version: 1.18.29
- opencode.nvim version or commit: broken at
6071fe7; works atb629972and5e89ef9 - OS: Windows 11
Configuration
opencode.nvim configuration
Relevant keymaps (the behavior is also reproducible with the default [[ / [u mappings):
require('opencode').setup({
keymap = {
output_window = {
['<C-p>'] = { 'prev_message', desc = 'Prev message' },
['<M-p>'] = { 'prev_user_message', desc = 'Prev user message' },
},
},
})Logs and screenshots
Happy to capture debug logs if you tell me what to enable.
Checklist
- I have searched existing issues.
- I have included all relevant details.
- I have removed sensitive information from configs and logs.
Activity
sudo-tee commentedon Sep 17, 2026
Thanks for all the info.
I will have a look.
wzj-zz commentedon Sep 17, 2026
Update: root cause found — #490 is likely innocent, please disregard the regression claim
I kept debugging this with runtime instrumentation and owe you a correction: the misattribution above. Two separate things were conflated:
1. The dominant cause of my "wrong jumps": snacks.scroll (config-side, not opencode.nvim)
I have
snacks.scroll(smooth scrolling) enabled. It listens toWinScrolledand animates any topline change, so when opencode's jump actions set the cursor hundreds of lines away, snacks intercepted it and animated the cursor toward the target a few lines per frame — a ~570-line jump took seconds of visible crawling, landing mid-way on a wrong-looking position. That perfectly matched the "jumps are wrong / need a wait before they work" symptom, and it also churned on every streaming flush, which likely explains most of the perceived slowdown I blamed on #490.Fix on my side: disabling snacks.scroll entirely (
scroll = { enabled = false }). Users who want to keep smooth scrolling can opt out just for the output buffer instead:With this, I'm now running
6071fe7(including #490) and navigation is instant and accurate. A short "known conflicts" note in the README (snacks.scroll / smooth-scroll plugins) might save other users the same hunt.2. A genuine renderer issue that remains: phantom entries in render_state
While instrumenting I captured a real inconsistency, present already at
b629972(so older than #490):render_statecan contain line-number entries for messages that have no rendered content in the buffer. In my capture,render_stateheld entries likeuser:1045andassistant:1047with line numbers, but the buffer had no header extmarks for those messages at all. Sincenext/prev_messagenavigation targetsrender_state:get_message(id).line_start, a jump can land on a line that corresponds to no rendered message; it self-heals once those messages actually render.Likely interaction: lazy rendering renders only the tail, while navigation walks the full ledger. Suggestion: navigation could skip messages whose rendered range doesn't exist on screen, or validate against actual extmarks.
sudo-tee commentedon Sep 18, 2026
Thanks for the info I will check the issue with phanton render_state.
Currrently there is major refactoring hapening for supporting opencode v2. I will try to sqeeze a fix to this. at the same time