Skip to content

Commit b3b1ca5

Browse files
committed
fix(navigation): reimplemented without metadata
Extmarks already indicate where the messages are so I'm not sure maintaining the metadata part of output is worth it.
1 parent 6bfb8d9 commit b3b1ca5

File tree

1 file changed

+61
-26
lines changed

1 file changed

+61
-26
lines changed

lua/opencode/ui/navigation.lua

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,90 @@
11
local M = {}
22

33
local state = require('opencode.state')
4-
local formatter = require('opencode.ui.formatter')
4+
local output_window = require('opencode.ui.output_window')
55

6-
local function re_focus()
7-
vim.cmd('normal! zt')
6+
local function is_message_header(details)
7+
local icons = require('opencode.ui.icons')
8+
local header_user_icon = icons.get('header_user')
9+
local header_assistant_icon = icons.get('header_assistant')
10+
11+
if not details or not details.virt_text then
12+
return false
13+
end
14+
15+
local first_virt_text = details.virt_text[1]
16+
if not first_virt_text then
17+
return false
18+
end
19+
20+
return first_virt_text[1] == header_user_icon or first_virt_text[1] == header_assistant_icon
821
end
922

1023
function M.goto_next_message()
1124
require('opencode.ui.ui').focus_output()
12-
local windows = state.windows
25+
local windows = state.windows or {}
1326
local win = windows.output_win
1427
local buf = windows.output_buf
15-
local all_metadata = formatter.output:get_all_metadata()
28+
29+
if not win or not buf then
30+
return
31+
end
1632

1733
local current_line = vim.api.nvim_win_get_cursor(win)[1]
18-
local line_count = vim.api.nvim_buf_line_count(buf)
19-
local current = formatter.get_message_at_line(current_line)
20-
local current_idx = current and current.msg_idx or 0
21-
22-
for i = current_line, line_count do
23-
local meta = all_metadata[i]
24-
if meta and meta.msg_idx > current_idx and meta.type == 'header' then
25-
vim.api.nvim_win_set_cursor(win, { i, 0 })
26-
re_focus()
34+
35+
local extmarks = vim.api.nvim_buf_get_extmarks(
36+
buf,
37+
output_window.namespace,
38+
{ current_line, 0 },
39+
-1,
40+
{ details = true }
41+
)
42+
43+
for _, extmark in ipairs(extmarks) do
44+
local line = extmark[2] + 1
45+
local details = extmark[4]
46+
47+
if line > current_line and is_message_header(details) then
48+
vim.api.nvim_win_set_cursor(win, { line, 0 })
2749
return
2850
end
2951
end
52+
53+
local line_count = vim.api.nvim_buf_line_count(buf)
54+
vim.api.nvim_win_set_cursor(win, { line_count, 0 })
3055
end
3156

3257
function M.goto_prev_message()
3358
require('opencode.ui.ui').focus_output()
34-
local windows = state.windows
59+
local windows = state.windows or {}
3560
local win = windows.output_win
36-
local all_metadata = formatter.output:get_all_metadata()
61+
local buf = windows.output_buf
62+
63+
if not win or not buf then
64+
return
65+
end
3766

3867
local current_line = vim.api.nvim_win_get_cursor(win)[1]
39-
local current = formatter.get_message_at_line(current_line)
40-
local current_idx = current and current.msg_idx or 0
41-
42-
for i = current_line - 1, 1, -1 do
43-
local meta = all_metadata[i]
44-
if meta and meta.msg_idx < current_idx and meta.type == 'header' then
45-
vim.api.nvim_win_set_cursor(win, { i, 0 })
46-
re_focus()
68+
69+
local extmarks = vim.api.nvim_buf_get_extmarks(
70+
buf,
71+
output_window.namespace,
72+
0,
73+
{ current_line - 1, -1 },
74+
{ details = true }
75+
)
76+
77+
for i = #extmarks, 1, -1 do
78+
local extmark = extmarks[i]
79+
local line = extmark[2] + 1
80+
local details = extmark[4]
81+
82+
if line < current_line and is_message_header(details) then
83+
vim.api.nvim_win_set_cursor(win, { line, 0 })
4784
return
4885
end
4986
end
50-
5187
vim.api.nvim_win_set_cursor(win, { 1, 0 })
52-
re_focus()
5388
end
5489

5590
return M

0 commit comments

Comments
 (0)