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

btv

Top-level btv.* functions (those without a sub-namespace), plus the methods of the handles they hand back (promise:, iter:, stream:, timer:).

btv.mode()

nvim_get_mode(): the editor’s current mode, read from the btv._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.

btv.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.

btv.regex(pattern, opts)

btv.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 btv.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:find_all(s)       -> { s1, e1, s2, e2, … }: every match's start/end, in
                        one pass (a `:find` loop is quadratic on a long string)
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 = btv.regex([[(\w+)@(\w+)]])
local _, _, user, host = re:find("to jo@acme now")  -- "jo", "acme"
for word in btv.regex([[\w+]]):gmatch("one two") do ... end
local masked = btv.regex([[\d]]):gsub("id 42", "*")  -- "id **"

Defined in api.lua.

btv.replace_termcodes(str, _from_part, _do_lt, _special)

nvim_replace_termcodes(str, from_part, do_lt, special): translate key notation (<CR>, <C-w>, <lt>, …) into neovim’s terminal-byte encoding — <C-o> → \15, <CR> → \r, <Esc> → \27, <lt> → < — via the native btv._replace_termcodes. Keys with no single ASCII byte (arrows, function keys) have no such encoding bemtvi can emit (neovim uses K_SPECIAL sequences bemtvi doesn’t model), so they stay as <...> notation, which parse_keys still consumes — so the result round-trips exactly through nvim_feedkeys (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; bemtvi always translates the special names and <lt>.

Defined in api.lua.

btv.mode_str(_expanded)

btv.mode_str([expanded]) [alias vim.fn.mode]: the single-letter mode code ("n"/"i"/"v"/"V"/"R"/"c"). (Distinct from btv.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.

btv.err_writeln(msg)

Message writers (aliases nvim_err_writeln / nvim_err_write / nvim_out_write). Error writers route through btv._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.

btv.err_write(msg)

No documentation comment in the prelude.

Defined in api.lua.

btv.out_write(msg)

No documentation comment in the prelude.

Defined in api.lua.

btv.list_uis()

btv.list_uis() [alias nvim_list_uis]: the attached UIs. bemtvi 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 (bemtvi’s redraw protocol carries no external-UI widgets).

Defined in api.lua.

btv.exec(src, output)

btv.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.

btv.on(event, opts, fn)

Events — structured autocmd subscriptions. btv.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 btv.off).

btv.on(event, fn) is the same thing with no options — the spelling to reach for when there is nothing to configure:

btv.on("FileType", { pattern = "lua" }, function(ev) … end)  -- with options
btv.on("BufWritePost", function(ev) … end)                   -- without

Defined in btv.lua.

btv.off(id)

Drop a subscription created by btv.on.

Defined in btv.lua.

btv.command_disabled(name)

btv.command_disabled(name) -> whether this editor refuses the command name spells (any spelling: "e" and "edit" alike; a leading : and a trailing ! are ignored). An app embedding the editor can take commands away from it; running one then fails with E5800, on every route. Always false elsewhere.

Defined in btv.lua.

btv.command(name, fn, opts)

User commands — btv.command(name, fn, opts) defines :Name; fn is a function or an ex-command string.

Defined in btv.lua.

btv.uuid()

btv.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 btv.lua.

btv.echo(msg)

btv.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 btv.notify.

Defined in btv.lua.

btv.argv()

btv.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 BEMTVI_ARGV environment variable, so the binary stays the single source of truth.

Defined in btv.lua.

btv.now_ms()

btv.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 btv.lua.

btv.runtime_file(name, all)

btv.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 btv.lua.

btv.open(path, opts)

btv.open(path[, opts]) -> nil. Open a file (or a directory, which opens the file explorer) in the editing area. opts is an optional table:

  • reuse (boolean, default true) — “open or jump”. How to handle the file when it is already up:

    • shown in a window → focus that window (across tabs under the default 'switchbuf' = usetab); the file is NOT reloaded and no split is made.
    • loaded but hidden → show that existing buffer in the current window, preserving its edits and cursor (no re-read, no duplicate buffer).
    • not open at all → read it fresh into the current window.

    This is what a file explorer, a “go to file”, or a jump-to-source wants: click a file that’s already on screen and you land on it rather than getting a second copy. Set reuse = false for plain :edit semantics — always load into the current window even when another window already shows the file, e.g. to deliberately place a buffer into a split you just created.

  • where ("main" | nil) — with where = "main" the open first crosses to the main editor layer, so an open fired from a dock / sidebar keymap lands in the main area instead of inside the dock. Omitted, it opens in the current window.

Note: only reuse (the default) consults 'switchbuf', and 'switchbuf' only ever redirects to a window already DISPLAYING the buffer — a hidden buffer has no such window, hence the “loaded but hidden” case above.

Defined in btv.lua.

btv.component(def)

btv.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 (call btv.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 the state value handed to render. Runs only after the surface is ready, so everything on ctx is already valid (no tick-dance). May be async.
  • surface — "view" (default) or "float"; or pass backend (a function(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 with ipairs / # (NOT pairs — PUC 5.4 has no __pairs).
  • ctx.computed(getter) — a cached derived value, read as c() or c.value; it re-evaluates only when a reactive input it read last time has changed.
  • ctx.refresh() — force a re-render. ctx.props — the opts.props from mount.
  • ctx.on_close(fn) / ctx.close() — register a teardown hook / close the instance. On the "view" surface ctx also 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), and ctx.keymap_set(mode, lhs, rhs, opts) (buffer-scoped + nowait by default). A view is read-only, so in a modeless session ('modeless') its keys reach it only through the modeless layer: pass { "n", "modeless" } as mode to serve both editing models.

Surfaces — what render returns, and how the surface behaves:

  • "view" — a focus-taking, navigable btv.view buffer (dock / split / grabbing float): the file-tree / list / modal-dialog case. render returns { lines, decor } (or a bare line list). btv.view.component(def) is the sugar.
  • "float" — a NON-focus btv.ui.float content float (the which-key surface): never steals focus, binds no keys. render returns { 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 btv.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 btv.view.create{ persist=} + btv.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 btv.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 — btv.shada.plugin(ns) for the resolved owner namespace: an isolated, cross-session key/value slice. Read saved state in setup, 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 = btv.component({
  setup = function(ctx)
    local s = ctx.reactive({ n = 0 })
    local keys = { "n", "modeless" } -- both editing models
    ctx.keymap_set(keys, "+", function() s.n = s.n + 1 end)  -- write -> re-render
    ctx.keymap_set(keys, "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.

btv.on_key_pending(fn)

btv.on_key_pending(fn): subscribe to the engine-computed pending-key signal. The server fires it whenever the pending key-context changes — a mapped prefix grows (you type <leader>, then w) or clears (the sequence completed, broke, or the idle flush resolved it) — NOT per keystroke (ADR 0002 rule 4: no per-key Lua). The handler receives ctx = { mode, keys, continuations = { { key, desc, kind = “map”|“group” }, … } } where keys is the withheld prefix in vim notation (“” when the context cleared, which a which-key popup treats as “close”) and each continuation is one key that extends the prefix — kind = "map" completes a mapping (carrying its desc), kind = "group" only leads on to longer mappings. The finite built-in prefixes (g -> gg/gt/.., z -> zt/zz/.., <C-w> -> window commands) enumerate continuations too, merged under one prefix with any maps that share it (g + the LSP gd/gD/gr).

available (boolean) is true for every reachable continuation. It is false only for a continuation kept visible but no longer firable: a mapped g-prefix (gd/gD/gr) surfaced AFTER the leader timeout committed g to the built-in grammar – the maps need a faster sequence to fire, so which-key shows them dimmed / cued rather than dropping them mid-popup. (A future per-line float highlight will let a which-key gray these properly; see docs/plans/2026-06-16-keypending-source-b.md.)

ctx.label (a string, or nil) is the source B channel: the built-in command grammar’s open pending states — f/t/F/T find-char, r replace, i/a text-object, marks, registers, <C-w> — have no finite key list to enumerate, so they arrive with continuations = {} and a human label instead ("Find character"). A which-key renders the label as a hint card when continuations is empty; sources A/C (mapped prefixes) leave label nil and list keys.

This is the render-time oracle a native which-key plugin debounces (btv.utils.debounce) and draws as a persistent btv.ui.float. Continuations come from the mapped-prefix trie (user + native-default maps, sources A/C) AND the built-in command grammar’s finite prefixes (source B); the open built-in states are surfaced via label instead.

Defined in keymap.lua.

btv.run_local(spec)

btv.run_local { cmd, args, cwd, env, stdin } -> promise of { code, stdout, stderr }. The local-always twin of btv.run: runs a one-shot child to completion on THIS machine, even when the session’s processes route to a daemon. Same spec + resolution as btv.run (RESOLVES, never rejects; a spawn failure is code = -1). Reach for it for client-side work — provisioning a remote, an ssh control-master, a docker cp — that must not run on the daemon. In a bare/local session it is exactly btv.run.

Defined in localseam.lua.

btv.run(spec)

btv.run { cmd, args, cwd, env, stdin } -> promise of { code, stdout, stderr }. Runs a child to completion off the input tick, buffering all of its stdout and stderr and resolving once, on exit.

Spec fields:

  • cmd — the program. A string, or an argv list whose first element is the program. Spawned directly, with NO shell: nothing is word-split, quoted, or glob-expanded, so pass each argument as its own element.
  • args — optional list appended after cmd, so { cmd = "git", args = { "log" } } and { cmd = { "git", "log" } } are equivalent.
  • cwd — optional working directory for the child.
  • env — optional { NAME = value } map of environment overrides.
  • stdin — optional string piped to the child; its stdin then closes (EOF).

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. Await it inside btv.async, or chain with :next / :catch:

btv.async(function()
  local r = btv.await(btv.run({ cmd = "git", args = { "rev-parse", "HEAD" } }))
  if r.code == 0 then btv.print(r.stdout) end
end)()

The one-shot promise twin of btv.run_stream (stream stdout as it arrives). For a duplex child whose stdin stays open for a framed protocol (LSP/DAP) use btv.process instead.

Defined in process.lua.

stream:next()

No documentation comment in the prelude.

Defined in process.lua.

stream:kill()

No documentation comment in the prelude.

Defined in process.lua.

stream:exit()

stream:exit(): how the child ENDED — a table { code, stderr } once it has exited, or nil while it is still running (so it is meaningful only after the btv.await_each loop has finished). code is the child’s real exit status; -1 means the child never ran — the binary wasn’t found, or :kill() reaped it. stdout is empty here: it was already delivered through the stream.

The point of the accessor is to tell “the tool ran and its answer was nothing” apart from “the tool isn’t installed”, which output alone cannot distinguish. A fallback chain must branch on the status, not on emptiness — rg exits 1 on zero matches, and re-searching the tree with the next tool for that is pure waste:

local stream = btv.run_stream({ cmd = "rg", args = { "--vimgrep", "--", q } })
for batch in btv.await_each(stream) do ... end
local exit = stream:exit()
if exit and exit.code == -1 then ... end  -- no rg here; try the next tool

Defined in process.lua.

stream:pid()

stream:pid(): the running child’s OS pid, or nil. The pid is reported asynchronously by the event-loop actor (it can’t be known synchronously on the single-threaded runtime) into the btv._proc_pids registry this reads — so nil before the spawn lands, on a failed spawn, and again after the child exits (the registry entry dies with the child). Handy for signalling the child out-of-band (e.g. kill -USR1) where :kill()’s reap is too blunt.

Defined in process.lua.

btv.run_stream(spec)

btv.run_stream { cmd, args, cwd, env } -> Stream. Spawns a child and streams its stdout as it arrives, in newline-delimited batches — each batch a list of lines with the trailing newline stripped. Takes the same spec as btv.run minus stdin (the child’s stdin is closed at spawn). Only stdout streams; the exit status and stderr land together at the end, on stream:exit().

The streaming twin of btv.run — reach for it when output is large or long-lived and you want to act on lines as they come (the picker / completion sources feed results this way) rather than waiting for the child to exit. Iterate it with btv.await_each inside an btv.async function; call :kill() to reap the child early (e.g. a superseded query):

btv.async(function()
  local stream = btv.run_stream({ cmd = "rg", args = { "TODO" } })
  for batch in btv.await_each(stream) do
    for _, line in ipairs(batch) do btv.print(line) end
  end
end)()

Defined in process.lua.

btv.await_each(stream)

btv.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 btv.async function (btv.await suspends the enclosing coroutine).

for batch in btv.await_each(stream) do
  for _, line in ipairs(batch) do ... end
end

Defined in process.lua.

promise:next(on_fulfilled, on_rejected)

:next(on_fulfilled, on_rejected) — the spine. Returns a NEW promise resolved with the handler’s return (adopting it if it’s itself a promise), or rejected if the handler throws. A missing handler passes the value/reason straight through to the returned promise, which is what makes a bare :catch at the end of a chain catch errors from anywhere earlier in it.

Named :next (not :then) because then is a Lua keyword — p:then(...) won’t parse. :next is the idiomatic Lua spelling; :catch/:finally keep their browser names verbatim.

Defined in promise.lua.

promise:catch(on_rejected)

:catch(on_rejected) — sugar for :next(nil, on_rejected), verbatim browser.

Defined in promise.lua.

promise:finally(on_finally)

:finally(on_finally) — run on_finally whichever way the promise settles, then pass the original value/reason through untouched (so finally can’t swallow a result or a rejection). Matches the browser’s pass-through semantics: when on_finally returns a promise (an async cleanup), the chain waits for it, and a cleanup that rejects (or throws) replaces the outcome with its own reason.

Defined in promise.lua.

btv.async(fn)

btv.async(fn) returns a function that, when called, runs fn as a coroutine and returns a promise for its result. Inside, btv.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 = btv.async(function(path)
  local stat = btv.await(fs.stat(path))
  local data = btv.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 bemtvi’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.

btv.await(awaitable)

btv.await(awaitable): suspend the enclosing btv.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 btv.async coroutine — there is nothing to suspend.

Defined in promise.lua.

btv.schedule(fn)

btv.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.

btv.schedule_wrap(fn)

btv.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.

timer:stop()

No documentation comment in the prelude.

Defined in runtime.lua.

timer:is_active()

No documentation comment in the prelude.

Defined in runtime.lua.

btv.timer(fn, timeout)

btv.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.

btv.on_next_tick(fn)

btv.on_next_tick(fn): run fn on the NEXT event-loop tick — the turn after the current one finishes. The cross-tick sibling of btv.schedule: where btv.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), btv.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.

btv.notify(msg, level, _opts)

No documentation comment in the prelude.

Defined in runtime.lua.

btv.notify_once(msg, level, opts)

btv.notify_once(msg[, level[, opts]]) [alias vim.notify_once]: btv.notify, but a given message is shown only the FIRST time it is sent this session (as neovim’s), so a deprecation warning raised from a hot path does not flood the message line. Returns true when the message was shown, false when it was suppressed as a repeat.

Defined in runtime.lua.

btv.inspect(value)

btv.inspect [alias vim.inspect]: pretty-print a value (tables recursively). A table reached again on the current descent renders as "<cycle>" — a plugin inspects arbitrary state (parent-linked trees, self-referencing registries), and unguarded recursion would blow the C stack instead of printing.

Defined in runtime.lua.

btv.exists(expr)

btv.exists(expr) [alias vim.fn.exists]: does the vim entity named by expr exist? (1 / 0). bemtvi answers the forms it can verify and reports 0 for the rest (rather than a fake

  1. so feature-probing stays honest:
  • '&opt' / '&l:opt' / '&g:opt' / '+opt' -> an option bemtvi 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 bemtvi 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.

btv.log

btv.log [alias vim.log]: the log-level constants plugins compare against.

Defined in state.lua.

btv.set_option(name, value)

btv.set_option / btv.get_option(name[, value]) [aliases nvim_set_option / nvim_get_option]: the global-scope (deprecated) accessors. Route through btv.o, the canonical global-option table that canonicalizes the scope the name implies.

Defined in state.lua.

btv.get_option(name)

No documentation comment in the prelude.

Defined in state.lua.

btv.npcall(fn, ...)

btv.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.

btv.nonnil(...)

btv.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.

btv.keytrans(s)

btv.keytrans(s) [alias vim.fn.keytrans]: translate the internal terminal-byte form of a key sequence into readable key notation (\15 → <C-o>, \r → <CR>, <Space>, …) — the exact inverse of nvim_replace_termcodes, via the native btv._keytrans (parse_keys + key_to_notation). A string already in notation round-trips through unchanged.

Defined in stdlib.lua.

btv.print(...)

btv.print(...) [alias vim.print]: pretty-print each argument (via btv.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.

btv.iter(src, state, ctrl)

btv.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.

iter:find(pred)

Iter:find(pred): the first item for which pred(item) is truthy (or, when pred is a plain value, the first item equal to it), else nil.

Defined in stdlib.lua.

iter:any(pred)

Iter:any(pred): true iff pred(item) is truthy for some item.

Defined in stdlib.lua.

iter:flatten()

Iter:flatten(): flatten one level of list-valued items into the stream.

Defined in stdlib.lua.

iter:map(f)

No documentation comment in the prelude.

Defined in stdlib.lua.

iter:filter(f)

No documentation comment in the prelude.

Defined in stdlib.lua.

iter:each(f)

No documentation comment in the prelude.

Defined in stdlib.lua.

iter:fold(acc, f)

No documentation comment in the prelude.

Defined in stdlib.lua.

iter:totable()

No documentation comment in the prelude.

Defined in stdlib.lua.

btv.line(expr)

btv.line(expr) [alias vim.fn.line]: a buffer line number (1-based). "." is the cursor line, "$" the last line (the line count), "v" the fixed end of the live Visual selection (the cursor line outside Visual mode), and "'x" the line of mark x (0 when it is not set) — the same expressions btv.pos.get takes. The window-relative forms ("w0"/"w$") are not modelled and raise an error naming the expression.

Defined in vimfn.lua.

btv.col(expr)

btv.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.

btv.localtime()

btv.localtime() [alias vim.fn.localtime]: the current time in seconds. bemtvi sources this from a MONOTONIC clock (the server’s btv._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.

btv.expand(expr)

btv.expand(expr) [alias vim.fn.expand]: the % (current file) and # (alternate file) forms autocmd callbacks and statuslines use to resolve paths, backed by the current-buffer snapshot and the # mirror. % / # are the stored names; a :<mods> suffix routes through fnamemodify (so %:t, %:p, #:h, #:r, %:~:., … all work). Any other expression errors loud. (the override below extends this with cursor keywords / globs, re-binding btv.expand.)

Defined in vimfn.lua.

btv.getmousepos()

btv.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 — bemtvi has no 'virtualedit'). Reads the btv._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.

btv.cwd()

btv.cwd() [alias vim.fn.getcwd]: the editor’s effective working directory, as an absolute path with no trailing separator.

This is editor state, not a filesystem read: it is answered from the mirror the server republishes on every :cd / :lcd, so it costs nothing and is safe on a hot path. Over a daemon it reports the daemon’s cwd — the directory relative paths actually resolve against — which is the whole reason a plugin should ask here rather than at whatever process it happens to be running in.

The fallback root: a config that walks up looking for a project marker and finds none often wants “wherever the user is working” rather than the file’s own directory.

local root = btv.await(btv.lsp.find_root(bufnr, { ".git" })) or btv.cwd()

Defined in vimfn.lua.

btv.pid()

btv.pid() [alias vim.fn.getpid]: this editor process’s id.

What a language server wants when it offers a --hostPID-style flag: it watches that process and exits when the process does, so a crashed editor doesn’t leave a server holding a project’s worth of memory. In a daemon session this is still the process the server is a child of, which is the one it must watch.

Defined in vimfn.lua.

btv.version()

btv.version() [alias vim.version]: the editor’s version, as "bemtvi <x.y.z>".

For the protocols that carry a client identity — LSP clientInfo, a vendor’s “integration version” telemetry field — and for a plugin reporting what it is running under. It is a display string, not a comparable version object: bemtvi’s surfaces are not version-gated, so there is nothing here to branch on.

Defined in vimfn.lua.

btv.stdpath(what)

btv.stdpath(what) [alias vim.fn.stdpath]: the XDG directory bemtvi keeps what in, as an absolute path with no trailing separator. "config", "data", "cache", "state", "log", "run".

Where a plugin puts the things that are neither the user’s code nor the editor’s: a downloaded language server, a parser cache, a scratch workspace. Ask here rather than composing $HOME by hand — the answer honors $XDG_* and $BEMTVI_CONFIG, so a hand-built path silently diverges from where the editor itself looks.

local workspace = btv.utils.joinpath(btv.stdpath("cache"), "jdtls", "workspace")

The directory is named, not created: btv.fs.mkdir(dir, { recursive = true }) when you are about to write into it. It raises when the process has no home, no $XDG_* base and no platform default to put the directory under — rather than answering a path relative to the working directory.

Defined in vimfn.lua.