|
1 | 1 | local M = {} |
2 | 2 |
|
3 | 3 | local state = require('opencode.state') |
4 | | -local formatter = require('opencode.ui.formatter') |
| 4 | +local output_window = require('opencode.ui.output_window') |
5 | 5 |
|
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 |
8 | 21 | end |
9 | 22 |
|
10 | 23 | function M.goto_next_message() |
11 | 24 | require('opencode.ui.ui').focus_output() |
12 | | - local windows = state.windows |
| 25 | + local windows = state.windows or {} |
13 | 26 | local win = windows.output_win |
14 | 27 | 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 |
16 | 32 |
|
17 | 33 | 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 }) |
27 | 49 | return |
28 | 50 | end |
29 | 51 | end |
| 52 | + |
| 53 | + local line_count = vim.api.nvim_buf_line_count(buf) |
| 54 | + vim.api.nvim_win_set_cursor(win, { line_count, 0 }) |
30 | 55 | end |
31 | 56 |
|
32 | 57 | function M.goto_prev_message() |
33 | 58 | require('opencode.ui.ui').focus_output() |
34 | | - local windows = state.windows |
| 59 | + local windows = state.windows or {} |
35 | 60 | 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 |
37 | 66 |
|
38 | 67 | 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 }) |
47 | 84 | return |
48 | 85 | end |
49 | 86 | end |
50 | | - |
51 | 87 | vim.api.nvim_win_set_cursor(win, { 1, 0 }) |
52 | | - re_focus() |
53 | 88 | end |
54 | 89 |
|
55 | 90 | return M |
0 commit comments