-
-
Notifications
You must be signed in to change notification settings - Fork 7
10.Lua API
markdown-plus exposes a Lua API for plugin authors and for anyone scripting their own mappings, commands or autocommands.
Everything here is also in the help file — :help markdown-plus-api.
local mp = require("markdown-plus")| Function | Description |
|---|---|
mp.setup(opts) |
Validate and merge config, load enabled features, register <Plug> mappings and autocommands |
mp.teardown() |
Undo everything setup() did and restore the default config |
mp.config |
The merged, validated config table (read-only in practice) |
mp.in_list_context(kind) |
Whether the cursor is in list context — see Customizing Keymaps |
mp.enable_features_for_buffer() |
Enable features for the current buffer manually |
mp.setup_autocmds() |
Re-register the FileType autocommands |
setup() is the only function most users ever call.
Resets plugin-managed state so setup() can be re-run cleanly:
require("markdown-plus").teardown()It disables per-buffer features across loaded buffers, clears the augroup,
removes the buffer-local default keymaps it installed, resets the <Plug>
registration cache and the keymap-fallback state, drops the module handles, and
restores mp.config to the shipped defaults.
Important
This is not a full unload. The global <Plug> mappings created by an earlier
setup() are not deleted — only the cache that tracks them is cleared, so the
next setup() re-registers them. Invoking a <Plug> mapping in between still runs
the handler it captured.
This makes setup() safely re-runnable, which is what the test suite relies on.
It is also handy while tuning your config:
vim.keymap.set("n", "<leader>mr", function()
require("markdown-plus").teardown()
package.loaded["markdown-plus"] = nil
require("markdown-plus").setup({ --[[ new options ]] })
end, { desc = "Reload markdown-plus" })Each feature is exposed as a field on the root module:
require("markdown-plus").headers.generate_toc()
require("markdown-plus").footnotes.list()Important
These handles are nil until setup() has run, and they are only assigned
when the matching features.* flag is enabled. If you disable a feature, its
handle stays nil.
local mp = require("markdown-plus")
if mp.headers then
mp.headers.generate_toc()
endrequire() the module directly if you want it regardless of the feature flags:
require("markdown-plus.headers").generate_toc()| Handle | Module path |
|---|---|
mp.list |
markdown-plus.list |
mp.format |
markdown-plus.format |
mp.thematic_break |
markdown-plus.thematic_break |
mp.headers |
markdown-plus.headers |
mp.links |
markdown-plus.links |
mp.images |
markdown-plus.images |
mp.quotes |
markdown-plus.quote |
mp.callouts |
markdown-plus.callouts |
mp.code_block |
markdown-plus.code_block |
mp.table |
markdown-plus.table |
mp.footnotes |
markdown-plus.footnotes |
Note
The quotes handle is plural (mp.quotes) but the module path is singular
(markdown-plus.quote). Easy to trip over.
| Function | Description |
|---|---|
in_list_context(kind) |
true if the cursor is in list context for 'enter', 'backspace' or 'indent'
|
handle_enter() |
Insert-mode <CR> handler |
continue_list_content() |
Continue content without starting a new bullet |
handle_tab() / handle_shift_tab()
|
Indent / outdent the item |
handle_backspace() |
Insert-mode <BS> handler |
handle_normal_o() / handle_normal_O()
|
Normal-mode o / O handlers |
renumber_ordered_lists() |
Renumber every ordered list in the buffer |
debug_list_groups() |
Print the parsed list groups — useful for bug reports |
The handlers are not predicates and do not report whether they acted. When the
cursor is not in list context they emulate the native behavior for that key
themselves and return nothing. If you need to branch before calling one, use
in_list_context(kind).
| Function | Description |
|---|---|
toggle_format(format_type) |
Toggle formatting over the visual selection |
toggle_format_word(format_type) |
Toggle formatting on the word under the cursor |
strip_all_formatting(text) |
Return text with all markup removed |
toggle_escape_selection() |
Escape / unescape Markdown punctuation in the selection |
convert_to_code_block() |
Convert the visual selection into a fenced block |
clear_formatting() / clear_formatting_word()
|
Clear formatting on selection / word |
get_lines_in_range(start_row, end_row) |
Fetch a line range |
| Function | Description |
|---|---|
promote_header() / demote_header()
|
Add / remove a #
|
set_header_level(level) |
Set the line to a specific level (1–6) |
toggle_atx_setext() |
Switch an H1/H2 between ATX and setext style |
next_header() / prev_header()
|
Jump between headers |
generate_toc() / update_toc()
|
Create / refresh the table of contents |
follow_link() |
Follow the TOC link under the cursor — returns boolean
|
open_toc_window(window_type) |
Interactive TOC: 'vertical' (default), 'horizontal' or 'tab'
|
parse_header(line, next_line) |
Parse an ATX or setext heading |
| Function | Description |
|---|---|
insert_with_language() |
Insert a fenced block, prompting for the language |
wrap_selection() |
Wrap the visual selection in a fence |
change_language() |
Change the language of the block under the cursor |
toggle_fence_style() |
Switch between backtick and tilde fences |
find_all_blocks() |
Every fenced block in the buffer |
find_block_at_cursor() |
The block containing the cursor, or nil
|
find_block_at_cursor() is the one to reach for when you need to make your own
mapping defer inside code blocks.
| Function | Description |
|---|---|
insert() |
Insert a break below the cursor, adding blank lines as needed |
cycle_style() |
Rotate --- → *** → ___ → ---
|
| Function | Description |
|---|---|
insert_link() |
Prompt for text and URL, insert an inline link |
selection_to_link() |
Turn the visual selection into the link text |
edit_link() |
Edit the link under the cursor |
auto_link_url() |
Wrap a bare URL in <>
|
convert_to_reference() / convert_to_inline()
|
Convert between link styles |
find_reference_url(ref) |
Resolve a reference label to its URL |
Smart paste lives in a submodule rather than on the links handle:
require("markdown-plus.links.smart_paste").smart_paste()It is a no-op unless links.smart_paste.enabled is true in your config.
| Function | Description |
|---|---|
insert_image() |
Prompt for alt text and path, insert an image |
selection_to_image() |
Turn the visual selection into the alt text |
edit_image() |
Edit the image under the cursor |
get_image_at_cursor() |
Return the image under the cursor, or nil
|
toggle_image_link() |
Switch between  and [alt](src)
|
| Function | Description |
|---|---|
quote.toggle_quote() |
Toggle blockquote on the line or selection |
callouts.insert_callout(type) |
Insert a callout of a given type |
callouts.insert_callout_prompt() |
Insert a callout, prompting for the type |
callouts.wrap_selection_in_callout() |
Wrap the selection in a callout |
callouts.toggle_callout_type() |
Cycle the type of the callout under the cursor |
callouts.convert_to_callout() / convert_to_blockquote()
|
Convert between the two |
callouts.get_callout_at_cursor() |
The callout under the cursor, or nil
|
callouts.is_valid_callout_type(type) |
Validate a callout type string |
The largest module. Everything below operates on the table under the cursor; most are no-ops outside one.
| Function | Description |
|---|---|
is_in_table() |
true if the cursor is inside a table |
create_table(rows, cols) |
Create a rows × cols table — both arguments are required |
format_table() / normalize_table()
|
Realign columns / normalize structure |
move_left() / move_right() / move_up() / move_down()
|
Move between cells |
edit_cell() / clear_cell()
|
Edit / empty the current cell |
wrap_cell() / unwrap_cell()
|
Toggle soft wrapping in a cell |
insert_break() |
Insert a line break inside a cell |
insert_row_above() / insert_row_below()
|
Insert a row |
delete_row() |
Delete the current row |
move_row_up() / move_row_down()
|
Reorder rows |
insert_column_left() / insert_column_right()
|
Insert a column |
delete_column() |
Delete the current column |
move_column_left() / move_column_right()
|
Reorder columns |
toggle_cell_alignment() |
Cycle the column's alignment marker |
sort_ascending() / sort_descending()
|
Sort rows by the current column |
transpose_table() |
Swap rows and columns |
csv_to_table() / table_to_csv()
|
Convert between CSV and Markdown tables |
| Function | Description |
|---|---|
insert() |
Insert a reference and, if needed, its definition |
edit() |
Jump to the definition and enter insert mode |
delete() |
Delete every reference plus the definition |
goto_definition() / goto_reference()
|
Jump between the two |
next_footnote() / prev_footnote()
|
Walk references in document order |
list() |
Picker showing every footnote and its health |
get_all_footnotes() |
Every footnote with its references and definition |
get_next_id() |
The next unused numeric ID |
get_footnote_at_cursor() |
The footnote under the cursor, or nil
|
get_all_footnotes() is what you want for a lint-style check — each entry
carries its definition and reference list, so orphans and missing definitions
are easy to spot.
| Function | Description |
|---|---|
get_lines_in_range(start_row, end_row) |
Fetch a line range |
get_code_block_lines(lines) |
Map of which lines fall inside fenced blocks |
build_markdown_link(text, url, title) |
Build [text](url "title")
|
build_markdown_image(alt, url, title) |
Build 
|
Three buffer-local commands are available in Markdown buffers when the
headers_toc feature is enabled:
| Command | Equivalent |
|---|---|
:Toc |
headers.open_toc_window("vertical") |
:Toch |
headers.open_toc_window("horizontal") |
:Toct |
headers.open_toc_window("tab") |
They are only created if a command of that name does not already exist on the buffer, so they will not clobber a command from another plugin.
-
Customizing Keymaps —
in_list_contextrecipes and plugin interop -
Plug Mappings — the full
<Plug>reference -
:help markdown-plus-api— the same reference inside Neovim