Skip to content

Commit f36bdc5

Browse files
authored
feat(ui): add vim.ui.select rendering option for questions (#300)
1 parent a1c608c commit f36bdc5

4 files changed

Lines changed: 87 additions & 2 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ require('opencode').setup({
215215
preset = 'nerdfonts', -- 'nerdfonts' | 'text'. Choose UI icon style (default: 'nerdfonts')
216216
overrides = {}, -- Optional per-key overrides, see section below
217217
},
218+
questions = {
219+
use_vim_ui_select = false, -- If true, render questions/prompts with vim.ui.select instead of showing them inline in the output buffer.
220+
},
218221
output = {
219222
tools = {
220223
show_output = true, -- Show tools output [diffs, cmd output, etc.] (default: true)

lua/opencode/config.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ M.defaults = {
138138
},
139139
always_scroll_to_bottom = false,
140140
},
141+
questions = {
142+
use_vim_ui_select = false, -- If true, render questions with vim.ui.select instead of in the output buffer
143+
},
141144
input = {
142145
min_height = 0.10,
143146
max_height = 0.25,

lua/opencode/ui/question_window.lua

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ local state = require('opencode.state')
22
local icons = require('opencode.ui.icons')
33
local Dialog = require('opencode.ui.dialog')
44

5+
local config = require('opencode.config')
6+
57
local M = {}
68

79
M._current_question = nil
@@ -27,8 +29,13 @@ function M.show_question(question_request)
2729
M._current_question = question_request
2830
M._current_question_index = 1
2931
M._collected_answers = {}
30-
M._setup_dialog()
31-
render_question()
32+
33+
if config.ui.questions and config.ui.questions.use_vim_ui_select then
34+
M._show_question_with_vim_ui_select()
35+
else
36+
M._setup_dialog()
37+
render_question()
38+
end
3239
end
3340

3441
function M.clear_question()
@@ -247,6 +254,60 @@ function M._clear_dialog()
247254
end
248255
end
249256

257+
---Show question using vim.ui.select
258+
function M._show_question_with_vim_ui_select()
259+
if not M.has_question() then
260+
return
261+
end
262+
263+
local question_info = M.get_current_question_info()
264+
if not question_info or not question_info.options then
265+
return
266+
end
267+
268+
local options_to_display = add_other_if_missing(question_info.options)
269+
local progress = ''
270+
if M._current_question and #M._current_question.questions > 1 then
271+
progress = string.format(' (%d/%d)', M._current_question_index, #M._current_question.questions)
272+
end
273+
274+
local prompt = question_info.question .. progress
275+
local choices = {}
276+
for i, option in ipairs(options_to_display) do
277+
table.insert(choices, option.label)
278+
end
279+
280+
vim.ui.select(choices, {
281+
prompt = prompt,
282+
format_item = function(item)
283+
return item
284+
end,
285+
}, function(choice)
286+
if not choice then
287+
-- User cancelled
288+
if M._current_question and M._current_question.id then
289+
M._send_reject(M._current_question.id)
290+
end
291+
M.clear_question()
292+
return
293+
end
294+
295+
-- Find the selected option index
296+
local selected_index = nil
297+
for i, option in ipairs(options_to_display) do
298+
if option.label == choice then
299+
selected_index = i
300+
break
301+
end
302+
end
303+
304+
if selected_index then
305+
M._answering = true
306+
M._answer_with_option(selected_index)
307+
end
308+
end)
309+
end
310+
250311
---@param request_id string
251312
---@param answers string[][]
252313
function M._send_reply(request_id, answers)

lua/opencode/ui/renderer.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,16 @@ function M.render_permissions_display()
201201
end
202202

203203
function M.clear_question_display()
204+
local config_module = require('opencode.config')
205+
local use_vim_ui = config_module.ui.questions and config_module.ui.questions.use_vim_ui_select
206+
207+
if use_vim_ui then
208+
-- When using vim.ui.select, there's nothing to clear from the buffer
209+
local question_window = require('opencode.ui.question_window')
210+
question_window.clear_question()
211+
return
212+
end
213+
204214
local question_window = require('opencode.ui.question_window')
205215
question_window.clear_question()
206216
M._remove_part_from_buffer('question-display-part')
@@ -209,6 +219,14 @@ end
209219

210220
---Render question display as a fake part
211221
function M.render_question_display()
222+
local config_module = require('opencode.config')
223+
local use_vim_ui = config_module.ui.questions and config_module.ui.questions.use_vim_ui_select
224+
225+
if use_vim_ui then
226+
-- When using vim.ui.select, we don't render anything in the buffer
227+
return
228+
end
229+
212230
local question_window = require('opencode.ui.question_window')
213231

214232
local current_question = question_window._current_question

0 commit comments

Comments
 (0)