--- A single selection primitive. Uses built-in `vim.ui.select` so headless e2e --- needs no plugins; auto-upgrades to Telescope when it is installed and not --- explicitly disabled. Tests set `vim.g.heph_force_ui_select` and stub --- `vim.ui.select`, so a picker never blocks in `--headless`. local M = {} local function telescope_available() return pcall(require, "telescope") end --- Select one of `items`. `opts.prompt`, `opts.format(item)->string`, and an --- optional `opts.preview(item)->lines` (Telescope only; markdown-rendered). --- `on_choice(item|nil, index|nil)` — nil when cancelled. function M.select(items, opts, on_choice) opts = opts or {} if not vim.g.heph_force_ui_select and telescope_available() then -- Telescope path: a thin wrapper so fuzzy UX is available when present. local pickers = require("telescope.pickers") local finders = require("telescope.finders") local conf = require("telescope.config").values local actions = require("telescope.actions") local action_state = require("telescope.actions.state") local previewer = nil if opts.preview then previewer = require("telescope.previewers").new_buffer_previewer({ define_preview = function(self, entry) vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, opts.preview(entry.value) or {}) vim.bo[self.state.bufnr].filetype = "markdown" end, }) end pickers .new({}, { prompt_title = opts.prompt or "heph", finder = finders.new_table({ results = items, entry_maker = function(item) local display = opts.format and opts.format(item) or tostring(item) return { value = item, display = display, ordinal = display } end, }), sorter = conf.generic_sorter({}), previewer = previewer, attach_mappings = function(bufnr) actions.select_default:replace(function() actions.close(bufnr) local sel = action_state.get_selected_entry() on_choice(sel and sel.value or nil) end) return true end, }) :find() return end vim.ui.select(items, { prompt = opts.prompt, format_item = opts.format, }, function(choice, idx) on_choice(choice, idx) end) end return M