nx
Top-level nx.* functions (those without a sub-namespace).
nx.mode()
nvim_get_mode(): the editor’s current mode, read from the nx._cur_mode
snapshot the server refreshes before each Lua entry. blocking is always
false — the in-VM Lua bindings only run when the server is between keys, so it
is never blocked on input here. (The dedicated RPC method serves remote clients.)
Defined in api.lua.
nx.current_line()
nvim_get_current_line(): the text of the line the cursor is on in the current
window/buffer (no trailing newline). Composed from the cursor row and the
buffer’s lines — a completion plugin reads this when it builds a completion
context, which runs as soon as its core spins up, so a missing builtin would
break completion (and every completion source) at load.
Defined in api.lua.
nx.regex(pattern, opts)
nx.regex(pattern, opts) -> regex: compile pattern into a reusable regex object
for matching Lua strings — a more capable string.find/match/gmatch/gsub
with a real regex dialect (named groups, alternation, lazy quantifiers, …). The
match runs in Rust, so a string you already hold in Lua is matched in place (no
copy). For searching buffer text instead, use nx.buf.search. Raises on an
invalid pattern.
opts (all optional):
engine = “pcre” | “vim” – regex dialect (default “pcre”, the regex crate)
plain = false – match the pattern literally (ignores engine)
ignorecase = false – case-insensitive match
Offsets follow the string library: 1-based and byte-based, with :find’s end
inclusive, so s:sub(re:find(s)) is the matched text. The returned object has:
re:find(s, init?) -> start, end, cap1, … | nil (like string.find)
re:match(s, init?) -> the capture(s), or the whole match if the pattern has
none, or nil (like string.match)
re:gmatch(s) -> iterator over each match’s captures (or whole match)
(like string.gmatch)
re:gsub(s, repl, n?) -> newstring, count (like string.gsub)
repl is a string (%0 whole match, %1-%9 captures, %% literal %),
a function called with the captures (return nil/false to keep the match),
or a table keyed by the first capture.
re:test(s) -> boolean: does the pattern match anywhere
init is 1-based and may be negative to count from the end, as in string.find.
local re = nx.regex([[(\w+)@(\w+)]]) local _, _, user, host = re:find(“to jo@acme now”) – “jo”, “acme” for word in nx.regex([[\w+]]):gmatch(“one two”) do … end local masked = nx.regex([[\d]]):gsub(“id 42”, “*”) – “id **”
Defined in api.lua.
nx.replace_termcodes(str, _from_part, _do_lt, _special)
nvim_replace_termcodes(str, from_part, do_lt, special): in neovim, translate
key notation (<CR>, <C-w>, <lt>, …) into the internal terminal-byte
encoding. nxvim represents keys as that notation throughout — parse_keys and
nvim_feedkeys consume notation directly — so the canonical internal form of a
key string already IS the notation, and this returns str unchanged. The
result round-trips exactly through nvim_feedkeys (which re-parses the notation),
which is the contract callers rely on (build a “feed string”, later feed it).
The flags (from_part / do_lt / special) only shape neovim’s byte output and are
accepted for call-compatibility; <lt> and the special names are handled by
parse_keys at feed time, so no pre-translation is needed here.
Defined in api.lua.
nx.mode_str(_expanded)
nx.mode_str([expanded]) [alias vim.fn.mode]: the single-letter mode code
(“n”/“i”/“v”/“V”/“R”/“c”). (Distinct from nx.mode(), which returns the
nvim_get_mode {mode, blocking} table.) INCOMPLETE: expanded is ignored — the
core has a flat Mode (no operator-pending / sub-state), so mode(1)’s multi-char
forms (“no”, “niI”, …) don’t exist here; the short code is returned for both.
Defined in api.lua.
nx.err_writeln(msg)
Message writers (aliases nvim_err_writeln / nvim_err_write / nvim_out_write).
Error writers route through nx._echo_err, which lands on the message line and
in :messages painted red (the core echo_err path); out_write funnels
through print like a plain message. nvim_err_writeln/out_write append a
newline; the *_write forms don’t (the message line is line-oriented, so both
just emit the text).
Defined in api.lua.
nx.err_write(msg)
No documentation comment in the prelude.
Defined in api.lua.
nx.out_write(msg)
No documentation comment in the prelude.
Defined in api.lua.
nx.list_uis()
nx.list_uis() [alias nvim_list_uis]: the attached UIs. nxvim drives one client at a time, so this reports a single UI sized to the editor screen (vim.o.columns/lines), with the fields a layout calculation reads. The ext_* feature flags are all false (nxvim’s redraw protocol carries no external-UI widgets).
Defined in api.lua.
nx.exec(src, output)
nx.exec(src, output) [alias nvim_exec]: run the ex-command(s) in src and,
when output is truthy, return the text they produced (see exec_capture).
Defined in autocmd.lua.
nx.component(def)
nx.component(def) -> { mount(opts) } — build a reactive, Vue-shaped UI component for
a plugin surface, then :mount() one or more instances of it. The reactive core is
surface-agnostic: the same component can drive a focus-taking buffer or a passive
float, chosen per def / mount.
def is a table:
render(state, inst)— REQUIRED and PURE. Maps the current state to what’s on screen and returns the surface’s output (see Surfaces). The framework re-runs it automatically whenever reactive state changes, coalesced to ONE render per tick. May be async (callnx.await(...)straight inside it).setup(ctx, props)— OPTIONAL; runs ONCE on mount and owns every side effect — it creates reactive state, subscribes to events, binds keys, fetches data — and RETURNS thestatevalue handed torender. Runs only after the surface is ready, so everything onctxis already valid (no tick-dance). May be async.surface—"view"(default) or"float"; or passbackend(afunction(opts) -> adapter) to render to a custom surface.
The ctx handed to setup carries the reactivity and lifecycle:
ctx.reactive(tbl)— a deep reactive proxy; writing any key (s.x = 1) schedules a re-render. Iterate withipairs/#(NOTpairs— PUC 5.4 has no__pairs).ctx.computed(getter)— a cached derived value, read asc()orc.value; it re-evaluates only when a reactive input it read last time has changed.ctx.refresh()— force a re-render.ctx.props— theopts.propsfrommount.ctx.on_close(fn)/ctx.close()— register a teardown hook / close the instance. On the “view” surfacectxalso gains:ctx.view,ctx.bufnr(),ctx.winid(),ctx.line(),ctx.set_cursor(n),ctx.bo/ctx.wo(the view’s buffer/window-local option tables), andctx.keymap_set(mode, lhs, rhs, opts)(buffer-scoped +nowaitby default).
Surfaces — what render returns, and how the surface behaves:
- “view” — a focus-taking, navigable
nx.viewbuffer (dock / split / grabbing float): the file-tree / list / modal-dialog case.renderreturns{ lines, decor }(or a bare line list).nx.view.component(def)is the sugar. - “float” — a NON-focus
nx.ui.floatcontent float (the which-key surface): never steals focus, binds no keys.renderreturns{ lines, title?, relative?, border? }; an EMPTY render HIDES the float (a later non-empty one re-opens it), so a component shows/hides purely by what it returns. Only one float component may display at once (a second fails loud rather than clobbering the single content-float slot).
mount(opts) instantiates and returns the instance (with :close()). opts.props is
passed to setup; the rest configures the surface — view: name / filetype / dock
/ split / float (and eob to keep end-of-buffer tildes); float: title /
relative / border. Render errors and setup errors are caught and surfaced via
nx.notify rather than crashing the editor.
Persistence (view surface) — mount{ persist = "<id>", … } opts a view component into
cross-session restore, the high-level form of nx.view.create{ persist=} +
nx.view.on_restore. The framework resolves the owning namespace ONCE (from the
mount call site, or opts.namespace for a no-attribution context — the same escape-hatch
contract as nx.shada.plugin()), records only (namespace, id) + the view’s slot in the
session, and on a restart picks fresh-vs-restore for you: it adopts the reserved slot if
the session reopened the view, else mounts fresh — no on_restore handler, no VimEnter
fallback. The content is the component’s own: setup reads it from ctx.store and a
mutation saves it back. A persistent component’s ctx gains:
ctx.store—nx.shada.plugin(ns)for the resolved owner namespace: an isolated, cross-session key/value slice. Read saved state insetup, write it on every change.ctx.namespace— the resolved owner namespace;ctx.persist_id— the stable id. (examples/view-persist/is a runnable pinned-notes plugin built on exactly this.)
Example — a live-updating counter in a floating view:
local Counter = nx.component({
setup = function(ctx)
local s = ctx.reactive({ n = 0 })
ctx.keymap_set("n", "+", function() s.n = s.n + 1 end) -- write -> re-render
ctx.keymap_set("n", "q", ctx.close)
return s
end,
render = function(s)
return { lines = { "count: " .. s.n, "", "+ to increment · q to quit" } }
end,
})
Counter.mount({ float = { width = 30, height = 4, grab = true } })
Defined in component.lua.
nx.on_key_pending(fn)
No documentation comment in the prelude.
Defined in keymap.lua.
nx.on(event, opts, fn)
Events — structured autocmd subscriptions. nx.on(event, opts, fn): the
canonical verb. fn (when given) is the handler; otherwise opts.callback /
opts.command apply, exactly as the underlying registry expects. Returns the
subscription id (droppable with nx.off).
Defined in nx.lua.
nx.off(id)
Drop a subscription created by nx.on.
Defined in nx.lua.
nx.command(name, fn, opts)
User commands — nx.command(name, fn, opts) defines :Name; fn is a
function or an ex-command string.
Defined in nx.lua.
nx.uuid()
nx.uuid() -> a fresh random (version-4) UUID as a canonical 8-4-4-4-12 lowercase-hex string, e.g. “f47ac10b-58cc-4372-a567-0e02b2c3d479”. Bytes come from the OS CSPRNG, so each call is unique; handy for a session id, a temp-file name, or any unique key. Available on every build (native and browser/wasm).
Defined in nx.lua.
nx.echo(msg)
nx.echo(msg) -> nil. Append msg (a string) to the message line — the programmatic
echo, the canonical form of vim.api.nvim_echo. For a transient, separately-styled
notification prefer nx.notify.
Defined in nx.lua.
nx.argv()
nx.argv() -> the list of positional file arguments this process was launched with (strings; empty when none). A launcher / wrapper reads them to forward to a relaunched editor; carried through the NXVIM_ARGV environment variable, so the binary stays the single source of truth.
Defined in nx.lua.
nx.reexec(args)
nx.reexec(args) -> does not return on success. Replace THIS process with a fresh
nxvim <args…> of the current executable — a launcher relaunches the editor with
chosen flags this way (e.g. { “–shada-namespace”, ns, “–restore-session” }). On
Unix this execv()s (never returns on success); elsewhere it spawns and exits with
the child’s status. Raises if the exec / spawn itself fails.
Defined in nx.lua.
nx.now_ms()
nx.now_ms() -> a monotonic timestamp in milliseconds (a number) for timing and scheduling math. Unlike os.clock (CPU time, ≈0 across an awaited tick) it advances with real wall-clock time, so it measures durations that span async work.
Defined in nx.lua.
nx.runtime_file(name, all)
nx.runtime_file(name[, all]) -> full paths of runtimepath files matching name (a
runtimepath-relative path whose final component may be globbed with *), as a list.
With all falsey it returns just the first match (a one- or zero-element list).
Reads the LIVE runtimepath, so a plugin installed mid-session contributes its files
immediately. The lsp/<server>.lua config-discovery primitive.
Defined in nx.lua.
nx.open(path, opts)
nx.open(path[, opts]) -> nil. Open a file or directory in the editing area, like
:edit. With opts.where == "main" it first crosses to the main editor layer (so
an open fired from a dock / sidebar keymap lands in the main area, not the dock);
the default opens in the current window.
Defined in nx.lua.
nx.run(spec)
nx.run { cmd, args, cwd, env, stdin } -> promise of { code, stdout, stderr }.
Runs a child to completion off the input tick, collecting all of stdout. It
RESOLVES (never rejects) with the exit result: a non-zero code is the caller’s
to act on, and a spawn failure (e.g. binary not found) surfaces as code = -1
with empty output — exactly like vim.system. The one-shot promise twin of
nx.run_stream.
Defined in process.lua.
nx.run_stream(spec)
nx.run_stream { cmd, args, cwd, env } -> Stream. Spawns a child and streams its stdout in newline-delimited batches. The streaming twin of nx.run; the picker / completion sources consume it to feed results as they arrive.
Defined in process.lua.
nx.await_each(stream)
nx.await_each(stream): a for-loop iterator over a Stream’s batches. Each step
awaits the next batch; the loop ends when the stream is exhausted (:next()
resolves nil). MUST run inside an nx.async function (nx.await suspends the
enclosing coroutine).
for batch in nx.await_each(stream) do for _, line in ipairs(batch) do … end end
Defined in process.lua.
nx.async(fn)
nx.async(fn) returns a function that, when called, runs fn as a coroutine
and returns a promise for its result. Inside, nx.await(p) suspends until p
settles and evaluates to its value (or re-raises its rejection as a Lua error),
so a sequence of awaits reads top-to-bottom with no nesting:
local load = nx.async(function(path)
local stat = nx.await(fs.stat(path))
local data = nx.await(fs.read(path))
return parse(data, stat)
end)
load("init.lua"):next(use):catch(report)
A rejected await raises inside the coroutine, so you can handle it either way:
wrap the await in pcall to catch it locally (PUC 5.2+ yields across a pcall
boundary, so this works on nxvim’s 5.4 backend), or let it propagate to the
coroutine edge (the returned promise rejects, caught by :catch on the result)
or attach :catch to the awaited promise itself.
Defined in promise.lua.
nx.await(awaitable)
nx.await(awaitable): suspend the enclosing nx.async coroutine until awaitable
settles. Returns the fulfilment value, or raises the rejection reason as an
error (which, uncaught, rejects the async function’s promise). Errors loudly if
called outside an nx.async coroutine — there is nothing to suspend.
Defined in promise.lua.
nx.schedule(fn)
nx.schedule(fn): defer fn to the end of the current convergence — it runs
after the work that scheduled it settles, no longer nested in the caller’s
stack frame (the strict improvement over the old inline fn()), but still
within the same input tick (not a later wall-clock turn; that is defer_fn).
This is exactly what the colorscheme’s “defer to avoid reentrancy” wants.
Defined in runtime.lua.
nx.schedule_wrap(fn)
nx.schedule_wrap [alias vim.schedule_wrap] (fn): return a function that, when
called, schedules fn with whatever arguments it was given — a common plugin
idiom for “run this callback safely on the loop”. The captured args ride into
the deferred call via a closure.
Defined in runtime.lua.
nx.timer(fn, timeout)
nx.timer(fn, timeout): the canonical timer / defer primitive (aliased by
vim.defer_fn) — run fn once, timeout ms from now, on the loop — the
off-tick deferral configs use for retry patterns. Returns a handle so the
caller can :stop() it before it fires.
Defined in runtime.lua.
nx.on_next_tick(fn)
nx.on_next_tick(fn): run fn on the NEXT event-loop tick — the turn after the
current one finishes. The cross-tick sibling of nx.schedule: where nx.schedule
fires at the end of THIS convergence (a same-tick microtask, so it cannot observe
state that only refreshes between ticks — a freshly-mounted window’s id, a mirror
the server repopulates each turn), nx.on_next_tick yields the tick entirely and runs
on the next one, when those mirrors have been refreshed. A zero-delay one-shot
timer is exactly that. Returns the timer handle, so a caller can :stop() it before
it fires. (Poll across several ticks by calling it again from within fn.)
Defined in runtime.lua.
nx.notify(msg, level, _opts)
No documentation comment in the prelude.
Defined in runtime.lua.
nx.notify_once(msg, level, opts)
nx.notify_once [alias vim.notify_once]: in neovim this dedups by message; we have no message history to dedup against during a one-shot colorscheme load, so route to notify.
Defined in runtime.lua.
nx.inspect(value)
nx.inspect [alias vim.inspect]: pretty-print a value (tables recursively).
Defined in runtime.lua.
nx.exists(expr)
nx.exists(expr) [alias vim.fn.exists]: does the vim entity named by expr exist? (1 / 0). nxvim
answers the forms it can verify and reports 0 for the rest (rather than a fake
- so feature-probing stays honest:
- ‘&opt’ / ‘&l:opt’ / ‘&g:opt’ / ‘+opt’ -> an option nxvim models. A completion
plugin gates every window-option write on
exists('+'..key), so an unknown option is skipped instead of erroring the float setup. - ‘g:’/‘b:’/‘w:’/‘t:’/‘v:’ prefixed name -> that scoped variable is set.
- ‘:Cmd’ -> a user command nxvim can confirm (2, neovim’s exact-match value); a buffer-local command for the current buffer counts, like at dispatch.
- everything else (‘*func’, built-in ‘:write’, bare names) -> 0 (can’t confirm).
Defined in state.lua.
nx.set_option(name, value)
nx.set_option / nx.get_option(name[, value]) [aliases nvim_set_option / nvim_get_option]: the global-scope (deprecated) accessors. Route through nx.o, the canonical global-option table that canonicalizes the scope the name implies.
Defined in state.lua.
nx.get_option(name)
No documentation comment in the prelude.
Defined in state.lua.
nx.npcall(fn, ...)
nx.npcall(fn, …) [alias vim.npcall]: pcall that maps failure to nil — select(2, pcall(...))
on success, nil on error. A neovim helper kept for config/plugin convenience
(wrap a call that may raise and treat failure as “no value”).
Defined in stdlib.lua.
nx.nonnil(...)
nx.nonnil(…) [alias vim.nonnil]: the first non-nil argument, or nil (verbatim from neovim’s vim/_core/shared.lua; the replacement for the deprecated vim.F.if_nil). A general helper for defaulting an optional value.
Defined in stdlib.lua.
nx.keytrans(s)
nx.keytrans(s) [alias vim.fn.keytrans]: translate the internal form of a key
sequence to readable key notation (<C-w>, <Space>, …). nxvim represents keys
AS that notation throughout (parse_keys / nvim_feedkeys consume notation directly,
and nvim_replace_termcodes returns its input unchanged), so the internal form
already IS the notation — this returns s unchanged, the inverse of
nvim_replace_termcodes exactly as in vim.
Defined in stdlib.lua.
nx.print(...)
nx.print(…) [alias vim.print]: pretty-print each argument (via nx.inspect) on the message line and return them unchanged, so it can wrap a value inline. Strings print verbatim; tables are inspected.
Defined in stdlib.lua.
nx.iter(src, state, ctrl)
nx.iter(src[, state, ctrl]) [alias vim.iter]: wrap a list-like table OR a Lua iterator triple
in a chainable iterator. The triple form is what vim.iter(vim.fs.parents(p))
passes — vim.fs.parents returns (fn, state, start), which Lua spreads as
three args here — so the ancestors are drained eagerly into the item list.
Defined in stdlib.lua.
nx.line(expr)
nx.line(expr) [alias vim.fn.line]: a buffer line number. “.” is the cursor line (1-based), “$” the last line (the line count). The window-relative forms (“w0”/“w$”) need the scroll position, which the mirror doesn’t carry yet, so they error loud.
Defined in vimfn.lua.
nx.col(expr)
nx.col(expr) [alias vim.fn.col]: a byte column (1-based). “.” is the cursor column, “$” one past the end of the cursor line (its byte length + 1), matching vim.
Defined in vimfn.lua.
nx.localtime()
nx.localtime() [alias vim.fn.localtime]: the current time in seconds. nxvim
sources this from a MONOTONIC clock (the server’s nx._mono_secs, the same base
stamped onto undo nodes), not wall-clock unix epoch, so localtime() - node.time
elapsed math (e.g. the undotree visualizer’s “N minutes ago”) stays correct and
non-negative across NTP steps and manual clock changes. Only differences matter.
Defined in vimfn.lua.
nx.expand(expr)
nx.expand(expr) [alias vim.fn.expand]: the % (current file) forms autocmd
callbacks and statuslines use to resolve paths, backed by the current-buffer
snapshot. % is the stored name; %:<mods> routes through fnamemodify (so %:t,
%:p, %:h, %:r, %:~:., … all work). A non-% expression errors loud.
(the override below extends this with cursor keywords / globs, re-binding nx.expand.)
Defined in vimfn.lua.
nx.getmousepos()
nx.getmousepos() [alias vim.fn.getmousepos]: the most recent mouse event’s
position as a dict — screenrow/screencol (1-based global screen cell),
winid (the window the cell is in, 0 if none), winrow/wincol (1-based,
window-relative, gutter included), line/column (1-based buffer line and byte
column, 0 off a window’s text), and coladd (always 0 — nxvim has no
‘virtualedit’). Reads the nx._mouse_pos mirror the server pushes from the
editor’s last mouse cell, so a mouse mapping (<RightMouse>, <MiddleMouse>, …)
can act on the clicked position rather than the cursor.
Defined in vimfn.lua.