lib.nvim · Foundation · vimdoc

:help lib.nvim

Reusable Lua/Neovim helper library

doc/lib.nvim.txt — rendered from the plugin's own vimdoc

*lib.nvim.txt*            Reusable Lua/Neovim helper library        *lib.nvim*

CONTENTS *lib.nvim-contents*

  1. Introduction ............................. |lib.nvim-introduction|
  2. Installation ............................. |lib.nvim-installation|
  3. Usage .................................... |lib.nvim-usage|
  4. Namespaces ............................... |lib.nvim-namespaces|
       lib.lua ................................ |lib.nvim-lib.lua|
       lib.nvim ............................... |lib.nvim-lib.nvim|
  5. Configuration ............................ |lib.nvim-config|
  6. Health ................................... |lib.nvim-health|
  7. Conventions .............................. |lib.nvim-conventions|
  8. Module reference ......................... |lib.nvim-modules|

1. INTRODUCTION *lib.nvim-introduction*

lib.nvim is a reusable Lua/Neovim helper library, extracted from a private
Neovim configuration so that personal plugins can share one tested base via a
|lazy.nvim| dependency.

The library is split by responsibility into two namespaces:

    lib.lua.*    general, editor-independent Lua helpers (no vim API)
    lib.nvim.*   Neovim-specific helpers (adapters onto the vim API)

Guiding rule: anything that does not need the vim API belongs in lib.lua.*.
lib.nvim.* is only an adapter onto Neovim.

2. INSTALLATION *lib.nvim-installation*

How you install lib.nvim depends on WHEN it is needed.

As a dependency of other plugins (loaded on demand):

    {
      "you/my-plugin.nvim",
      dependencies = { "StefanBartl/lib.nvim" },
    }
With packer.nvim:

    use {
      "you/my-plugin.nvim",
      requires = { "StefanBartl/lib.nvim" },
    }
The package.path bootstrap below (|lib.nvim-bootstrap|) is specific to
lazy.nvim's module loader. Under packer or another manager, adapt the same
idea: prepend lib.nvim's lua/ dir to package.path before your first
require("lib.*").

Standalone, lazily on first require:

    { "StefanBartl/lib.nvim", lazy = true }
                                                       *lib.nvim-bootstrap*

Config-wide use

If you use lib.* directly in your own config (lua/config/*, lua/plugins/*,
autocmds, mappings, ...), it is needed BEFORE lazy.nvim finishes reading your
plugin specs. A normal spec is too late, and rtp:prepend alone does not help:
lazy.nvim installs its own module loader that ignores runtimepath entries added
afterwards. You must also register lib.nvim on package.path (the C require
searcher, which lazy does not replace).

Bootstrap it in init.lua, BEFORE require("lazy").setup():

    local libpath = vim.fn.stdpath("data") .. "/lazy/lib.nvim"
    if not (vim.uv or vim.loop).fs_stat(libpath) then
      vim.fn.system({
        "git", "clone", "--filter=blob:none",
        "https://github.com/StefanBartl/lib.nvim.git", libpath,
      })
    end
    vim.opt.rtp:prepend(libpath)
    package.path = table.concat({
      libpath .. "/lua/?.lua",
      libpath .. "/lua/?/init.lua",
      package.path,
    }, ";")
Then add a managed spec so :Lazy update keeps it current:

    { "StefanBartl/lib.nvim", lazy = false, priority = 1000 }
lib.nvim has no third-party dependencies; it uses only vim and itself.

3. USAGE *lib.nvim-usage*

Direct module paths are recommended in plugin code (tree-shake friendly):

    local notify = require("lib.nvim.notify")
    local tables = require("lib.lua.tables")
    local map    = require("lib.nvim.bindings.keymap")
Or via the aggregator (require("lib")), which resolves keys on first access:

    local lib = require("lib")
    lib.notify          -- -> lib.nvim.notify
    lib.map             -- -> lib.nvim.bindings.keymap
    lib.is_windows()    -- -> lib.nvim.cross.platform.is_windows

4. NAMESPACES *lib.nvim-namespaces*


lib.lua *lib.nvim-lib.lua*

Editor-independent Lua helpers. No vim API; usable/testable outside Neovim.

    lib.lua.tables      array / dict / set / functional / safe / unique / with;
                        deep_merge (mutating recursive merge)
    lib.lua.strings     trim, split/join, case conversion, padding, slugify, …;
                        utf8 (codepoint encode/decode/iter), encoding
                        (percent-encode, base64, html_escape), distance (levenshtein,
                        similarity), format (format_bytes, format_number),
                        location (parse "path:line:col" and friends), case
                        (case_shape/apply_shape, change_case), wrap
                        (center_text, center_text_lines)
    lib.lua.functions   meta helpers: noop, identity, const, raise, …
    lib.lua.time        time / diff calculation; presets (today/yesterday/
                        last_week/this_{month,quarter,year}); format
                        (iso/human/short/log/filename/unix timestamps)
    lib.lua.json        encode (pure-Lua JSON encoder) + decode helpers
    lib.lua.yaml        minimal, deliberately non-spec-complete YAML decoder
    lib.lua.uuid        UUIDv4 generate/format
    lib.lua.numeral     roman <-> int, bijective base-26 alpha <-> int
    lib.lua.diff        lines (common-prefix/suffix splice region), myers
                        (LCS edit script)
    lib.lua.error       structured errors ({kind, message, data}) + safe_call
                        with traceback
    lib.lua.dump        recursive Lua value dumper (vim.inspect alternative)
    lib.lua.memo        memoization
    lib.lua.lazy        lazy-require proxy
    lib.lua.config      the "defaults + user overrides" store pattern:
                        deep_merge (non-mutating, arrays replaced wholesale)
                        + get(tbl, path) dot-path accessor
    lib.lua.class       prototype OOP: new/extend/include, pure Lua
    lib.lua.context_manager  try/finally as one composable primitive (with);
                        built on lib.lua.error.safe_call
    lib.lua.range       parse "1-3,5,7"-style range specs into a sorted,
                        deduplicated integer[] (page/line/commit ranges)

lib.nvim *lib.nvim-lib.nvim*

Neovim adapters.

    lib.nvim.notify        notify wrapper + log-level resolution
    lib.nvim.logger        structured logging / diagnostics / crash dumps
    lib.nvim.bindings.keymap           keymap helpers
    lib.nvim.bindings.usercmd       user-command helpers
    lib.nvim.bindings.autocmd       autocmd / augroup helpers; autocmd.dispatcher: one
                           autocmd, many handlers (lazy-loaded, prioritized,
                           per-buffer once), plus a FileType convenience
                           wrapper
    lib.nvim.buffer        buffer helpers (insert_lines, is_markdown_buf,
                           open_background, …); buffer.context: changedtick-
                           cached buffer metadata accessor; buffer.apply_edits:
                           bottom-up positional text edits with an optional
                           stale-match check per edit
    lib.nvim.buf_win_tab   buffer / window / tab utilities
    lib.nvim.window        overlay/float helpers (make_scratch, nice_quit, …);
                           window.context: same-event-cached window metadata
                           accessor
    lib.nvim.ui            kit (themed UI toolkit), highlight helpers
    lib.nvim.fs            path / filesystem helpers (vim.fs / uv); cached
                           marker-based root finding (find_root: glob markers
                           like *.rockspec, opt-in chain caching), relpath,
                           create_entry, mkdirp (mkdir -p on libuv only, safe
                           in a fast event context), normkey, project_key,
                           path_shorten,
                           collect_recursive / scan_cached / scan_roots
                           (recursive scanning, in-memory or on-disk TTL
                           cache; each has a coroutine-driven *_async
                           counterpart that doesn't block the main loop on
                           large trees), trash (cross-platform send-to-trash)
                           |lib.nvim-fs|
    lib.nvim.cross         cross-platform: OS detection, run/argv, clipboard,
                           run.env (spawn environment: guaranteed-complete
                           PATH + session/keyring vars) |lib.nvim-spawn-env|,
                           uv: spawn_capture (buffered, one callback at exit)
                           and spawn_stream (line-by-line streaming, optional
                           timeout, returns a kill handle),
                           path separators: unify_slashes (\ -> /), normalize
                           (-> OS-native), collapse_dots (lexical ./.. collapse),
                           has_win_sep (C:\ drive predicate), drive_upper
                           (uppercase C: prefix),
                           fs.wslpath (to_win / to_unix via the wslpath
                           binary; nil off WSL and for Linux-only paths)
    lib.nvim.normalize     path / value normalization
    lib.nvim.git           git helpers
    lib.nvim.terminal      terminal-buffer helpers
    lib.nvim.require       safe / dir / lazy require
    lib.nvim.lua_ls        LuaLS: module path, @module annotation
    lib.nvim.core          misc Neovim helpers (has_exec, simple_echo)
    lib.nvim.treesitter    filetype allowlist gate + prompt/auto-install
                           policy for missing treesitter parsers
                           |lib.nvim-treesitter|
    lib.nvim.system        host env snapshot + Windows rpc pipe + cross-platform
                           system info (float + clipboard, :SystemInfo usercmd)
                           + proc_trace (blocking-call instrumentation for
                           freeze diagnosis, see lua/lib/nvim/system/README.md)
    lib.nvim.selection     reselect a Visual line/char range after a mapping
                           mutates it (keep_lines, keep_chars) |lib.nvim-selection|
    lib.nvim.cache         disk: persistent JSON cache with TTL; memory:
                           namespace cache with TTL/changedtick validation
                           and opt-in, toggleable autocmd auto-invalidation
    lib.nvim.store         project: persistent state keyed by project root
                           (git root, else cwd), built on cache.disk +
                           fs.project_key |lib.nvim-store|
    lib.nvim.markdown.table  GFM pipe-table parse/render engine (parse, at_cursor,
                           render, format_lines/_buffer/_at_cursor/_file);
                           extracted from markdown.nvim and buffer-ctx.nvim,
                           see lua/lib/nvim/markdown/table/README.md
    lib.nvim.markdown.frontmatter  flat-YAML frontmatter: parse, get/set/patch,
                           update_text/update change only the touched keys
                           (byte-exact roundtrip, CRLF/BOM aware, REMOVE
                           deletes a key); see
                           lua/lib/nvim/markdown/frontmatter/README.md
    lib.nvim.health         :checkhealth authoring helpers: version_ok(min),
                           check_require(mod, label, level); see
                           lua/lib/nvim/health/README.md
    (telemetry)            opt-in call counting / usage statistics moved to
                           runtime-analysis.telemetry (runtime-analysis.nvim,
                           a sibling plugin; see that plugin's README.md and
                           documentation.nvim's docs/ECOSYSTEM.md step 7).
                           This repo keeps a thin caller,
                           lib.strategies.telemetry_wrap, for instrumenting
                           require("lib")'s own metatable-hidden aggregate
                           specifically (see lua/lib/strategies/telemetry_wrap.lua).
    lib.nvim.neotree       neo-tree.nvim-specific helpers: node (path/node
                           extraction from a neo-tree state, marks/pickers
                           share it), watch (file-watcher handle registry +
                           proactive release — fixes a Windows directory-
                           lock neo-tree's own fs_watch leaks on rename/
                           delete; drive release() from cross.fs.mutate's
                           on_retry hook, see lua/lib/nvim/neotree/watch/README.md)
    lib.nvim.contextmenu   nvzone/menu context-menu item builder (entry/
                           group/submenu, self-gating) + mouse-trigger binder
                           (bind_buffer, soft dependency) |lib.nvim-contextmenu|
    lib.nvim.async         coroutine async/await over libuv (await/run/wrap),
                           Semaphore + Condvar + LatestWins (a "newest
                           request wins" token gate for overlapping async
                           work) |lib.nvim-async|
    lib.nvim.count         count-prefix helpers for keymaps (count1 vs count
                           vs "no count" disambiguation)
    lib.nvim.debounce      generic debounce primitive: new(fn, ms) returns a
                           { call, cancel } handle
    lib.nvim.dotrepeat     wire native .-repeat through operatorfunc,
                           no vim-repeat dependency
    lib.nvim.frecency      frequency x recency ranking for anything a user
                           picks repeatedly
    lib.nvim.image_preview  in-Neovim image preview via images.nvim/
                           snacks.nvim/image.nvim (soft deps, auto-detected)
    lib.nvim.json          decode/encode arbitrary JSON strings (not just
                           files -- see lib.nvim.fs.json for that)
    lib.nvim.lastcmd       repeat the last real command (mapping or native
                           change), skipping pure motions
    lib.nvim.net.curl      async/blocking HTTP via curl (JSON / raw /
                           download-to-file tiers)
    lib.nvim.safe_api      validated, pcall-wrapped vim.api accessors for
                           buffers/windows (never raises on a deleted
                           buffer / closed window)
    lib.nvim.token         ephemeral session-nonce / token generator (NOT
                           cryptographically secure)
    lib.nvim.vregex        build \V-literal Vim-regex patterns from
                           arbitrary text (literal/escape); prevents
                           regex-injection when user/arbitrary text is
                           dropped into a search or :s pattern
    lib.nvim.checkpoint    snapshot a set of files before a destructive
                           multi-file operation (create/restore/discard),
                           byte-exact restore via fs_copyfile, built on
                           cross.fs.mutate

5. CONFIGURATION *lib.nvim-config*

The only runtime choice is which aggregator strategy require("lib") uses.
All strategies expose the same surface; they differ only in WHEN submodules
load. Configure BEFORE the first require("lib"):

    require("lib.config").setup({ strategy = "lazy" })
    local lib = require("lib")
                                                       *lib.nvim-config-strategy*

strategy

    "metatable"  (default) per-key proxy; a submodule loads on first access.
    "lazy"       eager key registry; submodules load on first access.
    "eager"      every submodule is required up-front.

Direct module paths (e.g. require("lib.nvim.notify")) ignore this setting and
are always the most efficient way to consume the library.

6. HEALTH *lib.nvim-health*

Run a diagnostic with:

    :checkhealth lib
It reports the Neovim version, the configured aggregator strategy, and
whether a representative set of modules resolves.

7. CONVENTIONS *lib.nvim-conventions*

- One module per directory with init.lua; module path == directory path.
- ---@module 'lib.<namespace>.<path>' as the first line of every file.
- LuaLS type definitions (@class, @alias, standalone @type) live in
  @types/ files, never inline in the source module.
- Internal (non-public) modules are prefixed with _ or live under
  internal/; everything else is part of the public API.
- Documentation is two-tier: a per-module README.md next to the source (the
  detailed function reference) and, for modules with :help docs, a file
  doc/lib.nvim-<module>.txt in THIS directory tagged *lib.nvim-<module>*.
  Help only works from the runtimepath-root doc/, so all .txt help lives
  here, one file per module — never in a nested doc/.

8. MODULE REFERENCE *lib.nvim-modules*

Modules with dedicated :help documentation. Jump to one via its tag, or
:help the file directly.

    lib.nvim.window      overlay / floating window helpers  |lib.nvim-window|
    lib.nvim.ui.kit      themed, composable UI toolkit       |lib.nvim-kit|
    lib.lua.time.diff    high-precision time / interval diff |lib.nvim-time_diff|
    lib.nvim.progress    style-agnostic progress indicator   |lib.nvim-progress|
    lib.nvim.treesitter  filetype allowlist gate + parser install policy |lib.nvim-treesitter|
    lib.nvim.selection   reselect a Visual range after mutation |lib.nvim-selection|
    lib.nvim.bindings.usercmd.composer  subcommand user commands + docgen |lib.nvim-composer|
    lib.nvim.fs          filesystem helpers: paths, scanning, IO, trash |lib.nvim-fs|
    lib.nvim.store       project-scoped persistent state       |lib.nvim-store|
    lib.nvim.logger      structured logging / diagnostics / crash dumps |lib.nvim-logger|
    lib.nvim.harvest     collect from a scope, then show/export it |lib.nvim-harvest|
    lib.nvim.deps        declare/detect/install external tools  |lib.nvim-deps|
    lib.nvim.cross.run.env  spawn environment: complete PATH + session vars |lib.nvim-spawn-env|
    lib.nvim.async       coroutine async/await over libuv      |lib.nvim-async|
    lib.lua.strings.width  display-width (column) arithmetic  |lib.nvim-strings_width|
    lib.nvim.contextmenu  nvzone/menu item builder + mouse-trigger binder |lib.nvim-contextmenu|

Every other module documents itself in a README.md next to its source; see
the namespace tables under |lib.nvim-namespaces|.