From d6fe72c65778ab977704752b0b5c21631a94557d Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Wed, 20 May 2026 07:59:55 -0400 Subject: [PATCH 1/2] feat(ui): add multi-question navigation and tabbed question UI Add group navigation to Dialog (navigate_group, set/get_group_selection, on_navigate_group) and left/right keymaps. Update legend formatting to show key hints. Update highlight definitions for question tabs and key hints. Update question_window to track answers by question index, render tabbed question headers (showing active/done/pending state), wait until all questions are answered before sending the reply, and synchronize dialog group selection with the current question. Add unit tests covering multi-question flow, tab rendering, and navigation. --- lua/opencode/ui/dialog.lua | 115 ++++++++++++++++++++++--- lua/opencode/ui/highlight.lua | 8 ++ lua/opencode/ui/question_window.lua | 110 +++++++++++++++++++++++- tests/unit/question_window_spec.lua | 125 ++++++++++++++++++++++++++++ 4 files changed, 344 insertions(+), 14 deletions(-) diff --git a/lua/opencode/ui/dialog.lua b/lua/opencode/ui/dialog.lua index 6c3e56a5..8aa13cbb 100644 --- a/lua/opencode/ui/dialog.lua +++ b/lua/opencode/ui/dialog.lua @@ -3,7 +3,9 @@ ---@field on_select function(index: integer) Called when an option is selected ---@field on_dismiss? function() Called when dialog is dismissed ---@field on_navigate? function() Called when selection changes +---@field on_navigate_group? function(index: integer) Called when group selection changes ---@field get_option_count function(): integer Returns the total number of options +---@field get_group_count? function(): integer Returns the total number of groups ---@field check_focused? function(): boolean Returns whether dialog should be active ---@field keymaps? DialogKeymaps Custom keymap configuration ---@field namespace_prefix? string Prefix for vim.on_key namespace (default: 'opencode_dialog') @@ -12,6 +14,8 @@ ---@class DialogKeymaps ---@field up? string[] Keys for navigating up (default: {'k', ''}) ---@field down? string[] Keys for navigating down (default: {'j', ''}) +---@field left? string[] Keys for navigating left between groups +---@field right? string[] Keys for navigating right between groups ---@field select? string Key for selecting current option (default: '') ---@field dismiss? string Key for dismissing dialog (default: '') ---@field number_shortcuts? boolean Enable 1-9 number shortcuts (default: true) @@ -22,6 +26,7 @@ ---@field private _key_capture_ns integer? Namespace for vim.on_key ---@field private _selected_index integer Currently selected option index ---@field private _active boolean Whether dialog is currently active +---@field private _group_index integer Currently selected group index local Dialog = {} Dialog.__index = Dialog @@ -35,6 +40,8 @@ function Dialog.new(config) local default_keymaps = { up = { 'k', '' }, down = { 'j', '' }, + left = {}, + right = {}, select = '', dismiss = '', number_shortcuts = true, @@ -52,6 +59,7 @@ function Dialog.new(config) self._keymaps = {} self._key_capture_ns = nil self._selected_index = 1 + self._group_index = 1 self._active = false return self @@ -72,6 +80,24 @@ function Dialog:set_selection(index) end end +---@return integer +function Dialog:get_group_selection() + return self._group_index +end + +---@param index integer +function Dialog:set_group_selection(index) + local group_count = self._config.get_group_count and self._config.get_group_count() or 0 + if group_count == 0 then + self._group_index = 1 + return + end + + if index >= 1 and index <= group_count then + self._group_index = index + end +end + ---Navigate selection by delta (positive for down, negative for up) ---@param delta integer Amount to move selection function Dialog:navigate(delta) @@ -98,6 +124,28 @@ function Dialog:navigate(delta) end end +---@param delta integer +function Dialog:navigate_group(delta) + if not self._active or not self._config.check_focused() or not self._config.on_navigate_group then + return + end + + local group_count = self._config.get_group_count and self._config.get_group_count() or 0 + if group_count <= 1 then + return + end + + self._group_index = self._group_index + delta + + if self._group_index < 1 then + self._group_index = group_count + elseif self._group_index > group_count then + self._group_index = 1 + end + + self._config.on_navigate_group(self._group_index) +end + ---Select the current option function Dialog:select() if not self._active or not self._config.check_focused() then @@ -178,31 +226,42 @@ function Dialog:format_legend(output, options) end if ui.is_opencode_focused() then - local legend_parts = {} local keymaps = self._config.keymaps if not keymaps then return end if keymaps.up and #keymaps.up > 0 and keymaps.down and #keymaps.down > 0 then - table.insert(legend_parts, string.format('Navigate: `%s`/`%s` or `↑`/`↓`', keymaps.down[1], keymaps.up[1])) + local line = output:add_line(string.format('Move: j/k or %s/%s', '↑', '↓')) + output:add_extmark(line - 1, { start_col = 6, end_col = 9, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) + output:add_extmark(line - 1, { start_col = 13, end_col = 16, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) + end + + if keymaps.left and #keymaps.left > 0 and keymaps.right and #keymaps.right > 0 then + local line = output:add_line('Question: h/l or <-/->') + output:add_extmark(line - 1, { start_col = 10, end_col = 13, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) + output:add_extmark(line - 1, { start_col = 17, end_col = 23, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) end if keymaps.select and keymaps.select ~= '' then - local select_text = string.format('Select: `%s`', keymaps.select) + local select_text = 'Select: ' + if keymaps.number_shortcuts and option_count > 0 then + local max_shortcut = math.min(option_count, 9) + select_text = select_text .. string.format(' or 1-%d', max_shortcut) + end + local line = output:add_line(select_text) + output:add_extmark(line - 1, { start_col = 8, end_col = 12, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) if keymaps.number_shortcuts and option_count > 0 then local max_shortcut = math.min(option_count, 9) - select_text = select_text .. string.format(' or `1-%d`', max_shortcut) + local suffix = string.format('1-%d', max_shortcut) + local start_col = #select_text - #suffix + output:add_extmark(line - 1, { start_col = start_col, end_col = #select_text, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) end - table.insert(legend_parts, select_text) end if keymaps.dismiss and keymaps.dismiss ~= '' then - table.insert(legend_parts, string.format('Dismiss: `%s`', keymaps.dismiss)) - end - - if #legend_parts > 0 then - output:add_line(table.concat(legend_parts, ' ')) + local line = output:add_line('Close: ') + output:add_extmark(line - 1, { start_col = 7, end_col = 12, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) end else local message = options.unfocused_message or 'Focus Opencode window to interact' @@ -353,6 +412,42 @@ function Dialog:_setup_keymaps() end end + if keymaps.left then + for _, key in ipairs(keymaps.left) do + if key and key ~= '' then + vim.keymap.set( + 'n', + key, + function() + self:navigate_group(-1) + end, + vim.tbl_extend('force', keymap_opts, { + desc = 'Dialog: navigate left', + }) + ) + table.insert(self._keymaps, key) + end + end + end + + if keymaps.right then + for _, key in ipairs(keymaps.right) do + if key and key ~= '' then + vim.keymap.set( + 'n', + key, + function() + self:navigate_group(1) + end, + vim.tbl_extend('force', keymap_opts, { + desc = 'Dialog: navigate right', + }) + ) + table.insert(self._keymaps, key) + end + end + end + if keymaps.select and keymaps.select ~= '' then vim.keymap.set( 'n', diff --git a/lua/opencode/ui/highlight.lua b/lua/opencode/ui/highlight.lua index 1e5bb4c2..b92269cc 100644 --- a/lua/opencode/ui/highlight.lua +++ b/lua/opencode/ui/highlight.lua @@ -48,6 +48,10 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeQuestionOption', { link = 'Normal', default = true }) vim.api.nvim_set_hl(0, 'OpencodeQuestionBorder', { fg = '#E3F2FD', default = true }) vim.api.nvim_set_hl(0, 'OpencodeQuestionTitle', { link = '@label', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionTabActive', { bg = '#E3F2FD', fg = '#1976D2', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionTabDone', { fg = '#2E7D32', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionTabPending', { fg = '#757575', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionKeyHint', { fg = '#1976D2', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeChangedLines', { bg = '#FFF3BF', default = true }) else vim.api.nvim_set_hl(0, 'OpencodeBorder', { fg = '#616161', default = true }) @@ -92,6 +96,10 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeQuestionOption', { link = 'Normal', default = true }) vim.api.nvim_set_hl(0, 'OpencodeQuestionBorder', { fg = '#2B3A5A', default = true }) vim.api.nvim_set_hl(0, 'OpencodeQuestionTitle', { link = '@label', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionTabActive', { bg = '#2B3A5A', fg = '#61AFEF', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionTabDone', { fg = '#98C379', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionTabPending', { fg = '#7F8490', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeQuestionKeyHint', { fg = '#61AFEF', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeChangedLines', { bg = '#3D3520', default = true }) end end diff --git a/lua/opencode/ui/question_window.lua b/lua/opencode/ui/question_window.lua index 616a4edc..950537a0 100644 --- a/lua/opencode/ui/question_window.lua +++ b/lua/opencode/ui/question_window.lua @@ -13,6 +13,48 @@ M._collected_answers = {} M._answering = false M._dialog = nil +---@param index integer +---@return string[]|nil +local function get_answer_for_index(index) + local answer = M._collected_answers[index] + if type(answer) ~= 'table' or #answer == 0 then + return nil + end + return answer +end + +---@return boolean +local function has_all_answers() + local request = M._current_question + local questions = request and request.questions or {} + if #questions == 0 then + return false + end + + for i = 1, #questions do + if not get_answer_for_index(i) then + return false + end + end + + return true +end + +---@return integer|nil +local function get_next_unanswered_question_index() + local request = M._current_question + local questions = request and request.questions or {} + if #questions == 0 then + return nil + end + + for i = 1, #questions do + if not get_answer_for_index(i) then + return i + end + end +end + ---@param question_request OpencodeQuestionRequest|nil ---@return boolean function M.matches_active_question(question_request) @@ -159,8 +201,8 @@ function M.show_question(question_request) end M._current_question = question_request - M._current_question_index = 1 M._collected_answers = {} + M._current_question_index = 1 if config.ui.questions and config.ui.questions.use_vim_ui_select then M._show_question_with_vim_ui_select() @@ -245,13 +287,13 @@ local function answer_current_question(answer_value) return end - table.insert(M._collected_answers, type(answer_value) == 'table' and answer_value or { answer_value }) - M._current_question_index = M._current_question_index + 1 + M._collected_answers[M._current_question_index] = type(answer_value) == 'table' and answer_value or { answer_value } - if M._current_question_index > #request.questions then + if has_all_answers() then M._send_reply(request.id, M._collected_answers) M.clear_question() else + M._current_question_index = get_next_unanswered_question_index() or M._current_question_index M._answering = false M._clear_dialog() M._setup_dialog() @@ -329,6 +371,49 @@ local function add_other_if_missing(options) return result end +---@param output Output +local function format_question_tabs(output) + local request = M._current_question + if not request or #request.questions <= 1 then + return + end + + local line = '' + local segments = {} + + for i, question in ipairs(request.questions) do + local label = question.header ~= '' and question.header or ('Q' .. i) + local is_active = i == M._current_question_index + local is_done = get_answer_for_index(i) ~= nil + local marker = is_done and 'x' or ' ' + local segment = string.format(' %d [%s] %s ', i, marker, label) + + if #line > 0 then + line = line .. ' ' + end + + local start_col = #line + line = line .. segment + table.insert(segments, { + start_col = start_col, + end_col = #line, + hl_group = is_active and 'OpencodeQuestionTabActive' + or (is_done and 'OpencodeQuestionTabDone' or 'OpencodeQuestionTabPending'), + }) + end + + local line_idx = output:add_line(line) + for _, segment in ipairs(segments) do + output:add_extmark(line_idx - 1, { + start_col = segment.start_col, + end_col = segment.end_col, + hl_group = segment.hl_group, + } --[[@as OutputExtmark]]) + end + + output:add_line('') +end + ---@param output Output function M.format_display(output) if not M.has_question() or M._answering then @@ -347,6 +432,8 @@ function M.format_display(output) progress = string.format(' (%d/%d)', M._current_question_index, #M._current_question.questions) end + format_question_tabs(output) + -- Prepare options local options_to_display = add_other_if_missing(question_info.options) local options = {} @@ -417,6 +504,12 @@ function M._setup_dialog() render_question() end + ---@param index integer + local function on_navigate_group(index) + M._current_question_index = index + render_question() + end + ---@return integer local function get_option_count() local question_info = M.get_current_question_info() @@ -428,11 +521,20 @@ function M._setup_dialog() on_select = on_select, on_dismiss = on_dismiss, on_navigate = on_navigate, + on_navigate_group = on_navigate_group, get_option_count = get_option_count, + get_group_count = function() + return M._current_question and #M._current_question.questions or 0 + end, check_focused = check_focused, namespace_prefix = 'opencode_question', + keymaps = { + left = { 'h', '' }, + right = { 'l', '' }, + }, }) + M._dialog:set_group_selection(M._current_question_index) M._dialog:setup() end diff --git a/tests/unit/question_window_spec.lua b/tests/unit/question_window_spec.lua index e4b5f081..bfa4d506 100644 --- a/tests/unit/question_window_spec.lua +++ b/tests/unit/question_window_spec.lua @@ -17,6 +17,93 @@ describe('question_window', function() state.jobs.set_api_client(nil) end) + it('tracks answers by question index and waits until all are answered', function() + local replies = {} + + state.jobs.set_api_client({ + reply_question = function(_, request_id, answers) + table.insert(replies, { request_id = request_id, answers = answers }) + return Promise.new():resolve({}) + end, + reject_question = function() + return Promise.new():resolve({}) + end, + }) + + question_window.show_question({ + id = 'q-multi', + sessionID = 'sess1', + questions = { + { + header = 'First', + question = 'Pick first', + options = { + { label = 'One' }, + }, + }, + { + header = 'Second', + question = 'Pick second', + options = { + { label = 'Two' }, + }, + }, + }, + }) + + question_window._current_question_index = 2 + question_window._answer_with_option(1) + + assert.are.same({ { 'Two' } }, { question_window._collected_answers[2] }) + assert.are.equal(1, question_window._current_question_index) + assert.are.equal(0, #replies) + + question_window._answer_with_option(1) + + assert.are.equal(1, #replies) + assert.are.same({ { 'One' }, { 'Two' } }, replies[1].answers) + assert.is_nil(question_window._current_question) + end) + + it('renders multi-question tabs with answer status', function() + local output = Output.new() + + question_window._current_question = { + id = 'q1', + questions = { + { + header = 'Color', + question = 'Pick a color', + options = { + { label = 'Blue', description = 'cool' }, + }, + }, + { + header = 'Shape', + question = 'Pick a shape', + options = { + { label = 'Circle', description = 'round' }, + }, + }, + }, + } + question_window._current_question_index = 2 + question_window._collected_answers = { + [1] = { 'Blue' }, + } + question_window._dialog = { + format_dialog = function(_, _, opts) + output:add_line(opts.title) + end, + } + + question_window.format_display(output) + + assert.are.equal(' 1 [x] Color 2 [ ] Shape ', output.lines[1]) + assert.are.equal('OpencodeQuestionTabDone', output.extmarks[0][1].hl_group) + assert.are.equal('OpencodeQuestionTabActive', output.extmarks[0][2].hl_group) + end) + it('adds the Other option when missing', function() local captured_opts = nil question_window._current_question = { @@ -200,4 +287,42 @@ describe('question_window', function() require('opencode.ui.ui').close_windows(state.windows) end end) + + it('navigates between questions with h and l', function() + helpers.replay_setup() + state.session.set_active({ id = 'sess1' }) + vim.api.nvim_set_current_win(state.windows.output_win) + + question_window.show_question({ + id = 'q-nav-groups', + sessionID = 'sess1', + questions = { + { + header = 'First', + question = 'Pick one', + options = { + { label = 'One' }, + }, + }, + { + header = 'Second', + question = 'Pick two', + options = { + { label = 'Two' }, + }, + }, + }, + }) + + question_window._dialog:navigate_group(1) + assert.are.equal(2, question_window._current_question_index) + + question_window._dialog:navigate_group(-1) + assert.are.equal(1, question_window._current_question_index) + + question_window.clear_question() + if state.windows then + require('opencode.ui.ui').close_windows(state.windows) + end + end) end) From 9035caf1fb06df0293aaecb18d5c47af87cbe608 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 25 May 2026 07:53:27 -0400 Subject: [PATCH 2/2] feat(ui/renderer): question navigation and flush --- lua/opencode/ui/dialog.lua | 22 +- lua/opencode/ui/question_window.lua | 15 +- lua/opencode/ui/renderer/ctx.lua | 13 + lua/opencode/ui/renderer/flush.lua | 5 +- .../data/multiple-question-ask.expected.json | 536 +++++--- tests/data/permission-ask-new.expected.json | 568 ++++++--- tests/data/permission-prompt.expected.json | 336 +++-- tests/data/question-ask-other.expected.json | 531 +++++--- tests/data/question-ask.expected.json | 408 +++++-- .../shifting-and-multiple-perms.expected.json | 1082 +++++++++++------ tests/manual/README.md | 2 +- tests/manual/regenerate_expected.lua | 84 ++ tests/manual/regenerate_expected.sh | 16 +- tests/manual/renderer_replay.lua | 33 +- tests/unit/question_window_spec.lua | 3 +- 15 files changed, 2562 insertions(+), 1092 deletions(-) create mode 100644 tests/manual/regenerate_expected.lua diff --git a/lua/opencode/ui/dialog.lua b/lua/opencode/ui/dialog.lua index 8aa13cbb..78cfc238 100644 --- a/lua/opencode/ui/dialog.lua +++ b/lua/opencode/ui/dialog.lua @@ -232,36 +232,24 @@ function Dialog:format_legend(output, options) end if keymaps.up and #keymaps.up > 0 and keymaps.down and #keymaps.down > 0 then - local line = output:add_line(string.format('Move: j/k or %s/%s', '↑', '↓')) - output:add_extmark(line - 1, { start_col = 6, end_col = 9, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) - output:add_extmark(line - 1, { start_col = 13, end_col = 16, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) + local line = output:add_line('Move: `j/k` or `↑/↓`') end if keymaps.left and #keymaps.left > 0 and keymaps.right and #keymaps.right > 0 then - local line = output:add_line('Question: h/l or <-/->') - output:add_extmark(line - 1, { start_col = 10, end_col = 13, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) - output:add_extmark(line - 1, { start_col = 17, end_col = 23, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) + local line = output:add_line('Question: `h/l` or `<-/->`') end if keymaps.select and keymaps.select ~= '' then - local select_text = 'Select: ' + local select_text = 'Select: ``' if keymaps.number_shortcuts and option_count > 0 then local max_shortcut = math.min(option_count, 9) - select_text = select_text .. string.format(' or 1-%d', max_shortcut) + select_text = select_text .. string.format(' or `1-%d`', max_shortcut) end local line = output:add_line(select_text) - output:add_extmark(line - 1, { start_col = 8, end_col = 12, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) - if keymaps.number_shortcuts and option_count > 0 then - local max_shortcut = math.min(option_count, 9) - local suffix = string.format('1-%d', max_shortcut) - local start_col = #select_text - #suffix - output:add_extmark(line - 1, { start_col = start_col, end_col = #select_text, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) - end end if keymaps.dismiss and keymaps.dismiss ~= '' then - local line = output:add_line('Close: ') - output:add_extmark(line - 1, { start_col = 7, end_col = 12, hl_group = 'OpencodeQuestionKeyHint' } --[[@as OutputExtmark]]) + local line = output:add_line('Close: ``') end else local message = options.unfocused_message or 'Focus Opencode window to interact' diff --git a/lua/opencode/ui/question_window.lua b/lua/opencode/ui/question_window.lua index 950537a0..dab5be35 100644 --- a/lua/opencode/ui/question_window.lua +++ b/lua/opencode/ui/question_window.lua @@ -159,7 +159,10 @@ local function get_question_part(question_request) if question_request and question_request.sessionID and question_request.sessionID ~= '' then local render_state = require('opencode.ui.renderer.ctx').render_state - return find_matching_question_part(render_state:get_child_session_parts(question_request.sessionID), question_request) + return find_matching_question_part( + render_state:get_child_session_parts(question_request.sessionID), + question_request + ) end end @@ -226,14 +229,16 @@ function M.restore_pending_question(session_id) M.clear_question() end - return state.api_client:list_questions() + return state.api_client + :list_questions() :and_then(function(requests) if not requests or type(requests) ~= 'table' then return end for _, request in ipairs(requests) do - if request + if + request and request.questions and #request.questions > 0 and M.belongs_to_active_session(request) @@ -385,8 +390,8 @@ local function format_question_tabs(output) local label = question.header ~= '' and question.header or ('Q' .. i) local is_active = i == M._current_question_index local is_done = get_answer_for_index(i) ~= nil - local marker = is_done and 'x' or ' ' - local segment = string.format(' %d [%s] %s ', i, marker, label) + local marker = is_done and icons.get('completed') or ' ' + local segment = string.format(' %d [%s] %s ', i, label, marker) if #line > 0 then line = line .. ' ' diff --git a/lua/opencode/ui/renderer/ctx.lua b/lua/opencode/ui/renderer/ctx.lua index 204c69db..74a31598 100644 --- a/lua/opencode/ui/renderer/ctx.lua +++ b/lua/opencode/ui/renderer/ctx.lua @@ -67,4 +67,17 @@ function ctx:bulk_reset() self.bulk_folds = {} end +---@param pending? RendererCtx['pending'] +---@return boolean +function ctx:has_pending_work(pending) + pending = pending or self.pending + + return self.flush_scheduled + or self.bulk_mode + or #pending.dirty_message_order > 0 + or #pending.dirty_part_order > 0 + or #pending.removed_part_order > 0 + or #pending.removed_message_order > 0 +end + return ctx diff --git a/lua/opencode/ui/renderer/flush.lua b/lua/opencode/ui/renderer/flush.lua index 57da8fb3..d8f22092 100644 --- a/lua/opencode/ui/renderer/flush.lua +++ b/lua/opencode/ui/renderer/flush.lua @@ -402,10 +402,7 @@ local function apply_pending(pending) return false end - local has_updates = #pending.removed_part_order > 0 - or #pending.removed_message_order > 0 - or #pending.dirty_message_order > 0 - or #pending.dirty_part_order > 0 + local has_updates = ctx:has_pending_work(pending) if not has_updates then return false diff --git a/tests/data/multiple-question-ask.expected.json b/tests/data/multiple-question-ask.expected.json index 2b816f34..6d010539 100644 --- a/tests/data/multiple-question-ask.expected.json +++ b/tests/data/multiple-question-ask.expected.json @@ -1,53 +1,39 @@ { - "lines": [ - "----", - "", - "", - "[`tests/replay/renderer_spec.lua`](tests/replay/renderer_spec.lua)", - "", - "can you use the question tool and ask me a couple of questions", - "", - "----", - "", - "", - "** question** ", - "", - "----", - "", - "", - " Question (1/2)", - "", - "Which Lua testing framework do you use or prefer for your Neovim Lua plugins?", - "", - " 1. busted - Busted is the most common Lua testing framework. ", - " 2. plenary.nvim - Plenary.nvim provides unit test utilities for Neovim plugins.", - " 3. other - Other or custom test framework", - "", - "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3` Dismiss: ``", - "", - "" - ], - "timestamp": 1774895736, + "actions": [], "extmarks": [ [ 1, 1, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text_win_col": -3, "ns_id": 3, "priority": 10, - "virt_text_pos": "win_col", + "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_bfab6dbf3001ZOVHTFKR1CMUE5]", "OpencodeHint"] - ] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_bfab6dbf3001ZOVHTFKR1CMUE5]", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -55,13 +41,18 @@ 1, 0, { - "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text_hide": false, "ns_id": 3, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2026-01-26 14:30:46", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", - "virt_text": [[" 2026-01-26 14:30:46", "OpencodeHint"]] + "virt_text_repeat_linebreak": false } ], [ @@ -69,14 +60,19 @@ 2, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeMessageRoleUser"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -84,14 +80,19 @@ 3, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeMessageRoleUser"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -99,14 +100,19 @@ 4, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeMessageRoleUser"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -114,14 +120,19 @@ 5, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeMessageRoleUser"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -129,14 +140,19 @@ 6, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeMessageRoleUser"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -144,20 +160,34 @@ 8, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text_win_col": -3, "ns_id": 3, "priority": 10, - "virt_text_pos": "win_col", + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["BUILD", "OpencodeMessageRoleAssistant"], - [" gpt-4.1", "OpencodeHint"], - [" [msg_bfab6dc80001FueCN7E2691J2R]", "OpencodeHint"] - ] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "BUILD", + "OpencodeMessageRoleAssistant" + ], + [ + " gpt-4.1", + "OpencodeHint" + ], + [ + " [msg_bfab6dc80001FueCN7E2691J2R]", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -165,13 +195,18 @@ 8, 0, { - "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text_hide": false, "ns_id": 3, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2026-01-26 14:30:46", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", - "virt_text": [[" 2026-01-26 14:30:46", "OpencodeHint"]] + "virt_text_repeat_linebreak": false } ], [ @@ -179,20 +214,34 @@ 13, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text_win_col": -3, "ns_id": 3, "priority": 10, - "virt_text_pos": "win_col", + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleSystem"], - [" "], - ["SYSTEM", "OpencodeMessageRoleSystem"], - ["", "OpencodeHint"], - [" [question-display-message]", "OpencodeHint"] - ] + [ + " ", + "OpencodeMessageRoleSystem" + ], + [ + " " + ], + [ + "SYSTEM", + "OpencodeMessageRoleSystem" + ], + [ + "", + "OpencodeHint" + ], + [ + " [question-display-message]", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -200,40 +249,40 @@ 15, 0, { + "end_col": 26, + "end_right_gravity": false, + "end_row": 15, + "hl_eol": false, + "hl_group": "OpencodeQuestionTabActive", "ns_id": 3, - "right_gravity": true, - "line_hl_group": "OpencodeQuestionTitle", - "priority": 4096 + "priority": 4096, + "right_gravity": true } ], [ 12, 15, - 0, + 27, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, + "end_col": 53, + "end_right_gravity": false, + "end_row": 15, + "hl_eol": false, + "hl_group": "OpencodeQuestionTabPending", "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "right_gravity": true } ], [ 13, - 16, + 17, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, + "line_hl_group": "OpencodeQuestionTitle", "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "right_gravity": true } ], [ @@ -241,14 +290,19 @@ 17, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -256,14 +310,19 @@ 18, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -272,100 +331,263 @@ 0, { "ns_id": 3, + "priority": 4096, "right_gravity": true, - "line_hl_group": "OpencodeDialogOptionHover", - "priority": 4096 + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ 17, - 19, + 20, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ 18, - 19, - 2, + 21, + 0, { - "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text_hide": false, + "line_hl_group": "OpencodeDialogOptionHover", "ns_id": 3, "priority": 4096, - "virt_text_pos": "overlay", - "virt_text": [["› ", "OpencodeDialogOptionHover"]] + "right_gravity": true } ], [ 19, - 20, + 21, 0, { - "virt_text_hide": false, - "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ 20, 21, - 0, + 2, { - "virt_text_hide": false, + "ns_id": 3, + "priority": 4096, "right_gravity": true, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, + "virt_text": [ + [ + "› ", + "OpencodeDialogOptionHover" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "overlay", + "virt_text_repeat_linebreak": false + } + ], + [ + 21, + 22, + 0, + { "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ - 21, 22, + 23, 0, { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 23, + 24, + 0, + { + "ns_id": 3, + "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, + "virt_text_win_col": -2 + } + ], + [ + 24, + 25, + 0, + { "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ - 22, - 23, + 25, + 26, 0, { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 26, + 27, + 0, + { + "ns_id": 3, + "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, + "virt_text_win_col": -2 + } + ], + [ + 27, + 28, + 0, + { "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text": [["▌", "OpencodeQuestionBorder"]] + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ] ], - "actions": [] -} + "lines": [ + "----", + "", + "", + "[`tests/replay/renderer_spec.lua`](tests/replay/renderer_spec.lua)", + "", + "can you use the question tool and ask me a couple of questions", + "", + "----", + "", + "", + "** question** ", + "", + "----", + "", + "", + " 1 [Testing Framework?] 2 [Run Tests Approach] ", + "", + " Question (1/2)", + "", + "Which Lua testing framework do you use or prefer for your Neovim Lua plugins?", + "", + " 1. busted - Busted is the most common Lua testing framework. ", + " 2. plenary.nvim - Plenary.nvim provides unit test utilities for Neovim plugins.", + " 3. other - Other or custom test framework", + "", + "Move: `j/k` or `↑/↓`", + "Question: `h/l` or `<-/->`", + "Select: `` or `1-3`", + "Close: ``", + "", + "" + ], + "timestamp": 1779709441 +} \ No newline at end of file diff --git a/tests/data/permission-ask-new.expected.json b/tests/data/permission-ask-new.expected.json index ca4f1322..53beaea1 100644 --- a/tests/data/permission-ask-new.expected.json +++ b/tests/data/permission-ask-new.expected.json @@ -1,4 +1,5 @@ { + "actions": [], "extmarks": [ [ 1, @@ -6,19 +7,33 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "virt_text_win_col": -3, "priority": 10, + "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_b8e7c60a2001Kisjwk2mVB4dye]", "OpencodeHint"] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_b8e7c60a2001Kisjwk2mVB4dye]", + "OpencodeHint" + ] ], - "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -27,12 +42,17 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "priority": 9, - "virt_text": [[" 2026-01-05 14:07:54", "OpencodeHint"]], "right_gravity": true, - "virt_text_pos": "right_align" + "virt_text": [ + [ + " 2026-01-05 14:07:54", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "right_align", + "virt_text_repeat_linebreak": false } ], [ @@ -41,13 +61,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -56,13 +81,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -71,13 +101,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -86,13 +121,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -101,13 +141,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -116,13 +161,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -131,13 +181,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -3, "priority": 4096, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -146,19 +201,33 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "virt_text_win_col": -3, "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["BUILD", "OpencodeMessageRoleAssistant"], - [" gpt-4.1", "OpencodeHint"], - [" [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "BUILD", + "OpencodeMessageRoleAssistant" + ], + [ + " gpt-4.1", + "OpencodeHint" + ], + [ + " [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]", + "OpencodeHint" + ] ], - "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -167,12 +236,17 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "priority": 9, - "virt_text": [[" 2026-01-05 14:07:54", "OpencodeHint"]], "right_gravity": true, - "virt_text_pos": "right_align" + "virt_text": [ + [ + " 2026-01-05 14:07:54", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "right_align", + "virt_text_repeat_linebreak": false } ], [ @@ -181,13 +255,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -1, "priority": 4096, - "virt_text": [["▌", "OpencodeToolBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -1 } ], [ @@ -196,13 +275,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -1, "priority": 4096, - "virt_text": [["▌", "OpencodeToolBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -1 } ], [ @@ -211,13 +295,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -1, "priority": 4096, - "virt_text": [["▌", "OpencodeToolBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -1 } ], [ @@ -226,13 +315,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -1, "priority": 4096, - "virt_text": [["▌", "OpencodeToolBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -1 } ], [ @@ -241,13 +335,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -1, "priority": 4096, - "virt_text": [["▌", "OpencodeToolBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -1 } ], [ @@ -256,13 +355,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -1, "priority": 4096, - "virt_text": [["▌", "OpencodeToolBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -1 } ], [ @@ -271,19 +375,33 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "virt_text_win_col": -3, "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleSystem"], - [" "], - ["SYSTEM", "OpencodeMessageRoleSystem"], - ["", "OpencodeHint"], - [" [permission-display-message]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleSystem" + ], + [ + " " + ], + [ + "SYSTEM", + "OpencodeMessageRoleSystem" + ], + [ + "", + "OpencodeHint" + ], + [ + " [permission-display-message]", + "OpencodeHint" + ] ], - "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -291,10 +409,10 @@ 22, 0, { - "ns_id": 3, "line_hl_group": "OpencodePermissionTitle", - "right_gravity": true, - "priority": 4096 + "ns_id": 3, + "priority": 4096, + "right_gravity": true } ], [ @@ -303,13 +421,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -318,13 +441,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -333,13 +461,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -348,13 +481,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -363,13 +501,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -378,13 +521,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -393,13 +541,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -408,13 +561,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -422,10 +580,10 @@ 30, 0, { - "ns_id": 3, "line_hl_group": "OpencodeDialogOptionHover", - "right_gravity": true, - "priority": 4096 + "ns_id": 3, + "priority": 4096, + "right_gravity": true } ], [ @@ -434,13 +592,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -449,12 +612,17 @@ 2, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "priority": 4096, - "virt_text": [["› ", "OpencodeDialogOptionHover"]], "right_gravity": true, - "virt_text_pos": "overlay" + "virt_text": [ + [ + "› ", + "OpencodeDialogOptionHover" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "overlay", + "virt_text_repeat_linebreak": false } ], [ @@ -463,13 +631,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -478,13 +651,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -493,13 +671,18 @@ 0, { "ns_id": 3, - "virt_text_hide": false, - "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -508,13 +691,38 @@ 0, { "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, - "virt_text_win_col": -2, + "virt_text_win_col": -2 + } + ], + [ + 35, + 35, + 0, + { + "ns_id": 3, "priority": 4096, - "virt_text": [["▌", "OpencodePermissionBorder"]], "right_gravity": true, - "virt_text_pos": "win_col" + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ] ], @@ -553,10 +761,10 @@ " 2. Reject", " 3. Allow always", "", - "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`", + "Move: `j/k` or `↑/↓`", + "Select: `` or `1-3`", "", "" ], - "timestamp": 1774895766, - "actions": [] -} + "timestamp": 1779709441 +} \ No newline at end of file diff --git a/tests/data/permission-prompt.expected.json b/tests/data/permission-prompt.expected.json index a2f7df03..780c5d47 100644 --- a/tests/data/permission-prompt.expected.json +++ b/tests/data/permission-prompt.expected.json @@ -1,4 +1,5 @@ { + "actions": [], "extmarks": [ [ 1, @@ -8,17 +9,31 @@ "ns_id": 3, "priority": 10, "right_gravity": true, - "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "virt_text_repeat_linebreak": false, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["PLAN", "OpencodeMessageRoleAssistant"], - [" claude-sonnet-4.5", "OpencodeHint"], - [" [msg_9eb45fbe60020xE560OGH3Vdoo]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "PLAN", + "OpencodeMessageRoleAssistant" + ], + [ + " claude-sonnet-4.5", + "OpencodeHint" + ], + [ + " [msg_9eb45fbe60020xE560OGH3Vdoo]", + "OpencodeHint" + ] ], - "virt_text_hide": false + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -28,11 +43,16 @@ { "ns_id": 3, "priority": 9, - "virt_text_pos": "right_align", "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text": [[" 2025-10-16 04:27:36", "OpencodeHint"]], - "virt_text_hide": false + "virt_text": [ + [ + " 2025-10-16 04:27:36", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "right_align", + "virt_text_repeat_linebreak": false } ], [ @@ -43,11 +63,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -1, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodeToolBorder"]], - "virt_text_hide": false + "virt_text_win_col": -1 } ], [ @@ -58,11 +83,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -1, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodeToolBorder"]], - "virt_text_hide": false + "virt_text_win_col": -1 } ], [ @@ -73,11 +103,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -1, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodeToolBorder"]], - "virt_text_hide": false + "virt_text_win_col": -1 } ], [ @@ -88,11 +123,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -1, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodeToolBorder"]], - "virt_text_hide": false + "virt_text_win_col": -1 } ], [ @@ -103,11 +143,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -1, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodeToolBorder"]], - "virt_text_hide": false + "virt_text_win_col": -1 } ], [ @@ -118,11 +163,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeToolBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -1, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodeToolBorder"]], - "virt_text_hide": false + "virt_text_win_col": -1 } ], [ @@ -133,17 +183,31 @@ "ns_id": 3, "priority": 10, "right_gravity": true, - "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "virt_text_repeat_linebreak": false, "virt_text": [ - [" ", "OpencodeMessageRoleSystem"], - [" "], - ["SYSTEM", "OpencodeMessageRoleSystem"], - ["", "OpencodeHint"], - [" [permission-display-message]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleSystem" + ], + [ + " " + ], + [ + "SYSTEM", + "OpencodeMessageRoleSystem" + ], + [ + "", + "OpencodeHint" + ], + [ + " [permission-display-message]", + "OpencodeHint" + ] ], - "virt_text_hide": false + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -151,10 +215,10 @@ 15, 0, { - "right_gravity": true, + "line_hl_group": "OpencodePermissionTitle", "ns_id": 3, "priority": 4096, - "line_hl_group": "OpencodePermissionTitle" + "right_gravity": true } ], [ @@ -165,11 +229,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -180,11 +249,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -195,11 +269,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -210,11 +289,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -225,11 +309,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -240,11 +329,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -255,11 +349,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -270,11 +369,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -282,10 +386,10 @@ 23, 0, { - "right_gravity": true, + "line_hl_group": "OpencodeDialogOptionHover", "ns_id": 3, "priority": 4096, - "line_hl_group": "OpencodeDialogOptionHover" + "right_gravity": true } ], [ @@ -296,11 +400,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -310,11 +419,16 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "overlay", "right_gravity": true, - "virt_text_repeat_linebreak": false, - "virt_text": [["› ", "OpencodeDialogOptionHover"]], - "virt_text_hide": false + "virt_text": [ + [ + "› ", + "OpencodeDialogOptionHover" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "overlay", + "virt_text_repeat_linebreak": false } ], [ @@ -325,11 +439,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -340,11 +459,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -355,11 +479,16 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ], [ @@ -370,15 +499,39 @@ "ns_id": 3, "priority": 4096, "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 26, + 28, + 0, + { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, "virt_text_repeat_linebreak": true, - "virt_text": [["▌", "OpencodePermissionBorder"]], - "virt_text_hide": false + "virt_text_win_col": -2 } ] ], - "actions": [], "lines": [ "----", "", @@ -407,9 +560,10 @@ " 2. Reject", " 3. Allow always", "", - "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`", + "Move: `j/k` or `↑/↓`", + "Select: `` or `1-3`", "", "" ], - "timestamp": 1774895766 -} + "timestamp": 1779709441 +} \ No newline at end of file diff --git a/tests/data/question-ask-other.expected.json b/tests/data/question-ask-other.expected.json index 475e1c70..328d39c9 100644 --- a/tests/data/question-ask-other.expected.json +++ b/tests/data/question-ask-other.expected.json @@ -1,35 +1,4 @@ { - "lines": [ - "----", - "", - "", - "[`docker-compose.yaml`](docker-compose.yaml)", - "", - "starting today, minIO is no longer maintained. can we migrate to something else, e.g. rustfs?", - "", - "----", - "", - "", - "I need to clarify a couple of things before we proceed with the migration:", - "", - "** question** ", - "", - "----", - "", - "", - " Question", - "", - "Did you mean RustyFS or perhaps a different storage solution? RustyFS appears to be a FUSE filesystem implementation. For S3-compatible object storage (MinIO replacement), common alternatives are SeaweedFS, LocalStack S3, or simply using local filesystem storage. Which would you prefer?", - "", - " 1. Local filesystem storage - Store files directly on disk, simpler setup, no S3 protocol needed ", - " 2. SeaweedFS - S3-compatible distributed storage, good MinIO alternative", - " 3. LocalStack S3 - AWS S3 emulator for local development", - " 4. Other S3-compatible solution - Different S3-compatible storage backend", - "", - "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-4` Dismiss: ``", - "", - "" - ], "actions": [], "extmarks": [ [ @@ -37,20 +6,34 @@ 1, 0, { - "priority": 10, - "virt_text_repeat_linebreak": false, "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_c595d93bb001YP4s8b1oxCvGev]", "OpencodeHint"] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_c595d93bb001YP4s8b1oxCvGev]", + "OpencodeHint" + ] ], - "virt_text_pos": "win_col", "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -58,13 +41,18 @@ 1, 0, { - "virt_text_repeat_linebreak": false, - "right_gravity": true, + "ns_id": 3, "priority": 9, - "virt_text": [[" 2026-02-13 23:37:10", "OpencodeHint"]], + "right_gravity": true, + "virt_text": [ + [ + " 2026-02-13 23:37:10", + "OpencodeHint" + ] + ], "virt_text_hide": false, "virt_text_pos": "right_align", - "ns_id": 3 + "virt_text_repeat_linebreak": false } ], [ @@ -72,14 +60,19 @@ 2, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -87,14 +80,19 @@ 3, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -102,14 +100,19 @@ 4, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -117,14 +120,19 @@ 5, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -132,14 +140,19 @@ 6, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -147,20 +160,34 @@ 8, 0, { - "priority": 10, - "virt_text_repeat_linebreak": false, "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["BUILD", "OpencodeMessageRoleAssistant"], - [" claude-sonnet-4-5", "OpencodeHint"], - [" [msg_c595d93ce001BDc0RIyyN71asg]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "BUILD", + "OpencodeMessageRoleAssistant" + ], + [ + " claude-sonnet-4-5", + "OpencodeHint" + ], + [ + " [msg_c595d93ce001BDc0RIyyN71asg]", + "OpencodeHint" + ] ], - "virt_text_pos": "win_col", "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -168,13 +195,18 @@ 8, 0, { - "virt_text_repeat_linebreak": false, - "right_gravity": true, + "ns_id": 3, "priority": 9, - "virt_text": [[" 2026-02-13 23:37:10", "OpencodeHint"]], + "right_gravity": true, + "virt_text": [ + [ + " 2026-02-13 23:37:10", + "OpencodeHint" + ] + ], "virt_text_hide": false, "virt_text_pos": "right_align", - "ns_id": 3 + "virt_text_repeat_linebreak": false } ], [ @@ -182,20 +214,34 @@ 15, 0, { - "priority": 10, - "virt_text_repeat_linebreak": false, "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleSystem"], - [" "], - ["SYSTEM", "OpencodeMessageRoleSystem"], - ["", "OpencodeHint"], - [" [question-display-message]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleSystem" + ], + [ + " " + ], + [ + "SYSTEM", + "OpencodeMessageRoleSystem" + ], + [ + "", + "OpencodeHint" + ], + [ + " [question-display-message]", + "OpencodeHint" + ] ], - "virt_text_pos": "win_col", "virt_text_hide": false, - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -203,10 +249,10 @@ 17, 0, { - "priority": 4096, - "right_gravity": true, + "line_hl_group": "OpencodeQuestionTitle", "ns_id": 3, - "line_hl_group": "OpencodeQuestionTitle" + "priority": 4096, + "right_gravity": true } ], [ @@ -214,14 +260,19 @@ 17, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -229,14 +280,19 @@ 18, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -244,14 +300,19 @@ 19, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -259,14 +320,19 @@ 20, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -274,10 +340,10 @@ 21, 0, { - "priority": 4096, - "right_gravity": true, + "line_hl_group": "OpencodeDialogOptionHover", "ns_id": 3, - "line_hl_group": "OpencodeDialogOptionHover" + "priority": 4096, + "right_gravity": true } ], [ @@ -285,14 +351,19 @@ 21, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -300,13 +371,18 @@ 21, 2, { - "virt_text_repeat_linebreak": false, - "right_gravity": true, + "ns_id": 3, "priority": 4096, - "virt_text": [["› ", "OpencodeDialogOptionHover"]], + "right_gravity": true, + "virt_text": [ + [ + "› ", + "OpencodeDialogOptionHover" + ] + ], "virt_text_hide": false, "virt_text_pos": "overlay", - "ns_id": 3 + "virt_text_repeat_linebreak": false } ], [ @@ -314,14 +390,19 @@ 22, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -329,14 +410,19 @@ 23, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -344,14 +430,19 @@ 24, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -359,14 +450,19 @@ 25, 0, { - "priority": 4096, - "virt_text_repeat_linebreak": true, "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], - "virt_text_pos": "win_col", + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -374,16 +470,115 @@ 26, 0, { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 24, + 27, + 0, + { + "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 25, + 28, + 0, + { "ns_id": 3, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 26, + 29, + 0, + { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ] ], - "timestamp": 1774895736 -} + "lines": [ + "----", + "", + "", + "[`docker-compose.yaml`](docker-compose.yaml)", + "", + "starting today, minIO is no longer maintained. can we migrate to something else, e.g. rustfs?", + "", + "----", + "", + "", + "I need to clarify a couple of things before we proceed with the migration:", + "", + "** question** ", + "", + "----", + "", + "", + " Question", + "", + "Did you mean RustyFS or perhaps a different storage solution? RustyFS appears to be a FUSE filesystem implementation. For S3-compatible object storage (MinIO replacement), common alternatives are SeaweedFS, LocalStack S3, or simply using local filesystem storage. Which would you prefer?", + "", + " 1. Local filesystem storage - Store files directly on disk, simpler setup, no S3 protocol needed ", + " 2. SeaweedFS - S3-compatible distributed storage, good MinIO alternative", + " 3. LocalStack S3 - AWS S3 emulator for local development", + " 4. Other S3-compatible solution - Different S3-compatible storage backend", + "", + "Move: `j/k` or `↑/↓`", + "Question: `h/l` or `<-/->`", + "Select: `` or `1-4`", + "Close: ``", + "", + "" + ], + "timestamp": 1779709441 +} \ No newline at end of file diff --git a/tests/data/question-ask.expected.json b/tests/data/question-ask.expected.json index bade2f1f..16c74cc4 100644 --- a/tests/data/question-ask.expected.json +++ b/tests/data/question-ask.expected.json @@ -1,34 +1,5 @@ { "actions": [], - "lines": [ - "----", - "", - "", - "[`lua/opencode/ui/renderer.lua`](lua/opencode/ui/renderer.lua)", - "", - "can you use the question tool and ask me a question with an other choice", - "", - "----", - "", - "", - "** question** ", - "", - "----", - "", - "", - " Question", - "", - "What is your favorite color?", - "", - " 1. Red - The color red ", - " 2. Blue - The color blue", - " 3. Other - Any color not listed", - "", - "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3` Dismiss: ``", - "", - "" - ], - "timestamp": 1774895736, "extmarks": [ [ 1, @@ -37,16 +8,30 @@ { "ns_id": 3, "priority": 10, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_bfaa078a2001RUYhlKZhSlyWeF]", "OpencodeHint"] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_bfaa078a2001RUYhlKZhSlyWeF]", + "OpencodeHint" + ] ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": false, "virt_text_win_col": -3 } @@ -57,12 +42,17 @@ 0, { "ns_id": 3, - "virt_text_pos": "right_align", - "virt_text_hide": false, - "right_gravity": true, "priority": 9, - "virt_text_repeat_linebreak": false, - "virt_text": [[" 2026-01-26 14:06:19", "OpencodeHint"]] + "right_gravity": true, + "virt_text": [ + [ + " 2026-01-26 14:06:19", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "right_align", + "virt_text_repeat_linebreak": false } ], [ @@ -72,10 +62,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -3 } @@ -87,10 +82,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -3 } @@ -102,10 +102,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -3 } @@ -117,10 +122,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -3 } @@ -132,10 +142,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeMessageRoleUser"]], + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -3 } @@ -147,16 +162,30 @@ { "ns_id": 3, "priority": 10, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["BUILD", "OpencodeMessageRoleAssistant"], - [" gpt-4.1", "OpencodeHint"], - [" [msg_bfaa078e7001qc33BqBlqzHv8X]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "BUILD", + "OpencodeMessageRoleAssistant" + ], + [ + " gpt-4.1", + "OpencodeHint" + ], + [ + " [msg_bfaa078e7001qc33BqBlqzHv8X]", + "OpencodeHint" + ] ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": false, "virt_text_win_col": -3 } @@ -167,12 +196,17 @@ 0, { "ns_id": 3, - "virt_text_pos": "right_align", - "virt_text_hide": false, - "right_gravity": true, "priority": 9, - "virt_text_repeat_linebreak": false, - "virt_text": [[" 2026-01-26 14:06:19", "OpencodeHint"]] + "right_gravity": true, + "virt_text": [ + [ + " 2026-01-26 14:06:19", + "OpencodeHint" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "right_align", + "virt_text_repeat_linebreak": false } ], [ @@ -182,16 +216,30 @@ { "ns_id": 3, "priority": 10, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleSystem"], - [" "], - ["SYSTEM", "OpencodeMessageRoleSystem"], - ["", "OpencodeHint"], - [" [question-display-message]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleSystem" + ], + [ + " " + ], + [ + "SYSTEM", + "OpencodeMessageRoleSystem" + ], + [ + "", + "OpencodeHint" + ], + [ + " [question-display-message]", + "OpencodeHint" + ] ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": false, "virt_text_win_col": -3 } @@ -201,9 +249,9 @@ 15, 0, { + "line_hl_group": "OpencodeQuestionTitle", "ns_id": 3, "priority": 4096, - "line_hl_group": "OpencodeQuestionTitle", "right_gravity": true } ], @@ -214,10 +262,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -229,10 +282,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -244,10 +302,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -259,10 +322,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -272,9 +340,9 @@ 19, 0, { + "line_hl_group": "OpencodeDialogOptionHover", "ns_id": 3, "priority": 4096, - "line_hl_group": "OpencodeDialogOptionHover", "right_gravity": true } ], @@ -285,10 +353,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -299,12 +372,17 @@ 2, { "ns_id": 3, - "virt_text_pos": "overlay", - "virt_text_hide": false, - "right_gravity": true, "priority": 4096, - "virt_text_repeat_linebreak": false, - "virt_text": [["› ", "OpencodeDialogOptionHover"]] + "right_gravity": true, + "virt_text": [ + [ + "› ", + "OpencodeDialogOptionHover" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "overlay", + "virt_text_repeat_linebreak": false } ], [ @@ -314,10 +392,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -329,10 +412,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -344,10 +432,15 @@ { "ns_id": 3, "priority": 4096, - "virt_text_pos": "win_col", - "virt_text_hide": false, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } @@ -359,13 +452,110 @@ { "ns_id": 3, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 23, + 24, + 0, + { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 24, + 25, + 0, + { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], "virt_text_hide": false, + "virt_text_pos": "win_col", + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 25, + 26, + 0, + { + "ns_id": 3, + "priority": 4096, "right_gravity": true, - "virt_text": [["▌", "OpencodeQuestionBorder"]], + "virt_text": [ + [ + "▌", + "OpencodeQuestionBorder" + ] + ], + "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, "virt_text_win_col": -2 } ] - ] -} + ], + "lines": [ + "----", + "", + "", + "[`lua/opencode/ui/renderer.lua`](lua/opencode/ui/renderer.lua)", + "", + "can you use the question tool and ask me a question with an other choice", + "", + "----", + "", + "", + "** question** ", + "", + "----", + "", + "", + " Question", + "", + "What is your favorite color?", + "", + " 1. Red - The color red ", + " 2. Blue - The color blue", + " 3. Other - Any color not listed", + "", + "Move: `j/k` or `↑/↓`", + "Question: `h/l` or `<-/->`", + "Select: `` or `1-3`", + "Close: ``", + "", + "" + ], + "timestamp": 1779709441 +} \ No newline at end of file diff --git a/tests/data/shifting-and-multiple-perms.expected.json b/tests/data/shifting-and-multiple-perms.expected.json index 832d0cba..9d372b44 100644 --- a/tests/data/shifting-and-multiple-perms.expected.json +++ b/tests/data/shifting-and-multiple-perms.expected.json @@ -6,20 +6,34 @@ 1, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_9efb39d68001J2h30a50B2774b]", "OpencodeHint"] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_9efb39d68001J2h30a50B2774b]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -27,11 +41,16 @@ 1, 0, { - "virt_text": [[" 2025-10-17 01:05:49", "OpencodeHint"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2025-10-17 01:05:49", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", "virt_text_repeat_linebreak": false } @@ -41,14 +60,19 @@ 2, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -56,14 +80,19 @@ 3, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -71,14 +100,19 @@ 4, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -86,14 +120,19 @@ 5, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -101,20 +140,34 @@ 8, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["PLAN", "OpencodeMessageRoleAssistant"], - [" claude-sonnet-4.5", "OpencodeHint"], - [" [msg_9efb39dc3002f81rMRqF2WO1UU]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "PLAN", + "OpencodeMessageRoleAssistant" + ], + [ + " claude-sonnet-4.5", + "OpencodeHint" + ], + [ + " [msg_9efb39dc3002f81rMRqF2WO1UU]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -122,11 +175,16 @@ 8, 0, { - "virt_text": [[" 2025-10-17 01:05:50", "OpencodeHint"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2025-10-17 01:05:50", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", "virt_text_repeat_linebreak": false } @@ -136,20 +194,34 @@ 83, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_9efb50a0b001WFK7AMDV45cF8Z]", "OpencodeHint"] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_9efb50a0b001WFK7AMDV45cF8Z]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -157,11 +229,16 @@ 83, 0, { - "virt_text": [[" 2025-10-17 01:07:23", "OpencodeHint"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2025-10-17 01:07:23", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", "virt_text_repeat_linebreak": false } @@ -171,14 +248,19 @@ 84, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -186,14 +268,19 @@ 85, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -201,20 +288,34 @@ 88, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["PLAN", "OpencodeMessageRoleAssistant"], - [" claude-sonnet-4.5", "OpencodeHint"], - [" [msg_9efb50a2a002dzMgbQnasd86o1]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "PLAN", + "OpencodeMessageRoleAssistant" + ], + [ + " claude-sonnet-4.5", + "OpencodeHint" + ], + [ + " [msg_9efb50a2a002dzMgbQnasd86o1]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -222,11 +323,16 @@ 88, 0, { - "virt_text": [[" 2025-10-17 01:07:23", "OpencodeHint"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2025-10-17 01:07:23", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", "virt_text_repeat_linebreak": false } @@ -236,20 +342,34 @@ 111, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - ["▌󰭻 ", "OpencodeMessageRoleUser"], - [" "], - ["USER", "OpencodeMessageRoleUser"], - ["", "OpencodeHint"], - [" [msg_9efb59d93001LSm9y0DS9p8cP6]", "OpencodeHint"] + [ + "▌󰭻 ", + "OpencodeMessageRoleUser" + ], + [ + " " + ], + [ + "USER", + "OpencodeMessageRoleUser" + ], + [ + "", + "OpencodeHint" + ], + [ + " [msg_9efb59d93001LSm9y0DS9p8cP6]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -257,11 +377,16 @@ 111, 0, { - "virt_text": [[" 2025-10-17 01:08:01", "OpencodeHint"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2025-10-17 01:08:01", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", "virt_text_repeat_linebreak": false } @@ -271,14 +396,19 @@ 112, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -286,14 +416,19 @@ 113, 0, { - "virt_text": [["▌", "OpencodeMessageRoleUser"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodeMessageRoleUser" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -3 } ], [ @@ -301,20 +436,34 @@ 116, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleAssistant"], - [" "], - ["PLAN", "OpencodeMessageRoleAssistant"], - [" claude-sonnet-4.5", "OpencodeHint"], - [" [msg_9efb59db4002uWmyFRTjRIhIaQ]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleAssistant" + ], + [ + " " + ], + [ + "PLAN", + "OpencodeMessageRoleAssistant" + ], + [ + " claude-sonnet-4.5", + "OpencodeHint" + ], + [ + " [msg_9efb59db4002uWmyFRTjRIhIaQ]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -322,11 +471,16 @@ 116, 0, { - "virt_text": [[" 2025-10-17 01:08:01", "OpencodeHint"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 9, + "right_gravity": true, + "virt_text": [ + [ + " 2025-10-17 01:08:01", + "OpencodeHint" + ] + ], + "virt_text_hide": false, "virt_text_pos": "right_align", "virt_text_repeat_linebreak": false } @@ -336,20 +490,34 @@ 125, 0, { + "ns_id": 3, + "priority": 10, + "right_gravity": true, "virt_text": [ - [" ", "OpencodeMessageRoleSystem"], - [" "], - ["SYSTEM", "OpencodeMessageRoleSystem"], - ["", "OpencodeHint"], - [" [permission-display-message]", "OpencodeHint"] + [ + " ", + "OpencodeMessageRoleSystem" + ], + [ + " " + ], + [ + "SYSTEM", + "OpencodeMessageRoleSystem" + ], + [ + "", + "OpencodeHint" + ], + [ + " [permission-display-message]", + "OpencodeHint" + ] ], - "priority": 10, - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, "virt_text_pos": "win_col", - "virt_text_win_col": -3, - "right_gravity": true + "virt_text_repeat_linebreak": false, + "virt_text_win_col": -3 } ], [ @@ -357,10 +525,10 @@ 127, 0, { - "right_gravity": true, - "ns_id": 3, "line_hl_group": "OpencodePermissionTitle", - "priority": 4096 + "ns_id": 3, + "priority": 4096, + "right_gravity": true } ], [ @@ -368,14 +536,19 @@ 127, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -383,14 +556,19 @@ 128, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -398,14 +576,19 @@ 129, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -413,14 +596,19 @@ 130, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -428,14 +616,19 @@ 131, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -443,14 +636,19 @@ 132, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -458,20 +656,29 @@ 133, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 134, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["11", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "11", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 134, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -479,14 +686,19 @@ 133, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -494,20 +706,29 @@ 134, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 135, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["12", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "12", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 135, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -515,14 +736,19 @@ 134, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -530,20 +756,29 @@ 135, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 136, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["13", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "13", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 136, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -551,14 +786,19 @@ 135, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -566,20 +806,29 @@ 136, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 137, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["14", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "14", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 137, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -587,14 +836,19 @@ 136, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -602,22 +856,31 @@ 137, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 138, + "hl_eol": true, + "hl_group": "OpencodeDiffAdd", + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["15", "OpencodeDiffAddGutter"], - ["+", "OpencodeDiffAddGutter"], - [" ", "OpencodeDiffAddGutter"] + [ + "15", + "OpencodeDiffAddGutter" + ], + [ + "+", + "OpencodeDiffAddGutter" + ], + [ + " ", + "OpencodeDiffAddGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "hl_group": "OpencodeDiffAdd", "virt_text_pos": "overlay", - "end_right_gravity": false, - "priority": 5000, - "virt_text_repeat_linebreak": false, - "right_gravity": true, - "end_row": 138, - "end_col": 0, - "hl_eol": true + "virt_text_repeat_linebreak": false } ], [ @@ -625,14 +888,19 @@ 137, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -640,20 +908,29 @@ 138, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 139, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["16", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "16", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 139, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -661,14 +938,19 @@ 138, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -676,20 +958,29 @@ 139, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 140, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["17", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "17", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 140, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -697,14 +988,19 @@ 139, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -712,20 +1008,29 @@ 140, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 141, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["18", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "18", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 141, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -733,14 +1038,19 @@ 140, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -748,20 +1058,29 @@ 141, 0, { + "end_col": 0, + "end_right_gravity": false, + "end_row": 142, + "ns_id": 3, + "priority": 5000, + "right_gravity": true, "virt_text": [ - ["19", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"], - [" ", "OpencodeDiffGutter"] + [ + "19", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ], + [ + " ", + "OpencodeDiffGutter" + ] ], - "ns_id": 3, "virt_text_hide": false, - "virt_text_repeat_linebreak": false, - "priority": 5000, "virt_text_pos": "overlay", - "right_gravity": true, - "end_row": 142, - "end_col": 0, - "end_right_gravity": false + "virt_text_repeat_linebreak": false } ], [ @@ -769,14 +1088,19 @@ 141, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -784,14 +1108,19 @@ 142, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -799,14 +1128,19 @@ 143, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -814,14 +1148,19 @@ 144, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -829,10 +1168,10 @@ 145, 0, { - "right_gravity": true, - "ns_id": 3, "line_hl_group": "OpencodeDialogOptionHover", - "priority": 4096 + "ns_id": 3, + "priority": 4096, + "right_gravity": true } ], [ @@ -840,14 +1179,19 @@ 145, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -855,11 +1199,16 @@ 145, 2, { - "virt_text": [["› ", "OpencodeDialogOptionHover"]], "ns_id": 3, - "virt_text_hide": false, - "right_gravity": true, "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "› ", + "OpencodeDialogOptionHover" + ] + ], + "virt_text_hide": false, "virt_text_pos": "overlay", "virt_text_repeat_linebreak": false } @@ -869,14 +1218,19 @@ 146, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -884,14 +1238,19 @@ 147, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -899,14 +1258,19 @@ 148, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, - "virt_text_repeat_linebreak": true, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ], [ @@ -914,14 +1278,39 @@ 149, 0, { - "virt_text": [["▌", "OpencodePermissionBorder"]], - "priority": 4096, "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], "virt_text_hide": false, + "virt_text_pos": "win_col", "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 + } + ], + [ + 57, + 150, + 0, + { + "ns_id": 3, + "priority": 4096, + "right_gravity": true, + "virt_text": [ + [ + "▌", + "OpencodePermissionBorder" + ] + ], + "virt_text_hide": false, "virt_text_pos": "win_col", - "virt_text_win_col": -2, - "right_gravity": true + "virt_text_repeat_linebreak": true, + "virt_text_win_col": -2 } ] ], @@ -1075,9 +1464,10 @@ " 2. Reject", " 3. Allow always", "", - "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`", + "Move: `j/k` or `↑/↓`", + "Select: `` or `1-3`", "", "" ], - "timestamp": 1774895737 -} + "timestamp": 1779709441 +} \ No newline at end of file diff --git a/tests/manual/README.md b/tests/manual/README.md index 8f8aa725..75478034 100644 --- a/tests/manual/README.md +++ b/tests/manual/README.md @@ -28,7 +28,7 @@ Once loaded, you can use these commands in Neovim: - `:ReplayStop` - Stop auto-replay - `:ReplayReset` - Reset to the beginning (clears buffer and resets event index) - `:ReplayClear` - Clear output buffer without resetting event index -- `:ReplaySave [file]` - Save snapshot of current buffer state (auto-derives filename from loaded file). Used to generated expected files for unit tests +- `:ReplaySave [file]` - Save snapshot of current buffer state after pending replay/render work settles (auto-derives filename from loaded file). Used to generated expected files for unit tests - `:ReplayStatus` - Show current replay status - `:ReplayHeadless` - Enable headless mode (useful for an AI agent to see replays) diff --git a/tests/manual/regenerate_expected.lua b/tests/manual/regenerate_expected.lua new file mode 100644 index 00000000..390e8cfd --- /dev/null +++ b/tests/manual/regenerate_expected.lua @@ -0,0 +1,84 @@ +local helpers = require('tests.helpers') +local config = require('opencode.config') +local state = require('opencode.state') +local ui = require('opencode.ui.ui') +local output_window = require('opencode.ui.output_window') + +local M = {} + +local function wait_for_idle(timeout_ms) + timeout_ms = timeout_ms or 5000 + + return vim.wait(timeout_ms, function() + local emitter = state.event_manager and state.event_manager.throttling_emitter + if not emitter then + return true + end + + return #emitter.queue == 0 and not emitter.drain_scheduled + end, 10) +end + +local function with_ftplugin_disabled(fn) + local original = vim.g.did_load_ftplugin + vim.g.did_load_ftplugin = 1 + + local ok, result = xpcall(fn, debug.traceback) + vim.g.did_load_ftplugin = original + + if not ok then + error(result) + end + + return result +end + +---@param data_file string +---@param expected_file string +function M.run(data_file, expected_file) + if not data_file or data_file == '' then + error('Missing data file path') + end + if not expected_file or expected_file == '' then + error('Missing expected file path') + end + + config.debug.show_ids = true + + local ok, err = xpcall(function() + with_ftplugin_disabled(function() + helpers.replay_setup() + end) + + local events = helpers.load_test_data(data_file) + state.session.set_active(helpers.get_session_from_events(events)) + helpers.replay_events(events) + + if not wait_for_idle() then + error('Timed out waiting for replay events to drain') + end + + local actual = helpers.capture_output(state.windows and state.windows.output_buf, output_window.namespace) + local snapshot = { + lines = actual.lines, + extmarks = helpers.normalize_namespace_ids(actual.extmarks), + actions = actual.actions, + timestamp = os.time(), + } + + local json = vim.json.encode(snapshot, { indent = ' ', sort_keys = true }) + local file = assert(io.open(expected_file, 'w')) + file:write(json) + file:close() + end, debug.traceback) + + if state.windows then + ui.close_windows(state.windows) + end + + if not ok then + error(err) + end +end + +return M diff --git a/tests/manual/regenerate_expected.sh b/tests/manual/regenerate_expected.sh index 0ca19b1b..770936fd 100755 --- a/tests/manual/regenerate_expected.sh +++ b/tests/manual/regenerate_expected.sh @@ -3,7 +3,7 @@ # Usage: ./regenerate_expected.sh [filename] # filename: Optional. Just the filename (e.g., "simple-session.json"). If not provided, regenerates all files. -set -e +set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$SCRIPT_DIR/../.." @@ -47,10 +47,9 @@ if [[ -n "$TARGET_FILE" ]]; then fi echo "Processing: $data_file -> $expected_file" - nvim --headless -u tests/manual/init_replay.lua \ - "+ReplayLoad $data_file" \ - "+ReplayAll 0" \ - "+lua vim.defer_fn(function() vim.cmd('ReplaySave $expected_file') vim.cmd('qall!') end, 200)" 2>&1 | grep -v "^$" + nvim --headless -u tests/minimal/init.lua \ + -c "lua require('tests.manual.regenerate_expected').run([[$data_file]], [[$expected_file]])" \ + -c "qall!" 2>&1 | grep -v "^$" echo "Done! Regenerated $expected_file" else @@ -77,10 +76,9 @@ else expected_file="${data_file%.json}.expected.json" echo "Processing: $data_file -> $expected_file" - nvim --headless -u tests/manual/init_replay.lua \ - "+ReplayLoad $data_file" \ - "+ReplayAll 0" \ - "+lua vim.defer_fn(function() vim.cmd('ReplaySave $expected_file') vim.cmd('qall!') end, 200)" 2>&1 | grep -v "^$" + nvim --headless -u tests/minimal/init.lua \ + -c "lua require('tests.manual.regenerate_expected').run([[$data_file]], [[$expected_file]])" \ + -c "qall!" 2>&1 | grep -v "^$" done echo "" diff --git a/tests/manual/renderer_replay.lua b/tests/manual/renderer_replay.lua index 1c74cefa..b63bbf20 100644 --- a/tests/manual/renderer_replay.lua +++ b/tests/manual/renderer_replay.lua @@ -176,12 +176,40 @@ function M.normalize_file_paths(data) return replace_paths(data) end +function M.wait_for_idle(timeout_ms) + timeout_ms = timeout_ms or 5000 + + local ctx = require('opencode.ui.renderer.ctx') + local flush = require('opencode.ui.renderer.flush') + + return vim.wait(timeout_ms, function() + local emitter = state.event_manager and state.event_manager.throttling_emitter + if emitter and (#emitter.queue > 0 or emitter.drain_scheduled) then + return false + end + + if ctx:has_pending_work() then + if ctx.bulk_mode then + flush.end_bulk_mode() + else + flush.flush() + end + end + + return not ctx:has_pending_work() + end, 10) +end + function M.save_output(filename) if not state.windows or not state.windows.output_buf then vim.notify('No output buffer available', vim.log.levels.ERROR) return nil end + if not M.wait_for_idle() then + vim.notify('Timed out waiting for replay output to settle before saving', vim.log.levels.WARN) + end + local buf = state.windows.output_buf if not buf then @@ -234,10 +262,7 @@ end function M.dump_buffer_and_quit() vim.schedule(function() - -- wait until the emitter queue is empty - vim.wait(5000, function() - return vim.tbl_isempty(state.event_manager.throttling_emitter.queue) - end) + M.wait_for_idle(5000) if not state.windows or not state.windows.output_buf then print('ERROR: No output buffer available') diff --git a/tests/unit/question_window_spec.lua b/tests/unit/question_window_spec.lua index bfa4d506..bfa6ed2f 100644 --- a/tests/unit/question_window_spec.lua +++ b/tests/unit/question_window_spec.lua @@ -99,7 +99,8 @@ describe('question_window', function() question_window.format_display(output) - assert.are.equal(' 1 [x] Color 2 [ ] Shape ', output.lines[1]) + assert.are.equal(' 1 [Color] 󰄳 2 [Shape] ', output.lines[1]) + assert.are.equal('OpencodeQuestionTabDone', output.extmarks[0][1].hl_group) assert.are.equal('OpencodeQuestionTabActive', output.extmarks[0][2].hl_group) end)