NORMAL ~/wkd/p/buffer-ctx/help :set skin=modern utf-8

buffer-ctx.txt

Buffer context for Neovim — buffer-ctx.nvim

doc/buffer-ctx.txt — rendered from the plugin's own vimdoc

*buffer-ctx.txt*  Buffer context for Neovim              *buffer-ctx.nvim*

Author:   Stefan Bartl
Version:  0.1.0

CONTENTS *buffer-ctx-contents*

  1. Introduction .............. |buffer-ctx-intro|
  2. Requirements .............. |buffer-ctx-requirements|
  3. Installation .............. |buffer-ctx-installation|
  4. Configuration ............. |buffer-ctx-config|
  5. Commands .................. |buffer-ctx-commands|
     5.1  filepath .............. |:Insert-filepath|
     5.2  filename .............. |:Insert-filename|
     5.3  module ................ |:Insert-module|
     5.4  location .............. |:Insert-location|
     5.5  timestamp ............. |:Insert-timestamp|
     5.6  uuid .................. |:Insert-uuid|
     5.7  annotation ............ |:Insert-annotation|
     5.8  boilerplate ........... |:Insert-boilerplate|
     5.9  env ................... |:Insert-env|
     5.10 date .................. |:Insert-date|
     5.11 snippet ............... |:Insert-snippet|
     5.12 git ................... |:Insert-git|
     5.13 linecount / bufnr ..... |:Insert-linecount|
     5.14 mdlink ................ |:Insert-mdlink|
     5.15 imagepaste ............ |:Insert-imagepaste|
  6. Format command ............ |buffer-ctx-format|
     6.1  column ................ |:Format-column|
     6.2  table ................. |:Format-table|
     6.3  textwidth ............. |:Format-textwidth|
     6.4  filter ................ |:Format-filter|
     6.5  enum .................. |:Format-enum|
     6.6  misc .................. |:Format-misc|
     6.7  squeeze ............... |:Format-squeeze|
  7. Mark command .............. |buffer-ctx-mark|
     7.1  toggle ................ |:Mark-toggle|
     7.2  yank .................. |:Mark-yank|
     7.3  clear ................. |:Mark-clear|
  8. Reveal commands ........... |buffer-ctx-reveal|
     8.1  RevealInFm ............ |:RevealInFm|
     8.2  OpenInBrowser ......... |:OpenInBrowser|
  9. Keymaps ................... |buffer-ctx-keymaps|
 10. Lua API ................... |buffer-ctx-api|
 11. Tab completion ............ |buffer-ctx-completion|
 12. Telescope integration ..... |buffer-ctx-telescope|
 13. Health check .............. |buffer-ctx-health|
 14. Architecture .............. |buffer-ctx-architecture|

1. INTRODUCTION *buffer-ctx-intro*

buffer-ctx.nvim provides two commands with (almost) an identical subcommand
catalog:

  :Insert {subcmd} [args…]   — write text at the current cursor position
  :Copy   {subcmd} [args…]   — copy text to the system clipboard (+ register)

All subcommands derive their output from the current buffer: its path, cursor
position, Lua module hierarchy, or structured content patterns. Two
subcommands are cross-plugin shims to sister plugins instead, soft-dependency
style: mdlink (|:Insert-mdlink|, delegates to markdown.nvim,
works under both commands) and imagepaste (|:Insert-imagepaste|, delegates
to images.nvim, :Insert-only — see its own section for why).

No hard dependency. Pure Lua, with one exception: the git subcommand shells
out to the git executable. Every other subcommand is shell-free.

2. REQUIREMENTS *buffer-ctx-requirements*

  - Neovim 0.9 or later
  - lib.nvim (https://github.com/StefanBartl/lib.nvim) — REQUIRED
    The :Insert/:Copy/:Format/:Mark command layer is built on
    lib.nvim.bindings.usercmd.composer. notify/map remain a soft dependency on
    top of that (nicer formatting when installed, falls back to plain
    vim.notify/vim.keymap.set otherwise).
  - (optional) which-key.nvim (https://github.com/folke/which-key.nvim)
    Labels the <leader>cn keymap group when installed.
  - (optional) telescope.nvim
    (https://github.com/nvim-telescope/telescope.nvim)
    Enables the boilerplate picker, see |buffer-ctx-telescope|.
  - (optional) git in $PATH — only for the |:Insert-git| subcommand.
  - (optional) open.nvim (https://github.com/StefanBartl/open.nvim)
    |:OpenInBrowser| delegates to its browser handler when installed;
    falls back to |vim.ui.open| (Neovim 0.10+) otherwise.
  - (optional) markdown.nvim (https://github.com/StefanBartl/markdown.nvim)
    |:Insert-mdlink| delegates to its own link builder when installed;
    falls back to a literal "[title](path)" otherwise.
  - (optional) images.nvim (https://github.com/StefanBartl/images.nvim)
    |:Insert-imagepaste| delegates to its paste feature. No local
    fallback — the subcommand fails without images.nvim installed.

3. INSTALLATION *buffer-ctx-installation*

lazy.nvim, recommended (load shortly after startup):
  {
    "stefanbartl/buffer-ctx.nvim",
    dependencies = { "stefanbartl/lib.nvim" },
    event = "VeryLazy",
    opts  = {},
  }
lazy.nvim, lazy-loaded on command use:
  {
    "stefanbartl/buffer-ctx.nvim",
    dependencies = { "stefanbartl/lib.nvim" },
    cmd  = { "Insert", "Copy", "Format", "Mark", "RevealInFm", "OpenInBrowser" },
    opts = {},
  }
packer:
  use {
    "stefanbartl/buffer-ctx.nvim",
    requires = { "stefanbartl/lib.nvim" },
    config = function()
      require("buffer_ctx").setup()
    end,
  }

4. CONFIGURATION *buffer-ctx-config*

  require("buffer_ctx").setup({
    commands = true,
    keymaps = {
      location_copy = "<leader>cnl",
      module_copy   = "<leader>cnm",
      filepath_copy = "<leader>cnf",
    },
  })

commands

  Register :Insert and :Copy. Default: true.

keymaps

  Table of keymap strings, or false to disable all keymaps.
  See |buffer-ctx-keymaps| for defaults.

which_key

  boolean  Label the <leader>cn group with which-key when installed.
  Default: true. No-op if which-key.nvim is not installed.

timestamp

  Table controlling |:Insert-timestamp|. Default:
    timestamp = { utc = false }
  utc  boolean  Emit every timestamp in UTC without passing --utc
                  each time. Default: false. An explicit --utc still
                  works; it can only turn UTC on, never off.

snippets

  Table controlling |:Insert-snippet|. Default:
    snippets = { paths = {} }
  paths  string[]  VSCode-format snippet files to load. Paths are
                     expanded, so ~ and $VAR work. Example:
    snippets = {
      paths = { vim.fn.stdpath("config") .. "/snippets/lua.json" },
    }

format

  Table controlling the :Format command tree. Default:
    format = { enable = true, command = "Format" }
  enable   boolean  Register :Format. Default: true.
  command  string   Command name. Default: "Format".
  Set format = false to disable the entire :Format tree.

mark

  Table controlling the :Mark command tree. Default:
    mark = {
      enable  = true,
      command = "Mark",
      keymaps = { toggle = "<S-m>", yank = "<C-p>" },
      sign    = { text = "●", hl = "ErrorMsg" },
      categories = {},
    }
  enable   boolean  Register :Mark. Default: true.
  command  string   Command name. Default: "Mark".
  keymaps  table    Normal-mode keymaps, or false to disable. Keys:
                      toggle, yank, clear (clear unset by default).
  sign     table    Appearance of the default category: glyph + highlight.
  categories array  Extra named appearances, each { name, text?, hl? }.
                      :Mark toggle <name> marks in that category; yank
                      and clear take a <name> to filter by it.
  Set mark = false to disable the entire :Mark tree.

reveal

  Table controlling |:RevealInFm| / |:OpenInBrowser|. Default:
    reveal = {
      enable  = true,
      keymaps = { fm = "<leader>of", browser = "<leader>ob" },
    }
  enable   boolean  Register both commands. Default: true.
  keymaps  table    Normal-mode keymaps, or false to disable. Keys:
                      fm, browser.
  Set reveal = false to disable both commands entirely.

5. COMMANDS *buffer-ctx-commands*

:Insert and :Copy accept the same subcommands and arguments, with one
exception: imagepaste (|:Insert-imagepaste|) is :Insert-only, since it
delegates to a sister plugin whose own action always inserts its result at
the cursor rather than returning text to a sink.

  :Insert {subcmd} [args…]   Insert at cursor
  :Copy   {subcmd} [args…]   Copy to clipboard

Tab completion covers the subcommand and its first argument; further tokens
have no completion (forwarded straight to the subcommand's own parser).
See |buffer-ctx-completion|.

5.1 filepath *:Insert-filepath*

  :Insert filepath [mode] [format] [depth]

Get the current buffer's file path.

mode

  cwd   relative to working directory (default)
  abs   absolute path
  nvim  relative to stdpath("config")
  repos relative to $REPOS_DIR (errors if unset)

format

  unix   forward slashes (default)
  lua    dot-separated module notation (strips extension + /lua/ prefix)
  win    backslashes
  system OS-native separator

depth

  Integer 0–3: only include the last (depth+1) path segments.

Examples:
  :Copy filepath                    → lua/buffer_ctx/ops/filepath.lua
  :Copy filepath abs                → C:/…/filepath.lua
  :Copy filepath lua                → buffer_ctx.ops.filepath
  :Copy filepath 1                  → filepath.lua
  :Copy filepath nvim               → relative to nvim config dir
  :Copy filepath repos              → relative to $REPOS_DIR
  :Copy filepath env                → "$REPOS_DIR/…" or "$NVIM_CONFIG_DIR/…"
env folds the buffer path under whichever of $REPOS_DIR / $NVIM_CONFIG_DIR
(stdpath("config")) it lives under into a literal "$VAR/…" string (longest
root wins); with neither set or matching, it falls back to the plain
cwd-relative path, same as nvim/repos do.

Compat commands are registered automatically:
  :CopyFilepathAbsolute   →  :Copy filepath absolute
  :CopyFilepathRelative   →  :Copy filepath relative
  :CopyFilepathRepos      →  :Copy filepath repos
  :CopyFilepathEnv        →  :Copy filepath env

5.2 filename *:Insert-filename*

  :Insert filename [noext]

Basename of the current buffer's file.

  noext   strip the extension

Examples:
  :Insert filename          → filepath.lua
  :Insert filename noext    → filepath

5.3 module *:Insert-module*

  :Insert module [style]

Derive the Lua module path from the /lua/ segment and emit it as a
statement or annotation.

style

  require          require("foo.bar")           (default)
  lua_ls / luals ---@module 'foo.bar'
  js               import "foo/bar"
  c                #include "foo/bar.h"
  generic          foo.bar

Examples:
  :Copy module               → require("buffer_ctx.ops.filepath")
  :Copy module lua_ls        → ---@module 'buffer_ctx.ops.filepath'

5.4 location *:Insert-location*

  :Insert location [mode] [range]

Current cursor position as path:line.

mode

  cwd  relative (default)
  abs  absolute
  lua  Lua module path

range

  Emit path:L1-L2 for a line span instead of a single line — useful for
  code-review comments and GitHub-style links.

  The span comes from the command's range. In visual mode, pressing :
  inserts '<,'> for you. Without an explicit range, the last visual
  selection's marks are used as a fallback. A single-line range has no span
  to express and collapses back to path:42.

Examples:
  :Copy location             → lua/buffer_ctx/ops/filepath.lua:42
  :Copy location abs         → C:/…/filepath.lua:42
  :Copy location lua         → buffer_ctx.ops.filepath:42
  :'<,'>Copy location range  → lua/buffer_ctx/ops/filepath.lua:L10-L20
  :10,20Copy location range  → lua/buffer_ctx/ops/filepath.lua:L10-L20

5.5 timestamp *:Insert-timestamp*

  :Insert timestamp [format] [--utc]

format

  iso       2026-06-22T14:35:00   (default)
  iso-date  2026-06-22
  iso-time  14:35:00
  unix      1750600500
  human     June 22, 2026 14:35
  short     22.06.2026
  log       2026-06-22 14:35:00
  filename  20260622_143500
  long      Monday, June 22, 2026
  weekday   Monday
  time      14:35:00              (alias of iso-time)
  12h       02:35:00 PM
  rfc2822   Mon, 22 Jun 2026 14:35:00

  --utc     output in UTC instead of local time

  weekday/long/rfc2822 always render English weekday/month names
  regardless of 'v:lang'/system locale (os.date's %A/%B/%a/%b
  follow the C locale, e.g. German renders %a as "Di"); 12h is built by
  hand since Windows' C runtime drops %p (AM/PM) silently.

Examples:
  :Insert timestamp               → 2026-06-22T14:35:00
  :Insert timestamp short --utc   → 22.06.2026 (UTC)
  :Insert timestamp 12h           → 02:35:00 PM

5.6 uuid *:Insert-uuid*

  :Insert uuid [format]

UUID v4 (randomly generated).

format

  standard  550e8400-e29b-41d4-a716-446655440000   (default)
  compact   550e8400e29b41d4a716446655440000
  upper     550E8400-E29B-41D4-A716-446655440000
  braced    {550e8400-e29b-41d4-a716-446655440000}

5.7 annotation *:Insert-annotation*

  :Insert annotation {type} [args…]

type

  module           ---@module 'foo.bar'   (from current buffer path)
  class  [name]    ---@class Name
  field  [n] [t]   ---@field name type
  param  [n] [t]   ---@param name type
  return [type]    ---@return type
  alias  [n] [t]   ---@alias Name string
  overload  [sig]  ---@overload fun(a: string): boolean
  diagnostic [c]   ---@diagnostic disable-next-line: code
  deprecated [r]   ---@deprecated Reason
  function         guided dialog → multi-line annotation block

Arguments not provided on the command line are prompted via vim.fn.input.

overload and deprecated take free text that may contain spaces; the whole
remainder of the command line is used, not just the first word. overload
wraps the signature in fun(…) if you leave that off.

:Copy annotation function joins the generated block into one \n-separated
clipboard string.

Examples:
  :Insert annotation module              → ---@module 'buffer_ctx.ops.module'
  :Insert annotation class MyService     → ---@class MyService
  :Insert annotation param name string   → ---@param name string
  :Insert annotation overload fun(): nil → ---@overload fun(): nil
  :Insert annotation diagnostic unused
      → ---@diagnostic disable-next-line: unused
  :Insert annotation deprecated use new  → ---@deprecated use new
  :Insert annotation function            → (interactive dialog)

5.8 boilerplate *:Insert-boilerplate*

  :Insert boilerplate [template] [name]

Insert (or copy) a multi-line code template. :Copy boilerplate joins lines
with newline before copying.

Called without a template name, a |vim.ui.select| picker of the available
keys is shown, so the feature does not depend on tab completion. With
telescope.nvim installed, see |buffer-ctx-telescope| for a picker that also
previews the generated lines.

Templates:
  lua-module           Lua module skeleton with setup()
  lua-class            OOP class with new() constructor
  lua-function         Annotated function stub
  nvim-autocmd         nvim_create_autocmd block
  nvim-keymap          vim.keymap.set stub
  guard-clause         Guard clause pattern (interactive)
  html-figure          <figure> with <img> + <figcaption>
  html-code            Code listing <figure>
  html-quote           Blockquote <figure>
  html-formula-table   Formula reference table
  html-aside           <aside> block
  html-pagination      Pagination <nav>
  html-accordion       <details> accordion
  html-table           <table> with thead + 3x3 body
  html-section         <section> with h2 + p
  lua-test             busted stub (describe/it/assert.are.equal)
  lua-enum             Enum table + ---@alias block
  md-frontmatter       YAML frontmatter block
Examples:
  :Insert boilerplate                     (interactive picker)
  :Insert boilerplate lua-module
  :Insert boilerplate lua-class MyService
  :Insert boilerplate nvim-autocmd MyAuGroup
  :Copy   boilerplate html-figure intro

5.9 env *:Insert-env*

  :Insert env {VAR}

Insert or copy the value of an environment variable. A leading $ is
stripped automatically. Tab completion lists the variables currently set.

Examples:
  :Copy env GOPATH
  :Insert env HOME
  :Copy env $PATH

5.10 date *:Insert-date*

  :Insert date [format] [--utc]

Shorthand for |:Insert-timestamp| defaulting to iso-date instead of iso
— same [format] values (iso, iso-date, iso-time, unix, human,
short, log, filename, long, weekday, time, 12h, rfc2822) and
the same --utc flag apply. Honours the timestamp.utc config option, see
|buffer-ctx-config|.

Examples:
  :Insert date                    → 2026-06-22
  :Insert date long               → Monday, June 22, 2026
  :Insert date iso --utc          → 2026-06-22T14:35:00 (UTC)

5.11 snippet *:Insert-snippet*

  :Insert snippet [name]

Insert a snippet from the VSCode-format files listed in snippets.paths,
see |buffer-ctx-config|. Without a name, a |vim.ui.select| picker is shown.

A snippet resolves by its key or by its prefix, so both of these work for
the file below:
  :Insert snippet "For Loop"
  :Insert snippet forl
File format:
  {
    "For Loop": {
      "prefix": "forl",
      "body": ["for ${1:i} = 1, ${2:10} do", "\t$0", "end"],
      "description": "numeric for loop"
    }
  }
Placeholders are flattened rather than expanded: ${1:i} becomes i,
${1|a,b|} becomes a, and bare tabstops ($0, $1) are removed.
buffer-ctx inserts plain text — for real tabstop navigation use a dedicated
snippet engine.

5.12 git *:Insert-git*

  :Insert git [mode]

Git revision info for the repository the current buffer belongs to. The query
runs in the buffer's own directory, so the result stays correct after |:cd|.

mode

  short   abbreviated commit hash (default)
  hash    full commit hash
  branch  current branch name
  tag     nearest tag, else abbreviated hash (git describe --tags --always)

Requires the git executable in $PATH. On a detached HEAD, branch reports
an error instead of returning the literal string "HEAD".

Examples:
  :Insert git                → a577942
  :Copy   git hash           → a577942dedbcb4e8a4e9ffb3529be12b27b58736
  :Copy   git branch         → main

5.13 linecount / bufnr *:Insert-linecount*

                                                        *:Insert-bufnr*

  :Insert linecount
  :Insert bufnr

Line count of the current buffer, and the current buffer handle. Useful for
documentation references and for Lua scripting/debugging respectively.

Examples:
  :Insert linecount          → 348
  :Insert bufnr              → 3

5.14 mdlink *:Insert-mdlink*

  :Insert mdlink [mode] [format] [depth]

Wrap the current buffer's path in a Markdown link ("[title](path)"). Takes
the exact same mode/format/depth arguments as |:Insert-filepath| —
whatever :Copy filepath ... would produce is what gets wrapped.

Cross-plugin shim: delegates to markdown.nvim's own
markdown.commands.markdown_links.for_paths() (the function behind
:Markdown links <path>) when markdown.nvim is installed — soft dependency,
pcall(require, ...), same convention as ui.kit in commands.lua's
resolve_kit(). Falls back to the literal "[%s](%s)" format inline
otherwise (markdown.nvim hardcodes the exact same format for a single file,
so nothing behaves differently either way).

Examples:
  :Copy mdlink                      → [filepath.lua](lua/buffer_ctx/ops/filepath.lua)
  :Insert mdlink abs                → [filepath.lua](C:/…/filepath.lua)
  :Copy mdlink repos                → [filepath.lua](buffer-ctx.nvim/lua/…/filepath.lua)

5.15 imagepaste *:Insert-imagepaste*

  :Insert imagepaste [name] [path=relative|absolute|repos|<prefix>]

Paste the clipboard image via images.nvim's own paste feature
(require("images").paste(name, nil, path_mode)) — the exact same
{name}/path=... grammar :Image paste itself accepts, so this is a
convenience alias for reaching that action through buffer-ctx's own
:Insert family rather than a second implementation of it.

:Insert-only, unlike every other subcommand above: images.nvim's paste
reads the OS clipboard *asynchronously* and inserts the resulting Markdown
link directly into the buffer at the cursor itself — there is no "give me
the link text instead" mode to route through :Copy's clipboard sink, so
:Copy imagepaste does not exist (attempting it errors "unknown
subcommand", the same as any other typo).

Cross-plugin shim: soft dependency on images.nvim, pcall(require, "images")
re-checked on every call, same convention as ui.kit in commands.lua's
resolve_kit(). Without images.nvim installed, this errors rather than
falling back — reimplementing its clipboard-read pipeline here would
duplicate platform-specific logic that already exists once, there, on
purpose.

Examples:
  :Insert imagepaste
  :Insert imagepaste screenshot-1
  :Insert imagepaste path=absolute

6. FORMAT COMMAND *buffer-ctx-format*

  :Format {subcmd} [args…]

Unified buffer/selection formatting. Tab completion covers the subcommand
and its first argument (e.g. -r/--reverse for sort, a style/key=
for enum); further tokens have no completion.

6.1 column *:Format-column*

  :Format column [<N> [fill]]

With a column number: align the character under the cursor (or visually
selected block column) to column N, padding with fill (default: space).

Without arguments: opens an interactive prompt for N and fill character.

Examples:
  :Format column 40       → pad current char to column 40 with spaces
  :Format column 40 =     → pad with "=" character
  :Format column          → interactive prompt

6.2 table *:Format-table*

  :Format table [ALIGN] [header=ALIGN] [cell=ALIGN] [skip=COL] [scope=SCOPE]

Format Markdown tables in the current buffer, a file, or the entire cwd.

ALIGN

  left, center, right    Positional shorthand for header + cell align.

header=ALIGN

  Alignment for the header row (default: center).

cell=ALIGN

  Alignment for data rows (default: center).

skip=COL

  Column number(s) or name(s) to force-align left (comma-separated).

scope=SCOPE

  cursor  Format only the table under the cursor (default).
  buffer  Format all tables in the current buffer.
  cwd     Format all *.md files under the working directory.

Examples:
  :Format table                          → format table at cursor
  :Format table left                     → all columns left-aligned
  :Format table header=left cell=right   → mixed alignment
  :Format table scope=buffer             → format every table in buffer

6.3 textwidth *:Format-textwidth*

  :Format textwidth <N|max>

Set textwidth to N (or the current window width if max) and reflow the
entire buffer using word-wrap, preserving paragraph breaks and list prefixes.

Examples:
  :Format textwidth 80
  :Format textwidth max

6.4 filter *:Format-filter*

  :Format filter [--remove] <pattern> [<pattern>…]

Keep lines that match ALL patterns. With --remove (or -r): remove
matching lines instead.

Examples:
  :Format filter TODO              → keep only lines containing "TODO"
  :Format filter --remove FIXME   → remove lines containing "FIXME"
  :Format filter foo bar           → keep lines containing both "foo" and "bar"

6.5 enum *:Format-enum*

  :Format enum [STYLE] [sep=SEP] [start=N] [inline=true|false]

Enumerate whitespace-separated tokens from the visual selection.

STYLE

  decimal  1. 2. 3.          (default)
  alpha    a. b. c.
  ALPHA    A. B. C.
  roman    i. ii. iii.
  ROMAN    I. II. III.

sep=SEP

  Separator string after each label. Default: ". ".

start=N

  First counter value. Default: 1.

inline=true|false

  true   emit all on one line.
  false  emit one per line.
  auto     single-line input → inline, multi-line → one per line.

Examples:
  :Format enum                     → 1. foo  2. bar  (decimal, inline)
  :Format enum roman               → i. foo  ii. bar
  :Format enum alpha inline=false  → a. foo\nb. bar
  :Format enum sep=) start=3       → 3) foo  4) bar

6.6 misc subcommands *:Format-misc*

  :Format trim
    Remove trailing whitespace from every line in the buffer.

  :Format sort [-r] [-i] [-n]
    Sort buffer lines.  -r reverse, -i ignore-case, -n numeric.

  :Format unique [-i]
    Remove duplicate lines.  -i ignore-case.

  :Format case <upper|lower|title|sentence>
    Change the case of every line.

  :Format indent [--spaces|--tabs] [N]
    Normalise indentation using the current expandtab/shiftwidth, or the
    flags/width provided.

  :Format clear
    Erase all lines in the buffer.

6.7 squeeze *:Format-squeeze*

  :Format squeeze

Collapse consecutive blank lines down to at most one, so a run of blank
lines never separates two pieces of text by more than a single empty line.

Operates on the whole buffer by default. With an explicit range — a visual
selection (press : right after v/V/CTRL-V, Neovim fills in '<,'> for
you) or a plain line range — only that span is squeezed; a blank line just
outside the range is left untouched, since it was not part of the selection.

Examples:
  :Format squeeze             (whole buffer)
  :'<,'>Format squeeze        (visual selection only)
  :10,20Format squeeze        (explicit line range only)

7. MARK COMMAND *buffer-ctx-mark*

  :Mark {subcmd} [category]

Toggle per-line marks, clear them, and collect them to the system clipboard.
Marks are stored per buffer and survive buffer switches (until Neovim exits).

A marked line is indicated by a ● character:
  • In the sign column when signcolumn ≠ "no"
  • As a left-column extmark otherwise

toggle, yank and clear each take an optional category name (configured
via mark.categories, see |buffer-ctx-config|); yank/clear then act only
on marks in that category. Tab completion is supported for the subcommand and
the category argument.

Compat commands are registered automatically:
  :MarkLineToggle   →  :Mark toggle
  :MarkLinesYank    →  :Mark yank

7.1 toggle *:Mark-toggle*

  :Mark toggle

Toggle the mark on the current line.  If the line is already marked the mark
is removed; otherwise it is added.

Marks are anchored to the text, not to a line number: they follow their line
as you insert or delete lines above them, and toggling recognises a mark by
where it sits now.  Deleting a marked line removes its mark (Neovim 0.10+;
on 0.9 the mark moves to the following line instead).

Marks are session-only and are cleared when the buffer is deleted or wiped.

Default keymap: <S-m>

7.2 yank *:Mark-yank*

  :Mark yank

Collect all marked lines in the current buffer and write them to the system
clipboard (+ register) as newline-separated text.

Lines come out in buffer order — that is, ordered by where each mark sits at
the time of the yank, not by the order the marks were created in.

A notification reports how many lines were copied.

Default keymap: <C-p>

7.3 clear *:Mark-clear*

  :Mark clear [category]

Remove every mark in the current buffer, or — with a category name — only the
marks in that category. Before this the only way to unmark was toggling each
line one at a time.

No keymap by default. Bind one with mark.keymaps.clear, see
|buffer-ctx-config|.

8. REVEAL COMMANDS *buffer-ctx-reveal*

Two independent, argument-less commands -- unlike |buffer-ctx-format| and
|buffer-ctx-mark| there is no shared subcommand tree here. Both act on the
current buffer's own path. Disable either (or both) via opts.reveal, see
|buffer-ctx-config|.

8.1 RevealInFm *:RevealInFm*

  :RevealInFm

Reveals the current buffer in the system file manager -- a file selected
inside its parent directory (Explorer/Finder/Nautilus/…). Delegates to
lib.nvim's cross.reveal_in_fm, the exact dispatcher filetree.nvim's
<leader>fm and open.nvim's :Open filemanager handler already share, so a
fix there lands here too. No fallback: lib.nvim is already a hard dependency
for this plugin's command layer (see |buffer-ctx-requirements|).

Default keymap: <leader>of

8.2 OpenInBrowser *:OpenInBrowser*

  :OpenInBrowser

Opens the current buffer with the OS-registered application for it -- a
browser for an .html file, whatever else the OS associates otherwise.

Prefers open.nvim's own browser handler when open.nvim is installed
(require("open").open("browser", "%"), an explicit target+scope so
open.nvim dispatches straight to it rather than running its own no-target
heuristic). Falls back to |vim.ui.open| (Neovim 0.10+) when open.nvim is
absent.

Default keymap: <leader>ob

9. KEYMAPS *buffer-ctx-keymaps*

Registered only when setup() is called (or keymaps = false to disable).

  <leader>cnl  Copy path:line  (location, cwd-relative)
  <leader>cnm  Copy Lua module path
  <leader>cnf  Copy filepath   (cwd-relative, unix format)

  <S-m>        :Mark toggle    (toggle mark on current line)
  <C-p>        :Mark yank      (yank all marked lines to clipboard)

  <leader>of   :RevealInFm     (reveal current buffer in file manager)
  <leader>ob   :OpenInBrowser  (open current buffer in the browser)

All keys are configurable via the respective config tables.

When which-key.nvim is installed, the <leader>cn prefix is automatically
labeled "buffer-ctx: copy context". Set which_key = false to disable this.

10. LUA API *buffer-ctx-api*

  local ctx = require("buffer_ctx")
setup({opts})                                      *buffer_ctx.setup()*
  Configure and activate. Idempotent.

insert({subcmd}, {args})                          *buffer_ctx.insert()*
  Insert at cursor. Equivalent to :Insert {subcmd} [args…].

copy({subcmd}, {args})                              *buffer_ctx.copy()*
  Copy to clipboard. Equivalent to :Copy {subcmd} [args…].

Examples:
  ctx.copy("location", {})
  ctx.copy("module", { "lua_ls" })
  ctx.insert("uuid", { "braced" })
  ctx.insert("boilerplate", { "lua-class", "MyService" })

11. TAB COMPLETION *buffer-ctx-completion*

Both :Insert and :Copy provide context-aware tab completion:

  :Insert <Tab>                 → list all subcommands
  :Insert filepath <Tab>        → cwd, abs, nvim, lua, unix, win, system, 0–3
  :Insert mdlink <Tab>          → same values as filepath (see above)
  :Insert module <Tab>          → require, lua_ls, js, c, generic
  :Insert timestamp <Tab>       → iso, iso-date, iso-time, unix, human, …
  :Insert uuid <Tab>            → standard, compact, upper, braced
  :Insert annotation <Tab>      → module, class, field, param, return, …
  :Insert boilerplate <Tab>     → lua-module, lua-class, nvim-autocmd, …
  :Insert location <Tab>        → cwd, abs, lua, range
  :Insert git <Tab>             → hash, short, branch, tag
  :Insert snippet <Tab>         → snippet keys and prefixes from your files
  :Insert env <Tab>             → environment variables currently set

12. TELESCOPE INTEGRATION *buffer-ctx-telescope*

With telescope.nvim installed, register the extension:
  require("telescope").load_extension("buffer_ctx")
Then:
  :Telescope buffer_ctx boilerplate
The picker lists every boilerplate template with its description and previews
the exact lines it would generate. Selecting one inserts it at the cursor.

Telescope is an optional dependency — the extension file is only ever loaded
by Telescope itself, so the plugin works standalone without it.

13. HEALTH CHECK *buffer-ctx-health*

  :checkhealth buffer_ctx
Checks:
  - Neovim >= 0.9
  - vim.uv / vim.loop available
  - vim.fn.setreg available
  - Plugin loaded (guard flag set)
  - lib.nvim detected? (required — command layer, lib.nvim.bindings.usercmd.composer)
  - lib.nvim detected? (optional — notify upgrade)
  - lib.nvim detected? (optional — map upgrade)
  - which-key detected? (optional — <leader>cn group label)
  - markdown.nvim detected? (optional — :Insert/:Copy mdlink's own link builder)
  - images.nvim detected? (optional, no local fallback — :Insert imagepaste)
  - buffer_ctx.bindings loadable
  - :CopyFilepathAbsolute, :CopyFilepathRelative, :CopyFilepathRepos and :CopyFilepathEnv compat commands registered
  - Format subsystem: enabled flag, :Format registered, each sub-module loadable
  - Mark subsystem: enabled flag, :Mark and :MarkLineToggle registered
  - Reveal subsystem: enabled flag, :RevealInFm/:OpenInBrowser registered,
    lib.nvim.cross.reveal_in_fm detected (required), open.nvim or vim.ui.open
    detected (optional — :OpenInBrowser's fallback chain)

14. ARCHITECTURE *buffer-ctx-architecture*

  plugin/buffer_ctx.lua        Load guard
  lua/buffer_ctx/
    init.lua                   Public API, setup()
    config/
      init.lua                 setup()/get() — deep-merge over DEFAULTS
      DEFAULTS.lua              Plugin-side default configuration
    @types.lua                 LuaLS annotations
    commands.lua               :Insert / :Copy (lib.nvim.bindings.usercmd.composer) + shared dispatch
    health.lua                 checkhealth provider
    bindings/
      init.lua                  Orchestrates usrcmds + keymaps + autocmds
      usrcmds.lua                Registers :Insert / :Copy
      keymaps.lua                The 3 core copy keymaps (+ the <leader>cn
                                 which-key group label, carried in the spec)
      autocmds.lua               Extension point (no autocmds registered today)
    format/
      init.lua                 :Format command (lib.nvim.bindings.usercmd.composer) + subcommand registry
      column_align.lua         Column-alignment (visual selection)
      table_fmt.lua            Markdown table formatter
      text_width.lua           Text reflow (word-wrap)
      filter_lines.lua         Line filter (keep / remove)
      enum_lines.lua           Token enumeration for visual selection
      misc.lua                 trim, sort, unique, case, indent, clear
      blank_lines.lua          squeeze (collapse blank-line runs, range-aware)
    mark/
      init.lua                 :Mark command (lib.nvim.bindings.usercmd.composer) + toggle/clear/yank logic + compat cmds
    reveal/
      init.lua                 :RevealInFm / :OpenInBrowser (lib.nvim.bindings.usercmd, plain -- no composer verb needed for two argument-less commands) + keymaps
    util/
      notify.lua               "[buffer-ctx] " notify wrapper; upgrades to lib.nvim if present
      map.lua                  keymap wrapper; upgrades to lib.nvim.bindings.keymap if present
      cursor.lua               insert_text / insert_lines at cursor position
      clip.lua                 setreg("+", …) + notify
      path.lua                 get_module_path, relative_to_cwd, pick_depth
    ops/
      filepath.lua             Path formatting (mode + format + depth)
      module.lua               Lua module path → statement
      timestamp.lua            Timestamp generation (13 formats)
      uuid.lua                 UUID v4 generation
      annotation.lua           LuaLS annotation lines (with interactive dialog)
      location.lua             path:line (and path:L1-L2) from cursor/range
      env.lua                  Environment variable lookup + completion list
      git.lua                  Git revision info (hash/short/branch/tag)
      bufinfo.lua              Buffer line count and handle
      snippet.lua              VSCode-format snippet loading
      reveal.lua               reveal_in_fm / open.nvim / vim.ui.open dispatch (side effects, no text return)
      markdown_link.lua        [title](path) wrapper; delegates to markdown.nvim when installed
      imagepaste.lua           images.nvim "paste" delegate (side effect, no text return -- like reveal.lua)
      boilerplate/
        init.lua               Template registry + dispatch
        templates/
          lua.lua              Lua code templates
          nvim.lua             Neovim-specific templates
          html.lua             HTML snippet templates
          markdown.lua         Markdown templates (frontmatter)
          guard.lua            Guard clause pattern
          utils.lua            Shared prompt helpers
  lua/telescope/_extensions/
    buffer_ctx.lua              Optional Telescope boilerplate picker
  docs/
    BINDINGS.md                 Keymap / command / autocommand cheatsheet
  TESTS/                        Headless spec suite (run.lua)

Module load order: util → ops → commands/format/mark → bindings → init

keys

j / k
next / previous line
gg / G
first / last line
⏎
open the line under the cursor
/
search the plugins
:
command line — Tab completes
:help x
vimdoc of a plugin (:e x = plugin page)
:ls · :log · :stack
plugin list · activity stream · dependency graph
:colo x
colorscheme
:set skin=
modern | tui
?
this help
esc
close