Markdown text objects allow you to operate on document structures using standard Vim operators like d (delete), c (change), y (yank), and v (visual select). These objects are aware of Markdown syntax, enabling precise editing of formatted text, links, and structural blocks.

When the Neovim RPC backend is connected, emphasis, inline code, math, strikethrough, links and wikilinks, code fences, blockquotes, callouts, tags, table rows, and table cells execute inside Neovim through buffer-local mappings. The companion uses Neovim’s bundled Markdown treesitter parsers for structural ranges and native it/at for tags, then applies operators to an explicit bounded character range. i= / a= highlight objects are unavailable in RPC mode because the bundled grammar does not expose ==...== as a node; delimiter scanning is intentionally not substituted for a treesitter range.

Markdown text objects

Operate on Markdown structures with standard Vim operators (d, c, y, v).

The Neovim RPC backend supports the tree-backed objects below in operator-pending and visual modes. i= / a= remains fork-only because Neovim’s bundled Markdown grammar has no highlight node.

KeybindingDescription
i* / a*Inside/around bold (**...**) or italic (*...*)
i_ / a_Inside/around italic (_..._)
i` / a`Inside/around inline code
i$ / a$Inside/around math ($...$ or $$...$$), with smart disambiguation
i~ / a~Inside/around strikethrough (~~...~~)
i= / a=Inside/around highlight (==...==)
il / alInside/around links ([[wikilink]] or [text](url))
iC / aCInside/around fenced code blocks
iB / aBInside/around blockquotes (>)
io / aoInside/around callouts (> [!type])
it / atInside/around HTML/XML tags
ir / arInside/around table row (raw markdown only)
i| / a|Inside/around table cell (between | pipes)
iS / aSSubword
in / anNumber
iq / aqAny quote
iD / aDDouble brackets
gLURL
i, / a,Argument
ii / aiIndentation
Link to original

Delimiter text objects

The following text objects operate on inline Markdown delimiters:

  • i* / a*: Bold (**...**) or italic (*...*)
  • i_ / a_: Underscore italic (_..._)
  • i` / a`: Inline code (`...`)
  • i$ / a$: Math ($...$ or $$...$$)
  • i~ / a~: Strikethrough (~~...~~)
  • i= / a=: Highlight (==...==)

These objects support multi-line scanning, allowing you to select content that spans across line breaks. To maintain performance, the scanner skips lines within fenced code blocks.

Inner objects require the cursor to be inside the content, not on the opening or closing delimiter. Around objects also work with the cursor on a delimiter. Tree-backed matching checks the actual delimiter character and width, so $...$ is not mistaken for $$...$$, and ~~...~~ includes both tildes on each side.

Bracket objects search forward

The bracket objects i( / i{ / i[ / i< (and ib / iB) find the next pair ahead of the cursor when the cursor is not already inside one, matching Neovim. The search is not limited to the current line, and it never looks backwards — past the last pair in the document, the operator is a no-op.

Smart asterisk disambiguation

i* tries to match **bold** first, then falls back to *italic*. In cases of nested formatting like ***bold italic***, the ** pair is matched first. Use i_ for underscore italic to select the italic portion specifically.

Smart dollar disambiguation

i$ / a$ tries to match $$ (block math) first, then falls back to $ (inline math). For nested math like $$ $inner$ $$, the $$ pair is matched first.

Configurable scan range

The multi-line scanner searches a set number of lines in each direction (default: 20). You can adjust this in Settings → Vim Motions → Advanced → Multi-line text object scan range (5–200 lines).

Link text objects (il / al) support both wikilinks and standard Markdown links:

  • Wikilinks: [[Link]] or [[Link|Alias]]
  • Markdown links: [Text](URL)

il selects the content inside the brackets or parentheses, while al selects the entire link structure.

Block text objects

Block text objects operate on structural Markdown elements:

  • Code blocks (iC / aC): Fenced code blocks starting and ending with ```.
  • Blockquotes (iB / aB): Lines prefixed with >.
  • Callouts (io / ao): Obsidian callouts (> [!type]).

Blockquotes select contiguous lines at the cursor line’s nesting depth or deeper, supporting both >> and > > prefixes. Unmarked continuation lines and shallower outer quote lines are excluded, even when the Markdown parser includes them in the same paragraph. Inner selections preserve the full opening quote prefix; around selections remove nested quote lines without leaving an extra empty line between adjacent quote lines.

The scanner for these blocks skips lines within fenced code blocks to avoid false positives. Note that fenced code blocks inside blockquotes (> ```) are currently not detected as separate blocks.

Tag text objects

Tag text objects (it / at) allow you to operate on HTML or XML tags within your Markdown files. These are implemented via raw text scanning rather than a full HTML parser to ensure compatibility with Markdown-mixed content.

General-purpose text objects

These text objects provide standard Vim-like behavior for common programming and writing patterns:

  • iS / aS — Subword: camelCase, snake_case, or kebab-case segments. Around includes the trailing separator.
  • in / an — Number: Full numeric literals, including signs and decimals. Around includes surrounding whitespace.
  • iq / aq — Any quote: The nearest quote pair (", ', or `) on the current line.
  • iD / aD — Double brackets: Wikilink-style [[...]] content. Supports nested brackets.
  • gL — URL: Forward-seeking URL selection. Jumps to the next URL on the line and selects it.
  • i, / a, — Argument: Comma-separated arguments in lists or function calls. Supports nesting (e.g., func(a, [b, c], d)).
  • ii / ai — Indentation: Contiguous lines with same-or-greater indentation. Around includes parent line above and trailing blank lines.

Custom text objects via Lua

You can define your own text objects using the Lua API. This is useful for custom delimiters or specific document structures.

Defining pairs

The vim.gen_spec.pair() function creates a text object specification for delimiter pairs:

-- Inner angle bracket
vim.textobject.add('i<', vim.gen_spec.pair('<', '>'))
-- Around angle bracket
vim.textobject.add('a<', vim.gen_spec.pair('<', '>'))

API Reference

  • vim.textobject.add(keys, spec): Registers a new text object. keys must start with i or a.
  • vim.gen_spec.pair(open, close, opts?): Generates a pair specification.
    • multiline (boolean, default true): Whether to search across multiple lines.

See lua-config > vim.textobject for more examples and details.

Table cell text objects

Table cell text objects (i| / a|) operate on individual cells within Markdown tables:

  • i|: Selects the content inside the cell (between the | pipes).
  • a|: Selects the content plus the trailing pipe.

These objects are particularly useful for quickly changing or deleting cell data without affecting the table structure.

See known-limitations > Text objects for detailed technical limitations.