Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

nx.ui

nx.ui.select(items, opts, on_choice)

nx.ui.select(items, opts) -> a PROMISE that resolves to the chosen item, or to nil on cancel (<Esc> / q). Promise-only: there is no on_choice argument (passing one is the old callback shape and errors loudly). The 1-based index is dropped — recover it from the item, or use the vim.ui.select alias, which keeps it. opts: prompt = the label drawn above the list (default none) format_item = item -> display string (default tostring); the original item round-trips to the resolved value regardless.

Defined in ui.lua.

nx.ui.input(opts, on_confirm)

nx.ui.input(opts) -> a PROMISE that resolves to the entered string on <CR>, or to nil on <Esc> (cancel). Promise-only: there is no on_confirm argument (passing one is the old callback shape and errors loudly). opts: prompt = the label drawn ahead of the editable line (default “”) default = text prefilled into the line, cursor at its end (default “”) history = a namespace string enabling readline-style recall: <Up>/<Down> (and <C-p>/<C-n>) browse the prompts submitted under this namespace, and each non-empty submission is recorded into it. Each namespace is an independent ring, so one plugin’s REPL history is separate from another’s. Session-only for now. Absent ⇒ no history. complete = a function (line, col) -> candidates driving <Tab> autocomplete (the inline wildmenu above the prompt line — <Tab>/<S-Tab> cycle, <CR> accepts). candidates is a { {label, insert?, doc?, start?, length?}, … } list (insert defaults to label), OR a PROMISE of one — so an async source (e.g. a DAP completions request) works. The token completed is the trailing identifier run before the cursor, UNLESS a candidate supplies start (0-based char offset into the line) + length (chars), an explicit replace span that overrides the token for that row. col is the cursor’s 0-based char offset. complete_docs = show the side docs pane rendering each candidate’s doc beside the list (default true when complete is set; false suppresses it). complete_debounce = ms to coalesce refresh queries (narrowing an open menu as you type) so an async source isn’t a wire round-trip per keystroke; the initial <Tab> is always immediate (default 100; 0 disables it). The server owns the prompt: it opens the editor’s command line as a labelled Prompt (Editor::open_prompt), and delivers the result to nx._cb_fns[id] through the shared prompt_results channel. Non-blocking (ADR 0002 rule 3): the call returns at once and the promise settles on a later tick. Note an empty submission (<CR> on an empty line) resolves to “” (not nil) — only <Esc> cancels, matching neovim’s vim.ui.input.

Defined in ui.lua.

nx.ui.confirm(message, opts, on_choice)

nx.ui.confirm(message, opts) -> a PROMISE that resolves to a boolean — true on Yes, false on No or cancel (<Esc>). Promise-only: there is no on_choice argument (the old callback forms — a third arg, or opts-as-function — error loudly). opts (optional): default = true | false – which button <CR> selects (default true = Yes) nx-native (no vim.ui twin): neovim spells this blocking vim.fn.confirm, which the nx model omits (rule 3). For an arbitrary multi-choice menu use nx.ui.select instead — confirm is deliberately just yes/no. The server opens a single-keypress Confirm dialog (Editor::open_confirm) sharing the prompt_results channel with nx.ui.input (one prompt open at a time); the chosen 1-based button index arrives as a string, which the wrapper folds to the boolean (1 = Yes; 2 = No; 0 = cancel).

Defined in ui.lua.

nx.ui.float(contents, opts)

nx.ui.float(contents, opts): open the list-less content float — the sibling of the selectable-list widget (docs/specs/2026-06-14-nx-ui-float-widget.md, “What stays out of this widget”) — rendering content with no list / selection. contents is a string (split on newlines), a list of line strings, or — for a styled float (the “pretty” which-key) — a list where a row may be a CHUNK LIST { {text, hl_group?}, … } (neovim’s virt_text shape): each chunk paints its text in hl_group, so a row can colour its key one group and its description another, or dim a whole row with a Comment/dim group. Plain and chunk rows mix freely; a plain row is just one un-grouped chunk. opts: border = “none”|“single”|“rounded”|“double”|“solid” (default “rounded”) title = a string drawn on the top border (optional) relative = “cursor” (default, anchors at the cursor) | “editor” (centered) | “bottom” (pinned to the editor’s bottom-right corner — the which-key shape) persist = when truthy, the float survives keystrokes (it is not dismissed by the next key) and nx.ui.float returns a HANDLE with :update(contents, opts) / :close() / :is_open(). This is the surface a key-observer plugin (e.g. which-key) renders through, refreshing it as keys arrive. Without persist it is fire-and-forget: the server owns the float, its geometry, and its dismissal (the next key closes it); returns nil. Empty contents open nothing. LSP hover and signature help use the non-persistent form.

Defined in ui.lua.

nx.ui.open(uri)

nx.ui.open(uri) -> a PROMISE of the opener’s exit result { code, stdout, stderr } (the nx.run shape). Hands uri — a file path or a URL — to the OS opener chosen by platform (nx._ui_opener: open on macOS, explorer on Windows, xdg-open elsewhere) and runs it off-tick. Like nx.run it RESOLVES rather than rejects: a missing opener surfaces as code = -1 and a non-zero opener exit as that code — the caller decides what to do with it. Promise-only (ADR 0002): no callback arg.

Defined in ui.lua.