- 🚀 Introduction
- ✨ Features
- 💾 Installation
- ⚙️ Configuration
- 🛠️ Commands & mappings
- 📚 API
- 🤝 Contributing
- 🔢 Version information
- 🔗 Related projects
Mkdnflow is designed for the fluent navigation and management of markdown documents and document collections (notebooks, wikis, etc). It features numerous convenience functions that make it easier to work within raw markdown documents or document collections: link and reference handling (🔗 Link and reference handling), navigation (🧭 Navigation), table support (📊 Table support), list (📝 List support) and to-do list (✅ To-do list support) support, file management (📁 File management), section folding (🪗 Folding), and more. Use it for notetaking, personal knowledge management, static website building, and more. Most features are highly tweakable (⚙️ Configuration).
- Jump to links
- Jump to section headings
- Link following
- Open markdown and other text filetypes in the current window
- Open other filetypes and URLs with your system's default application
- Browser-like 'Back' and 'Forward' functionality
- Table of contents window
- Link creation from a visual selection or the text under the cursor
- Link destruction
- Follow links to local paths and other Markdown files
- Follow external links (open using default application)
- Follow
.bib-based references- Open
urlordoifield in the default browser - Open documents specified in
filefield
- Open
- Implicit filetype extensions
- Support for various link types
- Standard Markdown links (
[my page](my_page.md)) - Wiki links (direct
[[my page]]or piped[[my_page.md|my page]]) - Automatic links (
<https://my.page>) - Reference-style links (
[my page][1]with[1]: my_page.md) - Image links (
) — opened in system viewer - Citations (
@citekeyor Pandoc-style[@citekey]) - Footnotes (
[^1]with[^1]: Footnote text)
- Standard Markdown links (
- Table creation
- Table extension (add rows and columns)
- Table formatting
- Pandoc grid table support
- Column alignment (left, right, center)
- Paste delimited data as a table
- Import delimited file into a new table
- Automatic list extension
- Sensible auto-indentation and auto-dedentation
- Ordered list number updating
- Toggle to-do item status
- Status propagation
- To-do list sorting
- Create to-do items from plain ordered or unordered list items
- Customizable highlighting for to-do status markers and content
- Simultaneous link and file renaming
- As-needed directory creation
- Section folding and fold toggling
- Helpful indicators for folded section contents
- Section heading level
- Counts of Markdown objects (tables, lists, code blocks, etc.)
- Line and word counts
- YAML block folding
- Path completion
- Completion of bibliography items
- Specify a bibliography file in YAML front matter
- Conceal markdown and wiki link syntax
- Extended link highlighting
- Automatic links
- Wiki links
Requirements:
- Linux, macOS, or Windows
- Neovim >= 0.9.5 (tested on 0.9.5, 0.10.x, and stable)
Install Mkdnflow using your preferred package manager for Neovim. Once installed, Mkdnflow is configured and initialized using a setup function.
Install with Lazy
require('lazy').setup({
-- Your other plugins
{
'jakewvincent/mkdnflow.nvim',
ft = { 'markdown', 'rmd' }, -- Add custom filetypes here if configured
config = function()
require('mkdnflow').setup({
-- Your config
})
end
}
-- Your other plugins
})Install with Vim-Plug
" Vim-Plug
Plug 'jakewvincent/mkdnflow.nvim'
" Include the setup function somewhere else in your init.vim file, or the
" plugin won't activate itself:
lua << EOF
require('mkdnflow').setup({
-- Config goes here; leave blank for defaults
})
EOFMkdnflow is configured and initialized using a setup function. To use the default settings, pass no arguments or an empty table to the setup function:
{
'jakewvincent/mkdnflow.nvim',
config = function()
require('mkdnflow').setup({})
end
}Most features are highly configurable. Study the default config first and read the documentation for the configuration options below or in the help files.
🔧 Complete default config
{
modules = {
bib = true,
buffers = true,
conceal = true,
cursor = true,
folds = true,
foldtext = true,
links = true,
lists = true,
maps = true,
paths = true,
tables = true,
templates = true,
to_do = true,
yaml = false,
cmp = false,
},
create_dirs = true,
silent = false,
wrap = false,
on_attach = false,
path_resolution = {
primary = 'first',
fallback = 'current',
root_marker = false,
sync_cwd = false,
update_on_navigate = true,
},
filetypes = {
markdown = true,
rmd = true,
},
foldtext = {
object_count = true,
object_count_icon_set = 'emoji',
object_count_opts = function()
return require('mkdnflow').foldtext.default_count_opts()
end,
line_count = true,
line_percentage = true,
word_count = false,
title_transformer = function()
return require('mkdnflow').foldtext.default_title_transformer
end,
fill_chars = {
left_edge = '⢾⣿⣿',
right_edge = '⣿⣿⡷',
item_separator = ' · ',
section_separator = ' ⣹⣿⣏ ',
left_inside = ' ⣹',
right_inside = '⣏ ',
middle = '⣿',
},
},
bib = {
default_path = nil,
find_in_root = true,
},
cursor = {
jump_patterns = nil,
},
links = {
style = 'markdown',
compact = false,
conceal = false,
search_range = 0,
implicit_extension = nil,
transform_on_follow = false,
transform_on_create = function(text)
text = text:gsub('[ /]', '-')
text = text:lower()
text = os.date('%Y-%m-%d_') .. text
return text
end,
transform_scope = 'path',
auto_create = true,
on_create_new = false,
},
new_file_template = {
enabled = false,
placeholders = {
before = {
title = 'link_title',
date = 'os_date',
},
after = {},
},
template = '# {{ title }}',
},
to_do = {
highlight = false,
statuses = {
{
name = 'not_started',
symbol = ' ',
colors = {
marker = { link = 'Conceal' },
content = { link = 'Conceal' },
},
sort = { section = 2, position = 'top' },
skip_on_toggle = false,
propagate = {
up = function(host_list) ... end,
down = function(child_list) ... end,
},
},
{
name = 'in_progress',
symbol = '-',
colors = {
marker = { link = 'WarningMsg' },
content = { bold = true },
},
sort = { section = 1, position = 'bottom' },
skip_on_toggle = false,
propagate = {
up = function(host_list) ... end,
down = function(child_list) end,
},
},
{
name = 'complete',
symbol = { 'X', 'x' },
colors = {
marker = { link = 'String' },
content = { link = 'Conceal' },
},
sort = { section = 3, position = 'top' },
skip_on_toggle = false,
propagate = {
up = function(host_list) ... end,
down = function(child_list) ... end,
},
},
},
status_propagation = {
up = true,
down = true,
},
sort = {
on_status_change = false,
recursive = false,
cursor_behavior = {
track = true,
},
},
},
tables = {
type = 'pipe',
trim_whitespace = true,
format_on_move = true,
auto_extend_rows = false,
auto_extend_cols = false,
style = {
cell_padding = 1,
separator_padding = 1,
outer_pipes = true,
apply_alignment = true,
},
},
yaml = {
bib = { override = false },
},
mappings = {
MkdnEnter = { { 'n', 'v' }, '<CR>' },
MkdnGoBack = { 'n', '<BS>' },
MkdnGoForward = { 'n', '<Del>' },
MkdnMoveSource = { 'n', '<F2>' },
MkdnNextLink = { 'n', '<Tab>' },
MkdnPrevLink = { 'n', '<S-Tab>' },
MkdnFollowLink = false,
MkdnDestroyLink = { 'n', '<M-CR>' },
MkdnTagSpan = { 'v', '<M-CR>' },
MkdnYankAnchorLink = { 'n', 'yaa' },
MkdnYankFileAnchorLink = { 'n', 'yfa' },
MkdnNextHeading = { 'n', ']]' },
MkdnPrevHeading = { 'n', '[[' },
MkdnIncreaseHeading = { { 'n', 'v' }, '+' },
MkdnDecreaseHeading = { { 'n', 'v' }, '-' },
MkdnIncreaseHeadingOp = { { 'n', 'v' }, 'g+' },
MkdnDecreaseHeadingOp = { { 'n', 'v' }, 'g-' },
MkdnToggleToDo = { { 'n', 'v' }, '<C-Space>' },
MkdnNewListItem = false,
MkdnNewListItemBelowInsert = { 'n', 'o' },
MkdnNewListItemAboveInsert = { 'n', 'O' },
MkdnExtendList = false,
MkdnUpdateNumbering = { 'n', '<leader>nn' },
MkdnTableNextCell = { 'i', '<Tab>' },
MkdnTablePrevCell = { 'i', '<S-Tab>' },
MkdnTableNextRow = false,
MkdnTablePrevRow = { 'i', '<M-CR>' },
MkdnTableNewRowBelow = { 'n', '<leader>ir' },
MkdnTableNewRowAbove = { 'n', '<leader>iR' },
MkdnTableNewColAfter = { 'n', '<leader>ic' },
MkdnTableNewColBefore = { 'n', '<leader>iC' },
MkdnTableDeleteRow = { 'n', '<leader>dr' },
MkdnTableDeleteCol = { 'n', '<leader>dc' },
MkdnFoldSection = { 'n', '<leader>f' },
MkdnUnfoldSection = { 'n', '<leader>F' },
MkdnTab = false,
MkdnSTab = false,
MkdnIndentListItem = { 'i', '<C-t>' },
MkdnDedentListItem = { 'i', '<C-d>' },
MkdnCreateLink = false,
MkdnCreateLinkFromClipboard = { { 'n', 'v' }, '<leader>p' },
},
}require('mkdnflow').setup({
modules = {
bib = true,
buffers = true,
conceal = true,
cursor = true,
folds = true,
foldtext = true,
links = true,
lists = true,
maps = true,
paths = true,
tables = true,
to_do = true,
yaml = false,
cmp = false,
}
})| Option | Type | Description |
|---|---|---|
modules.bib |
boolean |
true (default): bib module is enabled (required for parsing .bib files and following citations).false: Disable bib module functionality. |
modules.buffers |
boolean |
true (default): buffers module is enabled (required for backward and forward navigation through buffers).false: Suppress buffers keybindings. Note: This is a core module and is always loaded internally because other modules depend on it. Setting this to false only disables its keybindings. |
modules.conceal |
boolean |
true (default): conceal module is enabled (required if you wish to enable link concealing. This does not automatically enable conceal behavior; see links.conceal.)false: Disable conceal module functionality. |
modules.cursor |
boolean |
true (default): cursor module is enabled (required for cursor movements: jumping to links, headings, etc.).false: Suppress cursor keybindings. Note: This is a core module and is always loaded internally because other modules depend on it. Setting this to false only disables its keybindings. |
modules.folds |
boolean |
true (default): folds module is enabled (required for section folding).false: Disable folds module functionality. |
modules.foldtext |
boolean |
true (default): foldtext module is enabled (required for prettified foldtext).false: Disable foldtext module functionality. |
modules.links |
boolean |
true (default): links module is enabled (required for creating, destroying, and following links).false: Suppress links keybindings. Note: This is a core module and is always loaded internally because other modules depend on it. Setting this to false only disables its keybindings. |
modules.lists |
boolean |
true (default): lists module is enabled (required for working in and manipulating lists, etc.).false: Disable lists module functionality. |
modules.to_do |
boolean |
true (default): to_do module is enabled (required for manipulating to-do statuses/lists, toggling to-do items, to-do list sorting, etc.)false: Disable to_do module functionality. |
modules.paths |
boolean |
true (default): paths module is enabled (required for link interpretation, link following, etc.).false: Suppress paths keybindings. Note: This is a core module and is always loaded internally because other modules depend on it. Setting this to false only disables its keybindings. |
modules.tables |
boolean |
true (default): tables module is enabled (required for table management, navigation, formatting, etc.).false: Disable tables module functionality. |
modules.templates |
boolean |
true (default): templates module is enabled (required for new-file template formatting and injection when following links to non-existent files).false: Disable templates module functionality. Template injection will be skipped even if new_file_template.enabled is true. |
modules.yaml |
boolean |
true: yaml module is enabled (required for parsing yaml headers).false (default): Disable yaml module functionality. |
modules.cmp |
boolean |
true: cmp module is enabled (required if you wish to enable completion for nvim-cmp).false (default): Disable cmp module functionality. |
require('mkdnflow').setup({
create_dirs = true,
})| Option | Type | Description |
|---|---|---|
create_dirs |
boolean |
true (default): Directories referenced in a link will be (recursively) created if they do not exist.false: No action will be taken when directories referenced in a link do not exist. Neovim will open a new file, but you will get an error when you attempt to write the file. |
require('mkdnflow').setup({
path_resolution = {
primary = 'first',
fallback = 'current',
root_marker = false,
sync_cwd = false,
update_on_navigate = false,
},
})| Option | Type | Description |
|---|---|---|
path_resolution.primary |
string |
'first' (default): Links will be interpreted relative to the first-opened file (when the current instance of Neovim was started).'current': Links will always be interpreted relative to the current file.'root': Links will be always interpreted relative to the root directory of the current notebook (requires path_resolution.root_marker to be specified).Previously named perspective.priority. |
path_resolution.fallback |
string |
'first': (see above)'current' (default): (see above)'root': (see above) |
path_resolution.root_marker |
string | boolean |
false (default): The plugin does not look for the notebook root.string: The name of a file (not a full path) by which a notebook's root directory can be identified. For instance, '.root' or 'index.md'.Previously named perspective.root_tell. |
path_resolution.sync_cwd |
boolean |
true: Changes in path resolution will be reflected in the nvim working directory. (In other words, the working directory will sync with the plugin's path resolution.) This helps ensure (at least) that path completions (if using a completion plugin with support for paths) will be accurate and usable.false (default): Neovim's working directory will not be affected by Mkdnflow.Previously named perspective.nvim_wd_heel. |
path_resolution.update_on_navigate |
boolean |
true: Path resolution will be updated when following a link to a file in a separate notebook/wiki (or navigating backwards to a file in another notebook/wiki).false (default): Path resolution will be not updated when following a link to a file in a separate notebook/wiki. (Links in the file in the separate notebook/wiki will be interpreted relative to the original notebook/wiki.)Previously named perspective.update. |
require('mkdnflow').setup({
filetypes = {
markdown = true,
rmd = true,
},
})| Option | Type | Description |
|---|---|---|
filetypes.markdown |
boolean |
true (default): The plugin activates for files with the markdown filetype (includes .md, .markdown, .mkd, .mkdn, .mdwn, .mdown extensions).false: The plugin does not activate for markdown files. |
filetypes.rmd |
boolean |
true (default): The plugin activates for files with the rmd filetype (.rmd extension).false: The plugin does not activate for R Markdown files. |
filetypes.<name> |
boolean | string |
Custom filetype/extension configuration: - true: If Neovim recognizes this as an extension (e.g., md), the detected filetype is used. Otherwise, the extension is auto-registered as its own filetype (e.g., wiki = true registers .wiki files as filetype wiki).- 'filetype' (string): Register this extension as the specified filetype. Example: txt = 'markdown' makes .txt files activate mkdnflow and be treated as markdown.- false: Disable for this filetype/extension.Note: Old extension-based configs (e.g., md = true) are automatically migrated to filetype-based configs (e.g., markdown = true).Examples: lua<br>filetypes = {<br> markdown = true, -- Standard (default)<br> rmd = true, -- Standard (default)<br> wiki = true, -- Auto-register .wiki as 'wiki' filetype<br> txt = 'markdown', -- Treat .txt files as markdown<br>}<br> |
Note
Mkdnflow activates based on Neovim's filetype detection, not file extensions.
This means files with modelines like vim: ft=markdown will activate the plugin
regardless of their extension.
Lazy loading note: If you use a plugin manager with lazy loading (e.g., ft = { 'markdown' })
and configure custom extensions like wiki = true, you must add those filetypes
to your lazy loading configuration (e.g., ft = { 'markdown', 'wiki' }), since the
plugin won't load until it sees a matching filetype.
require('mkdnflow').setup({
wrap = false,
})| Option | Type | Description |
|---|---|---|
wrap |
boolean |
true: When jumping to next/previous links or headings, the cursor will continue searching at the beginning/end of the file.false (default): When jumping to next/previous links or headings, the cursor will stop searching at the end/beginning of the file. |
require('mkdnflow').setup({
bib = {
default_path = nil,
find_in_root = true,
},
})| Option | Type | Description |
|---|---|---|
bib.default_path |
string | nil |
nil (default): No default/fallback bib file will be used to search for citation keys.string: A path to a default .bib file to look for citation keys in when attempting to follow a reference. The path need not be in the root directory of the notebook. |
bib.find_in_root |
boolean |
true (default): When path_resolution.primary is also set to root (and a root directory was found), the plugin will search for bib files to reference in the notebook's top-level directory. If bib.default_path is also specified, the default path will be added to the list of bib files found in the top-level directory so that it will also be searched.false: The notebook's root directory will not be searched for bib files. |
require('mkdnflow').setup({
silent = false,
})| Option | Type | Description |
|---|---|---|
silent |
boolean |
true: The plugin will not display any messages in the console except compatibility warnings related to your config.false (default): The plugin will display messages to the console. |
require('mkdnflow').setup({
cursor = {
jump_patterns = nil,
},
})| Option | Type | Description |
|---|---|---|
cursor.jump_patterns |
table | nil |
nil (default): Cursor jumping (MkdnNextLink/MkdnPrevLink) uses detection-based link finding, which reuses the same link detection system as followLink(). All recognized link types (markdown links, wiki links, auto links, reference links, citations, footnote refs with definitions) are automatically jumped to based on the configured links.style. Links inside fenced code blocks and inline code spans are skipped.table: A table of additional Lua regex patterns to jump to alongside detected links. Useful for non-link targets like TODO markers (e.g. { 'TODO', 'FIXME' }).{} (empty table): No extra patterns; only detected links are jumped to (same as nil). |
cursor.yank_register |
string |
'"' (default): Anchor links are yanked to the unnamed register.'+': Yank to the system clipboard.'<any register>': Yank to any valid Vim register (e.g. 'a', '*', '0'). |
require('mkdnflow').setup({
links = {
style = 'markdown',
compact = false,
conceal = false,
search_range = 0,
implicit_extension = nil,
transform_on_follow = false,
transform_on_create = function(text)
text = text:gsub(" ", "-")
text = text:lower()
text = os.date('%Y-%m-%d_') .. text
return(text)
end,
auto_create = true,
on_create_new = false,
},
})| Option | Type | Description |
|---|---|---|
links.style |
string |
'markdown' (default): Links will be expected in the standard markdown format: [<title>](<source>)'wiki': Links will be expected in the unofficial wiki-link style, specifically the title-after-pipe format: [[<source>|<title>]].This sets the default style for link creation. To create links in both styles, you can override the style per-call via :MkdnCreateLink wiki (or markdown), or via the Lua API: createLink({ style = 'wiki' }). See 'custom-mappings-on-attach' for an example. |
links.compact |
boolean |
true: Wiki-style links will be created with the source and name being the same (e.g. [[Link]] will display as "Link" and go to a file named "Link.md").false (default): Wiki-style links will be created with separate name and source (e.g. [[link-to-source|Link]] will display as "Link" and go to a file named "link-to-source.md").Previously named links.name_is_source. |
links.conceal |
boolean |
true: Link sources and delimiters will be concealed (depending on which link style is selected).false (default): Link sources and delimiters will not be concealed by mkdnflow. |
links.ref_hint |
boolean |
true: When the cursor is on a reference-style link ([text][ref] or [label]), the resolved URL is shown as virtual text at the end of the line. When the cursor is on a reference definition line ([ref]: url), a usage count is shown instead. The virtual text uses the MkdnflowRefHint highlight group, which is linked to Comment by default. To customize its appearance, override the highlight group, e.g. vim.api.nvim_set_hl(0, 'MkdnflowRefHint', { fg = '#88aaff', italic = true }).false (default): No virtual text hints for reference links. |
links.search_range |
integer |
When following or jumping to links, consider n lines before and after a given line (useful if you ever permit links to be interrupted by a hard line break). Default: 0.Previously named links.context. |
links.implicit_extension |
string |
A string that instructs the plugin (a) how to interpret links to files that do not have an extension, and (b) how to create new links from the text under the cursor or text selection.nil (default): Extensions will be explicit when a link is created and must be explicit in any notebook link.'<any extension>' (e.g. 'md'): Links without an extension (e.g. [Homepage](index)) will be interpreted with the implicit extension (e.g. index.md), and new links will be created without an extension. |
links.transform_on_create |
fun(string): string | boolean |
false: No transformations are applied to the text to be turned into the name of the link source/path.fun(string): string (default): A function that transforms the text to be inserted as the source/path of a link when a link is created. Anchor links are not currently customizable. For an example, see the sample recipes beneath this table.Previously named links.transform_explicit. |
links.transform_scope |
string |
Controls which part of the link text is passed to transform_on_create when the text contains /.'path' (default): The entire text (including directory components) is passed to transform_on_create. For example, work/with/dirs is transformed as a single string, and the default transform produces 2026-02-15_work-with-dirs.md.'filename': Only the filename portion (after the last /) is passed to transform_on_create; the directory prefix is preserved. For example, work/with/dirs becomes work/with/2026-02-15_dirs.md.If the text contains no /, both modes behave identically.Can be overridden per-call via the Lua API: createLink({ transform_scope = 'filename' }), or via command argument: :MkdnCreateLink filename. |
links.transform_on_follow |
fun(string): string | boolean |
false (default): Do not perform any transformations on the link's source when following.fun(string): string: A function that transforms the path of a link immediately before interpretation. It does not transform the actual text in the buffer but can be used to modify link interpretation. For an example, see the sample recipe below.Previously named links.transform_implicit. |
links.auto_create |
boolean |
true (default): Try to create a link from the text under the cursor if there is no link under the cursor to follow.false: Do nothing if trying to follow a link and a link can't be found under the cursor.Previously named links.create_on_follow_failure. |
links.on_create_new |
false | fun(string, string|nil): string|nil |
A callback invoked when following a link to a file that does not yet exist, allowing file creation to be delegated to an external tool (e.g. zk,Obsidian CLI, a custom script). This callback is only invoked when the target file does not yet exist. Following a link to an existing file bypasses this callback entirely. The function receives two arguments: the full resolved path (with extension) that mkdnflow would create, and the link's display text (which may be nil).It should return a string (file path for mkdnflow to open) or nil (if thecallback handled everything). If a path is returned and the file exists there, mkdnflow opens it directly (skipping template injection). If the file does not exist at the returned path, mkdnflow runs its normal creation flow. false (default): Use mkdnflow's built-in file creation. |
links.uri_handlers |
table<string, fun(uri: string, scheme: string, path: string, anchor: string|nil)|'system'> |
A table of custom URI scheme handlers, keyed by scheme name (without ://).When following a link whose path starts with <scheme>://, the registeredhandler is called instead of the normal path classification. This is useful for custom protocols like phd://, zotero://, obsidian://, etc.Each value can be: - A function fun(uri, scheme, path, anchor) receiving the full URI(with anchor reattached), the scheme name, the path (without anchor), and the anchor (e.g. '#section') or nil. The function has full controlover what happens when the link is followed. - The string 'system' to open the URI with the OS default handler(same as how http:// URLs are opened).Standard schemes like http and https can also be overridden byregistering a handler for them. {} (default): No custom URI scheme handlers are registered.Example: lua<br>links = {<br> uri_handlers = {<br> phd = function(uri, scheme, path, anchor)<br> vim.fn.jobstart({ 'xdg-open', uri }, { detach = true })<br> end,<br> zotero = 'system',<br> },<br>}<br> |
Sample links recipes
require('mkdnflow').setup({
links = {
-- If you want all link paths to be explicitly prefixed with the year
-- and for the path to be converted to uppercase:
transform_on_create = function(input)
return(string.upper(os.date('%Y-')..input))
end,
-- Link paths that match a date pattern can be opened in a `journals`
-- subdirectory of your notebook, and all others can be opened in a
-- `pages` subdirectory:
transform_on_follow = function(input)
if input:match('%d%d%d%d%-%d%d%-%d%d') then
return('journals/'..input)
else
return('pages/'..input)
end
end
}
})Delegate new-file creation to zk:
require('mkdnflow').setup({
links = {
on_create_new = function(path, title)
-- Let zk create the note with its own templates and ID scheme.
-- `zk new` prints the created path to stdout.
local dir = vim.fn.fnamemodify(path, ':h')
local cmd = { 'zk', 'new', '--no-input', '--print-path', dir }
if title then
table.insert(cmd, '--title')
table.insert(cmd, title)
end
local result = vim.fn.system(cmd)
local new_path = vim.trim(result)
if vim.v.shell_error ~= 0 then
vim.notify('zk new failed: ' .. result, vim.log.levels.ERROR)
return nil
end
return new_path -- mkdnflow opens the zk-created file
end,
},
})require('mkdnflow').setup({
new_file_template = {
enabled = false,
placeholders = {
before = { title = 'link_title', date = 'os_date' },
after = {},
},
template = '# {{ title }}',
},
})| Option | Type | Description |
|---|---|---|
new_file_template.enabled |
boolean |
true: Use the new-file template when opening a new file by following a link.false (default): Don't use the new-file template when opening a new file by following a link.Previously named new_file_template.use_template. |
new_file_template.placeholders |
table<string, string|fun(ctx: table): string> |
A flat table whose keys are placeholder names mapped to one of: - A function fun(ctx): string — called with a context table containing all resolved built-in values. Available fields in ctx:- link_title — the display text of the link under the cursor, or ''- os_date — today's date as YYYY-MM-DD- source_file — basename of the source file (e.g. 'index.md')- filename — stem of the new file being created, without extension (e.g. 'my-page')- heading_context — text of the nearest heading above the cursor (without # prefix), or ''- A magic string shorthand — one of 'link_title' or 'os_date', which resolves to the corresponding ctx value.- A plain string literal — used as-is (e.g., author = 'Jake').All placeholders are resolved in a single pass before the new buffer is opened. Default: { title = 'link_title', date = 'os_date' }Deprecated: The old nested format { before = {...}, after = {} } is auto-migrated to this flat format. placeholders.after entries are merged in but all placeholders now resolve before the buffer switch. |
new_file_template.template |
string |
A string, optionally containing placeholder names, that will be inserted into a new file. Default: '# {{ title }}' |
require('mkdnflow').setup({
to_do = {
highlight = false,
status_propagation = { up = true, down = true },
sort = {
on_status_change = false,
recursive = false,
cursor_behavior = { track = true },
},
statuses = { ... }, -- See full default in docs
},
})| Option | Type | Description |
|---|---|---|
to_do.highlight |
boolean |
true: Apply highlighting to to-do status markers and/or content (as defined in to_do.statuses[*].highlight).false (default): Do not apply any highlighting. |
to_do.status_propagation.up |
boolean |
true (default): Update ancestor statuses (recursively) when a descendant status is changed or when a new to-do item is added to a list (e.g. a completed parent reverts to in-progress when a new uncompleted child is added). Updated according to logic provided in to_do.statuses[*].propagate.up.false: Ancestor statuses are not affected by descendant status changes or new item creation. |
to_do.status_propagation.down |
boolean |
true (default): Update descendant statuses (recursively) when an ancestor's status is changed. Updated according to logic provided in to_do.statuses[*].propagate.down.false: Descendant statuses are not affected by ancestor status changes. |
to_do.sort_on_status_change |
boolean |
true: Sort a to-do list when an item's status is changed.false (default): Leave all to-do items in their current position when an item's status is changed.Note: This will not apply if the to-do item's status is changed manually (i.e. by typing or pasting in the status marker). |
to_do.sort.recursive |
boolean |
true: sort_on_status_change applies recursively, sorting the host list of each successive parent until the root of the list is reached.false (default): sort_on_status_change only applies at the current to-do list level (not to the host list of the parent to-do item). |
to_do.sort.cursor_behavior.track |
boolean |
true (default): Move the cursor so that it remains on the same to-do item, even after a to-do list sort relocates the item.false: The cursor remains on its current line number, even if the to-do item is relocated by sorting. |
to_do.statuses |
table (array-like) |
A list of tables, each of which represents a to-do status. See options in the following rows. An arbitrary number of to-do status tables can be provided. See default statuses in the settings table. |
to_do.statuses[*].name |
string |
The designated name of the to-do status. |
to_do.statuses[*].marker |
string | table |
The marker symbol to use for the status. The marker's string width must be 1. When provided as a string (e.g. ' '), the string is used as both the recognized and written marker.When provided as a table (e.g. { 'X', 'x' }), the first element is the primary marker — the one written to the buffer when the status is set. Any additional elements are legacy markers that will be recognized as belonging to this status when read from a file, but will be replaced with the primary marker on the next toggle. This is useful for accepting alternate symbols from other tools or conventions without losing compatibility. |
to_do.statuses[*].highlight.marker |
table (highlight definition) |
A table of highlight definitions to apply to a status marker, including brackets. See the {val} parameter of :h nvim_set_hl for possible options. |
to_do.statuses[*].highlight.content |
table (highlight definition) |
A table of highlight definitions to apply to the to-do item content (everything following the status marker). See the {val} parameter of :h nvim_set_hl for possible options. |
to_do.statuses[*].skip_on_toggle |
boolean |
true: When toggling/rotating a to-do item's status, skip this status in the rotation.false: Leave the status in the rotation.Note: This setting is useful if there is a status marker that you never want to manually set and only want to apply when automatically updating ancestors or descendants. Previously named to_do.statuses[*].exclude_from_rotation. |
to_do.statuses[*].sort.section |
integer |
The integer should represent the linear section of the list in which items of this status should be placed when sorted. A section refers to a segment of a to-do list. If you want items with the 'in_progress' status to be first in the list, you would set this option to 1 for the status.Note: Sections are not visually delineated in any way other than items with the same section number occurring on adjacent lines in the list. |
to_do.statuses[*].sort.position |
string |
Where in its assigned section a to-do item should be placed:'top': Place a sorted item at the top of its corresponding section.'bottom': Place a sorted item at the bottom of its corresponding section.'relative': Maintain the current relative order of the sorted item whose status was just changed (vs. other list items). |
to_do.statuses[*].propagate.up |
fun(to_do_list): string | nil |
A function that accepts a to-do list instance and returns a valid to-do status name. The list passed in is the list that hosts the to-do item whose status was just changed. The return value should be the desired value of the parent. Return nil to leave the parent's status as is. |
to_do.statuses[*].propagate.down |
fun(to_do_list): string[] |
A function that accepts a to-do list instance and returns a list of valid to-do status names. The list passed in will be the child list of the to-do item whose status was just changed. Return nil or an empty table to leave the children's status as is. |
Warning
The following to-do configuration options are deprecated. Please use the
to_do.statuses table instead. Continued support for these options is
temporarily provided by a compatibility layer that will be removed in the
near future.
to_do.symbols- A list of markers representing to-do completion statusesto_do.not_started- Which marker represents a not-yet-started to-doto_do.in_progress- Which marker represents an in-progress to-doto_do.complete- Which marker represents a complete to-doto_do.update_parents- Whether parent to-dos' statuses should be updated
require('mkdnflow').setup({
foldtext = {
object_count = true,
object_count_icon_set = 'emoji',
object_count_opts = function()
return require('mkdnflow').foldtext.default_count_opts()
end,
line_count = true,
line_percentage = true,
word_count = false,
title_transformer = function()
return require('mkdnflow').foldtext.default_title_transformer
end,
fill_chars = {
left_edge = '⢾⣿⣿',
right_edge = '⣿⣿⡷',
item_separator = ' · ',
section_separator = ' ⣹⣿⣏ ',
left_inside = ' ⣹',
right_inside = '⣏ ',
middle = '⣿',
},
},
})| Option | Type | Description |
|---|---|---|
foldtext.object_count |
boolean |
true (default): Show a count of all objects inside of a folded section.false: Do not show a count of any objects inside of a folded section. |
foldtext.object_count_icon_set |
string | table |
'emoji' (default): Use pre-defined emojis as icons for counted objects.'plain': Use pre-defined plaintext UTF-8 characters as icons for counted objects.'nerdfont': Use pre-defined nerdfont characters as icons for counted objects. Requires a nerdfont.table<string, string>: Use custom mapping of object names to icons. |
foldtext.object_count_opts |
fun(): table<string, table> |
A function that returns the options table defining the final attributes of the objects to be counted, including icons and counting methods. The pre-defined object types are tbl, ul, ol, todo, img, fncblk, sec, par, and link. |
foldtext.line_count |
boolean |
true (default): Show a count of the lines contained in the folded section.false: Don't show a line count. |
foldtext.line_percentage |
boolean |
true (default): Show the percentage of document (buffer) lines contained in the folded section.false: Don't show the percentage. |
foldtext.word_count |
boolean |
true: Show a count of the paragraph words in the folded section, ignoring words inside of other objects.false (default): Don't show a word count. |
foldtext.title_transformer |
fun(): fun(string): string |
A function that returns another function. The inner function accepts a string (the section heading text) and returns a potentially modified string. |
foldtext.fill_chars.left_edge |
string |
The character(s) to use at the very left edge of the foldtext. Default: '⢾⣿⣿'. |
foldtext.fill_chars.right_edge |
string |
The character(s) to use at the very right edge of the foldtext. Default: '⣿⣿⡷' |
foldtext.fill_chars.item_separator |
string |
The character(s) used to separate the items within a section. Default: ' · ' |
foldtext.fill_chars.section_separator |
string |
The character(s) used to separate adjacent sections. Default: ' ⣹⣿⣏ ' |
foldtext.fill_chars.left_inside |
string |
The character(s) used at the internal left edge of fill characters. Default: ' ⣹' |
foldtext.fill_chars.right_inside |
string |
The character(s) used at the internal right edge of fill characters. Default: '⣏ ' |
foldtext.fill_chars.middle |
string |
The character used to fill empty space in the foldtext line. Default: '⣿' |
Sample foldtext recipes
-- SAMPLE FOLDTEXT CONFIGURATION RECIPE WITH COMMENTS
require('mkdnflow').setup({
foldtext = {
title_transformer = function()
local function my_title_transformer(text)
local updated_title = text:gsub('%b{}', '')
updated_title = updated_title:gsub('^%s*', '')
updated_title = updated_title:gsub('%s*$', '')
updated_title = updated_title:gsub('^######', '░░░░░▓')
updated_title = updated_title:gsub('^#####', '░░░░▓▓')
updated_title = updated_title:gsub('^####', '░░░▓▓▓')
updated_title = updated_title:gsub('^###', '░░▓▓▓▓')
updated_title = updated_title:gsub('^##', '░▓▓▓▓▓')
updated_title = updated_title:gsub('^#', '▓▓▓▓▓▓')
return updated_title
end
return my_title_transformer
end,
object_count_icon_set = 'nerdfont',
object_count_opts = function()
local opts = {
link = false,
blockquote = {
icon = ' ',
count_method = {
pattern = { '^>.+$' },
tally = 'blocks',
}
},
fncblk = { icon = ' ' }
}
return opts
end,
line_count = false,
word_count = true,
fill_chars = {
left_edge = '╾─🖿 ─',
right_edge = '──╼',
item_separator = ' · ',
section_separator = ' // ',
left_inside = ' ┝',
right_inside = '┥ ',
middle = '─',
},
},
})The above recipe will produce foldtext like the following
(for an h3-level section heading called My section):
require('mkdnflow').setup({
tables = {
type = 'pipe',
trim_whitespace = true,
format_on_move = true,
auto_extend_rows = false,
auto_extend_cols = false,
style = {
cell_padding = 1,
separator_padding = 1,
outer_pipes = true,
apply_alignment = true,
},
},
})| Option | Type | Description |
|---|---|---|
tables.type |
string |
'pipe' (default): New tables are created in pipe format (| cell | cell | with | --- | --- | separator).'grid': New tables are created in pandoc grid format with +---+ border lines between rows and +===+ header separators. Grid tables support native multiline cells.Regardless of this setting, existing tables are auto-detected and handled in their native format when formatting, navigating, or editing. |
tables.trim_whitespace |
boolean |
true (default): Trim extra whitespace from the end of a table cell when a table is formatted.false: Leave whitespace at the end of a table cell when formatting. |
tables.format_on_move |
boolean |
true (default): Format the table each time the cursor is moved to the next/previous cell/row using the plugin's API.false: Don't format the table when the cursor is moved. |
tables.auto_extend_rows |
boolean |
true: Add another row when attempting to jump to the next row and the row doesn't exist.false (default): Leave the table when attempting to jump to the next row and the row doesn't exist. |
tables.auto_extend_cols |
boolean |
true: Add another column when attempting to jump to the next column and the column doesn't exist.false (default): Go to the first cell of the next row when attempting to jump to the next column and the column doesn't exist. |
tables.style.cell_padding |
integer |
1 (default): Use one space as padding at the beginning and end of each cell.<n>: Use <n> spaces as cell padding. |
tables.style.separator_padding |
integer |
1 (default): Use one space as padding in the separator row.<n>: Use <n> spaces as padding in the separator row. |
tables.style.outer_pipes |
boolean |
true (default): Include outer pipes when formatting a table.false: Do not use outer pipes when formatting a table. |
tables.style.apply_alignment |
boolean |
true (default): Apply the cell alignment indicated in the separator row when formatting the table.false: Always visually left-align cell contents when formatting a table.Previously named tables.style.mimic_alignment. |
require('mkdnflow').setup({
yaml = {
bib = { override = false },
},
})| Option | Type | Description |
|---|---|---|
yaml.bib.override |
boolean |
true: A bib path specified in a markdown file's yaml header should be the only source considered for bib references in that file.false (default): All known bib paths will be considered, whether specified in the yaml header or in your configuration settings. |
require('mkdnflow').setup({
mappings = {
MkdnEnter = { { 'n', 'v' }, '<CR>' },
MkdnGoBack = { 'n', '<BS>' },
MkdnGoForward = { 'n', '<Del>' },
MkdnMoveSource = { 'n', '<F2>' },
MkdnNextLink = { 'n', '<Tab>' },
MkdnPrevLink = { 'n', '<S-Tab>' },
MkdnFollowLink = false,
MkdnDestroyLink = { 'n', '<M-CR>' },
MkdnTagSpan = { 'v', '<M-CR>' },
MkdnYankAnchorLink = { 'n', 'yaa' },
MkdnYankFileAnchorLink = { 'n', 'yfa' },
MkdnNextHeading = { 'n', ']]' },
MkdnPrevHeading = { 'n', '[[' },
MkdnIncreaseHeading = { { 'n', 'v' }, '+' },
MkdnDecreaseHeading = { { 'n', 'v' }, '-' },
MkdnIncreaseHeadingOp = { { 'n', 'v' }, 'g+' },
MkdnDecreaseHeadingOp = { { 'n', 'v' }, 'g-' },
MkdnToggleToDo = { { 'n', 'v' }, '<C-Space>' },
MkdnNewListItem = false,
MkdnNewListItemBelowInsert = { 'n', 'o' },
MkdnNewListItemAboveInsert = { 'n', 'O' },
MkdnExtendList = false,
MkdnUpdateNumbering = { 'n', '<leader>nn' },
MkdnTableNextCell = { 'i', '<Tab>' },
MkdnTablePrevCell = { 'i', '<S-Tab>' },
MkdnTableNextRow = false,
MkdnTablePrevRow = { 'i', '<M-CR>' },
MkdnTableNewRowBelow = { 'n', '<leader>ir' },
MkdnTableNewRowAbove = { 'n', '<leader>iR' },
MkdnTableNewColAfter = { 'n', '<leader>ic' },
MkdnTableNewColBefore = { 'n', '<leader>iC' },
MkdnTableDeleteRow = { 'n', '<leader>dr' },
MkdnTableDeleteCol = { 'n', '<leader>dc' },
MkdnTableAlignLeft = { 'n', '<leader>al' },
MkdnTableAlignRight = { 'n', '<leader>ar' },
MkdnTableAlignCenter = { 'n', '<leader>ac' },
MkdnTableAlignDefault = { 'n', '<leader>ax' },
MkdnFoldSection = { 'n', '<leader>f' },
MkdnUnfoldSection = { 'n', '<leader>F' },
MkdnTab = false,
MkdnSTab = false,
MkdnIndentListItem = { 'i', '<C-t>' },
MkdnDedentListItem = { 'i', '<C-d>' },
MkdnCreateLink = false,
MkdnCreateLinkFromClipboard = { { 'n', 'v' }, '<leader>p' },
},
})See descriptions of commands and mappings below.
Note: <command> should be the name of a command defined in
mkdnflow.nvim/plugin/mkdnflow.lua (see :h Mkdnflow-commands for a list).
| Option | Type | Description |
|---|---|---|
mappings.<command> |
[string|string[], string] |
The first item is a string or an array of strings representing the mode(s) that the mapping should apply in ('n', 'v', etc.). The second item is a string representing the mapping (in the expected format for vim). |
To enable completion via cmp using the provided source, add mkdnflow as a
source in your cmp setup function. You may also want to modify the formatting
to see which completions are coming from Mkdnflow:
cmp.setup({
-- Add 'mkdnflow' as a completion source
sources = cmp.config.sources({
{ name = 'mkdnflow' },
}),
-- Completion source attribution
formatting = {
format = function(entry, vim_item)
vim_item.menu = ({
-- Other attributions
mkdnflow = '[Mkdnflow]',
})[entry.source_name]
return vim_item
end
}
})Warning
There may be some compatibility issues with the completion module and
links.transform_on_create/links.transform_on_follow functions.
If you have some transform_on_create option for links to organizing in folders
then the folder name will be inserted accordingly. Some transformations may not
work as expected in completions.
To prevent this, make sure you write sensible transformation functions, preferably using it for folder organization.
Below are descriptions of the user commands defined by Mkdnflow. For the
default mappings to these commands, see the mappings = ... section of
Configuration options.
| Command | Default mapping | Description |
|---|---|---|
MkdnEnter |
-- | Triggers a wrapper function which will (a) infer your editor mode, and then if in normal or visual mode, either follow a link, create a new link from the text under the cursor or visual selection, or fold a section (if cursor is on a section heading); if in insert mode, it will create a new list item (if cursor is in a list), go to the next row in a table (if cursor is in a table), or behave normally (if cursor is not in a list or a table). In visual mode, if the selection overlaps a citation (@citekey or [@citekey]), a markdown link is created from the citekey instead of following the citation.Note: There is no insert-mode mapping for this command by default since some may find its effects intrusive. To enable the insert-mode functionality, add to the mappings table: MkdnEnter = {{'i', 'n', 'v'}, '<CR>'}. |
MkdnNextLink |
{ 'n', '<Tab>' } |
Move cursor to the beginning of the next link (if there is a next link). |
MkdnPrevLink |
{ 'n', '<S-Tab>' } |
Move the cursor to the beginning of the previous link (if there is one). |
MkdnNextHeading |
{ 'n', ']]' } |
Move the cursor to the beginning of the next heading (if there is one). |
MkdnPrevHeading |
{ 'n', '[[' } |
Move the cursor to the beginning of the previous heading (if there is one). |
MkdnGoBack |
{ 'n', '<BS>' } |
Open the historically last-active buffer in the current window. Note: The back-end function for :MkdnGoBack (require('mkdnflow').buffers.goBack()) returns a boolean indicating the success of goBack(). This may be useful if you wish to remap <BS> such that when goBack() is unsuccessful, another function is performed. |
MkdnGoForward |
{ 'n', '<Del>' } |
Open the buffer that was historically navigated away from in the current window. |
MkdnCreateLink |
-- | Create a link from the text under the cursor (in normal mode) or from the visual selection (in visual mode). Accepts optional arguments to override the link style and/or transform scope, in any order: :MkdnCreateLink wiki, :MkdnCreateLink filename, or :MkdnCreateLink wiki filename. Abbreviations are accepted (e.g. :MkdnCreateLink w f). |
MkdnCreateLinkFromClipboard |
{ { 'n', 'v' }, '<leader>p' } |
Create a link, using the content from the system clipboard (e.g. a URL) as the source and the text under the cursor or visual selection as the link text. Accepts optional arguments to override the link style and/or transform scope, in any order: :MkdnCreateLinkFromClipboard wiki filename. Abbreviations are accepted (e.g. :MkdnCreateLinkFromClipboard w f). |
MkdnCreateFootnote |
-- | Create a footnote reference ([^N]) at the cursor position and a corresponding definition ([^N]: ) at the end of the document. The reference is placed after the current word and any trailing punctuation (e.g., word.[^1] rather than word[^1].). The cursor jumps to the definition line in insert mode so the footnote text can be filled in immediately. After filling in the definition, use MkdnFollowLink (<CR>) on the definition to jump back to the reference (or use ``/'' via the jumplist).Auto-numbering increments from the highest existing numeric footnote label. An optional argument specifies an explicit string label instead (e.g., :MkdnCreateFootnote myref creates [^myref]).If no footnote definitions exist in the buffer and footnotes.heading is configured, the heading is appended to the end of the document before the definition. If definitions already exist, the new definition is placed after the last one. |
MkdnRenumberFootnotes |
-- | Renumber all footnote references and definitions in the current buffer so they form a sequential series (1, 2, 3, ...) based on order of first appearance in the document. Both references ([^label]) and definitions ([^label]: ...) are updated. String-labeled footnotes (e.g., [^myref]) are converted to numeric labels. Multiple references to the same footnote are all updated consistently.Definitions are consolidated under the configured footnotes.heading (default: ## Footnotes) in appearance order. Multi-line definitions (with indented continuation lines) are moved as a block. If the heading doesn't exist, it is appended to the end of the document.Aborts with a warning if duplicate definitions are found (same label defined more than once). If footnotes are already up to date, a message is shown and no changes are made. |
MkdnRefreshFootnotes |
-- | Refresh footnote numbering and consolidate definitions. Like MkdnRenumberFootnotes, but only renumbers footnotes that already have numeric labels — string-labeled footnotes (e.g., [^myref]) are preserved as-is.Definitions are reordered by first appearance in the document and consolidated under the configured footnotes.heading. This is useful for documents that mix numbered and named footnotes, or for reordering a disorganized definition list.Aborts with a warning if duplicate definitions are found. If footnotes are already up to date, a message is shown and no changes are made. |
MkdnFollowLink |
-- | Open the link under the cursor, creating missing directories if desired, or if there is no link under the cursor, make a link from the text under the cursor. Image links () are opened in the system's default viewer.For footnotes, this command jumps bidirectionally: pressing <CR> on a footnote reference ([^1]) jumps to its definition ([^1]: ...), and pressing <CR> on a definition jumps back to the reference. |
MkdnDestroyLink |
{ 'n', '<M-CR>' } |
Destroy the link under the cursor, replacing it with just the text from the link name. |
MkdnTagSpan |
{ 'v', '<M-CR>' } |
Tag a visually-selected span of text with an ID, allowing it to be linked to with an anchor link. |
MkdnMoveSource |
{ 'n', '<F2>' } |
Open a dialog where you can provide a new source for a link and the plugin will rename and move the associated file on the backend (and rename the link source). |
MkdnYankAnchorLink |
{ 'n', 'yaa' } |
Yank a formatted anchor link (if cursor is currently on a line with a heading). |
MkdnYankFileAnchorLink |
{ 'n', 'yfa' } |
Yank a formatted anchor link with the file path included before the anchor (if cursor is currently on a line with a heading). The file path is relative to the notebook's path resolution base (root directory, initial directory, or current file directory, depending on path_resolution config). |
MkdnIncreaseHeading |
{ { 'n', 'v' }, '+' } |
Increase heading importance (remove hashes). Supports visual selection to change multiple headings at once. Visual mode supports dot-repeat (like Vim's < and >). |
MkdnDecreaseHeading |
{ { 'n', 'v' }, '-' } |
Decrease heading importance (add hashes). Supports visual selection to change multiple headings at once. Visual mode supports dot-repeat (like Vim's < and >). |
MkdnIncreaseHeadingOp |
{ { 'n', 'v' }, 'g+' } |
Operator version of MkdnIncreaseHeading. In normal mode, use with a motion (e.g., g+} to increase headings to next paragraph). In visual mode, operates on selection. Supports dot-repeat. |
MkdnDecreaseHeadingOp |
{ { 'n', 'v' }, 'g-' } |
Operator version of MkdnDecreaseHeading. In normal mode, use with a motion (e.g., g-} to decrease headings to next paragraph). In visual mode, operates on selection. Supports dot-repeat. |
MkdnToggleToDo |
{ { 'n', 'v' }, '<C-Space>' } |
Toggle to-do list item's completion status, convert a list item into a to-do list item, or convert a plain text line into a to-do list item. Block-level markdown structures (headings, blockquotes, tables, code fences, thematic breaks, HTML blocks) and lines inside fenced code blocks are not converted. |
MkdnSortToDoList |
-- | Sort the to-do list at the cursor position by status. Items are grouped by their status's sort.section value and positioned according to sort.position. |
MkdnUpdateNumbering |
{ 'n', '<leader>nn' } |
Update numbering for all siblings of the list item of the current line. |
MkdnChangeListType {type} (marker) |
-- | Change the type of a list. The type argument must be one of ul (unordered), ol (ordered), ultd (unordered to-do), or oltd (ordered to-do). An optional marker argument (-, *, or +) specifies which bullet character to use when converting to an unordered type. Defaults to -. Ignored for ordered types. When used with a marker on a list that is already the target type, the bullet character is swapped (e.g., :MkdnChangeListType ul * changes - bullets to *).Without a visual selection, changes all siblings at the cursor's indentation level. With a visual selection, changes all list items in the selected range. When converting to a to-do type, items receive a not_started checkbox. When converting from a to-do type to a plain type, checkboxes are removed. When converting between to-do types, the existing checkbox status is preserved. |
MkdnNewListItem |
-- | Add a new ordered list item, unordered list item, or (uncompleted) to-do list item. When adding a to-do item and to_do.status_propagation.up is enabled, ancestor to-do statuses are updated accordingly (e.g. a completed parent reverts to in-progress). |
MkdnNewListItemBelowInsert |
{ 'n', 'o' } |
Add a new list item below the current line and begin insert mode. Add a new line and enter insert mode when the cursor is not in a list. |
MkdnNewListItemAboveInsert |
{ 'n', 'O' } |
Add a new list item above the current line and begin insert mode. Add a new line and enter insert mode when the cursor is not in a list. |
MkdnExtendList |
-- | Like above, but the cursor stays on the current line (new list items of the same type are added below). |
MkdnTable ncol nrow (noh) |
-- | Make a table of ncol columns and nrow rows. Pass noh as a third argument to exclude table headers. |
MkdnTableFormat |
-- | Format a table under the cursor. |
MkdnTableNextCell |
{ 'i', '<Tab>' } |
Move the cursor to the beginning of the next cell in the table, jumping to the next row if needed. |
MkdnTablePrevCell |
{ 'i', '<S-Tab>' } |
Move the cursor to the beginning of the previous cell in the table, jumping to the previous row if needed. |
MkdnTableCellNewLine |
{ 'i', '<S-CR>' } |
Insert a new line within the current table cell. In grid tables, this adds a new content line within the current row. In pipe tables, this inserts a <br> tag at the cursor position. |
MkdnTableNextRow |
-- | Move the cursor to the beginning of the same cell in the next row of the table. |
MkdnTablePrevRow |
{ 'i', '<M-CR>' } |
Move the cursor to the beginning of the same cell in the previous row of the table. |
MkdnTableNewRowBelow |
{ 'n', '<leader>ir' } |
Add a new row below the row the cursor is currently in. |
MkdnTableNewRowAbove |
{ 'n', '<leader>iR' } |
Add a new row above the row the cursor is currently in. |
MkdnTableNewColAfter |
{ 'n', '<leader>ic' } |
Add a new column following the column the cursor is currently in. |
MkdnTableNewColBefore |
{ 'n', '<leader>iC' } |
Add a new column before the column the cursor is currently in. |
MkdnTableDeleteRow |
{ 'n', '<leader>dr' } |
Delete the row the cursor is currently in. Does nothing if cursor is on the separator row. |
MkdnTableDeleteCol |
{ 'n', '<leader>dc' } |
Delete the column the cursor is currently in. Does nothing if the table has only one column. |
MkdnTableAlignLeft |
{ 'n', '<leader>al' } |
Set the alignment of the current table column to left. Updates the separator row and reformats the table. |
MkdnTableAlignRight |
{ 'n', '<leader>ar' } |
Set the alignment of the current table column to right. Updates the separator row and reformats the table. |
MkdnTableAlignCenter |
{ 'n', '<leader>ac' } |
Set the alignment of the current table column to center. Updates the separator row and reformats the table. |
MkdnTableAlignDefault |
{ 'n', '<leader>ax' } |
Remove alignment from the current table column, returning it to the default. Updates the separator row and reformats the table. |
MkdnTablePaste (delimiter) (noh) |
-- | Paste delimited data from the system clipboard as a formatted markdown table. The delimiter is auto-detected by default (supports tab, comma, semicolon, and pipe), but can be specified explicitly as the first argument. Pass noh to suppress the header separator row. The table is inserted below the current cursor line. |
MkdnTableFromSelection (delimiter) (noh) |
-- | Convert visually-selected delimited lines into a formatted markdown table, replacing the selection. The delimiter is auto-detected by default, but can be specified explicitly. Pass noh to suppress the header separator row. Supports CSV, TSV, and other delimited formats including quoted fields. |
MkdnIndentListItem |
{ 'i', '<C-t>' } |
Indent the current list item and update numbering for ordered lists. Falls back to the default <C-t> behavior when the cursor is not on a list item. |
MkdnDedentListItem |
{ 'i', '<C-d>' } |
Dedent the current list item and update numbering for ordered lists. Falls back to the default <C-d> behavior when the cursor is not on a list item. |
MkdnTab |
-- | Wrapper function which will jump to the next cell in a table (if cursor is in a table) or indent an (empty) list item (if cursor is in a list item). |
MkdnSTab |
-- | Wrapper function which will jump to the previous cell in a table (if cursor is in a table) or de-indent an (empty) list item (if cursor is in a list item). |
MkdnFoldSection |
{ 'n', '<leader>f' } |
Fold the section the cursor is currently on/in. |
MkdnUnfoldSection |
{ 'n', '<leader>F' } |
Unfold the folded section the cursor is currently on. |
MkdnCleanConfig |
-- | Open a scratch buffer showing a minimal, optimized version of your Mkdnflow config. Deprecated key names are updated to their modern equivalents, and values matching defaults are removed. Function values cannot be serialized and are shown with a placeholder comment. See also :checkhealth mkdnflow for a diagnostic report on your configuration. |
Mkdnflow |
-- | Subcommand dispatcher for Mkdnflow. Provides a single entry point to all Mkdnflow functionality with tab completion at every level. Use :Mkdnflow with no arguments to see available command groups. Use:Mkdnflow <group> to see actions within a group. Use:Mkdnflow <group> <action> [args] to execute a command.Available groups: link, nav, heading, todo, list, table,fold, yank, start, config, enter, tab, shift-tab.Examples: - :Mkdnflow link follow — follow link under cursor- :Mkdnflow table new 3 4 — create a 3-column, 4-row table- :'<,'>Mkdnflow todo toggle — toggle to-do status for visual selection- :Mkdnflow link create wiki — create a wiki-style link- :Mkdnflow start — force-start Mkdnflow on non-configured filetypes- :Mkdnflow start silent — force-start silentlyNote: The previous behavior of :Mkdnflow (force-start) has moved to:Mkdnflow start. The old usage still works but shows a deprecationwarning. |
Tip
If you are attempting to (re)map <CR> in insert mode but can't get it to
work, try inspecting your current insert mode mappings and seeing if anything
is overriding your mapping. Possible candidates are completion plugins and
auto-pair plugins.
If using nvim-cmp, consider using the mapping with a fallback.
If using an autopair plugin that automatically maps <CR> (e.g. nvim-autopairs),
see if it provides a way to disable its <CR> mapping.
There are several ways to customize mkdnflow's keybindings. All
mkdnflow commands (e.g., MkdnFollowLink, MkdnToggleToDo) are
standard Neovim user commands and can be mapped using any method
you'd normally use to map a Neovim command.
To disable a single default mapping, set it to false in the
mappings table:
require('mkdnflow').setup({
mappings = {
MkdnNextLink = false, -- Frees <Tab>
MkdnPrevLink = false, -- Frees <S-Tab>
MkdnNewListItemBelowInsert = false, -- Frees 'o'
MkdnNewListItemAboveInsert = false, -- Frees 'O'
},
})To disable all default mappings at once, disable the maps
module:
require('mkdnflow').setup({
modules = { maps = false },
})The simplest way to change a binding is to set a different key
in the mappings table. Each entry takes a mode (or array of
modes) and a key string:
require('mkdnflow').setup({
mappings = {
MkdnFollowLink = { 'n', 'gf' }, -- Single mode
MkdnToggleToDo = { { 'n', 'v' }, 'tt' }, -- Multiple modes
MkdnEnter = false, -- Disable default
},
})Note
The mappings table maps each command to a single key. If you
need the same command on multiple keys (e.g., in different
modes), use on_attach, lazy.nvim keys, or a manual autocmd
instead.
The on_attach callback fires each time mkdnflow activates on
a matching buffer. It receives the buffer number as its
argument, making it ideal for buffer-local mappings, options,
or autocommands.
When modules.maps is enabled (the default), default mappings
are set up before on_attach runs, so you can selectively
override or supplement them:
require('mkdnflow').setup({
on_attach = function(bufnr)
local opts = { buffer = bufnr }
-- Bind a command to an additional key
vim.keymap.set('n', 'gf', '<Cmd>MkdnFollowLink<CR>', opts)
-- Bind the same command in multiple modes
vim.keymap.set({ 'n', 'v' }, 'tt', '<Cmd>MkdnToggleToDo<CR>', opts)
-- Add a mapping not in the defaults
vim.keymap.set('n', '<leader>ml', '<Cmd>MkdnCreateLink<CR>', opts)
-- Delete a default mapping you don't want
pcall(vim.keymap.del, 'n', '+', { buffer = bufnr })
-- Set buffer-local options
vim.bo[bufnr].textwidth = 80
end,
})To use on_attach as the sole source of mappings (fully
manual control), disable the maps module:
require('mkdnflow').setup({
modules = { maps = false },
on_attach = function(bufnr)
local opts = { buffer = bufnr }
vim.keymap.set('n', '<CR>', '<Cmd>MkdnEnter<CR>', opts)
vim.keymap.set('n', '<BS>', '<Cmd>MkdnGoBack<CR>', opts)
vim.keymap.set('n', '<Tab>', '<Cmd>MkdnNextLink<CR>', opts)
vim.keymap.set({ 'n', 'v' }, '<C-Space>', '<Cmd>MkdnToggleToDo<CR>', opts)
end,
})You can also use on_attach to create links in both markdown
and wiki styles from different keys. The MkdnCreateLink and
MkdnCreateLinkFromClipboard commands accept an optional
style argument (abbreviations like w and m are accepted):
require('mkdnflow').setup({
on_attach = function(bufnr)
local opts = { buffer = bufnr }
-- Markdown link from clipboard (uses configured default)
vim.keymap.set({ 'n', 'v' }, '<leader>p',
'<Cmd>MkdnCreateLinkFromClipboard<CR>', opts)
-- Wiki link from clipboard (per-call style override)
vim.keymap.set({ 'n', 'v' }, '<leader>wp',
'<Cmd>MkdnCreateLinkFromClipboard wiki<CR>', opts)
end,
})If you use lazy.nvim, you can define mappings in the plugin
spec's keys table. Use the ft field to scope them to
markdown buffers:
{
'jakewvincent/mkdnflow.nvim',
ft = { 'markdown', 'rmd' },
opts = {
mappings = {
MkdnFollowLink = false, -- Disable default
MkdnEnter = false,
},
},
keys = {
{ 'gf', '<Cmd>MkdnFollowLink<CR>', ft = 'markdown', desc = 'Follow link' },
{ '<CR>', '<Cmd>MkdnEnter<CR>', ft = 'markdown', desc = 'Mkdn enter' },
},
}Note
Lazy.nvim's ft-scoped keys use a filetype autocmd
internally, so they are effectively buffer-local. Plain keys
entries without ft are global and will apply in non-markdown
buffers too.
You can also set mappings via your own FileType autocmd.
This is equivalent to on_attach but managed outside of
mkdnflow's config:
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'markdown', 'rmd' },
callback = function(args)
vim.keymap.set('n', 'gf', '<Cmd>MkdnFollowLink<CR>', {
buffer = args.buf,
desc = 'Follow link',
})
end,
})Warning
With a manual autocmd, firing order depends on registration
order. Your autocmd may fire before or after mkdnflow's,
depending on when each is registered. Use on_attach for
guaranteed ordering (it always runs after default mappings).
Mkdnflow provides a range of Lua functions that can be called directly to manipulate markdown files, navigate through buffers, manage links, and more. Below are the primary functions available:
- Initialization (Initialization)
- Link management (Link management)
- Link & path handling (Link and path handling)
- Templates (Templates)
- Buffer navigation (Buffer navigation)
- Cursor movement (Cursor movement)
- Cursor-aware manipulations (Cursor-aware manipulations)
- List management (List management)
- To-do list management (To-do list management)
- Table management (Table management)
- Folds (Folds)
- Yaml blocks (Yaml blocks)
- Bibliography (Bibliography)
- Statusline components (Statusline components)
require('mkdnflow').setup(config)
Initializes the plugin with the provided configuration. See Advanced configuration and sample recipes. If called with an empty table, the default configuration is used.
- Parameters:
config: (table) Configuration table containing various settings such as filetypes, modules, mappings, and more.
require('mkdnflow').forceStart(opts)
Activates the plugin if it has not already been activated. This is called automatically when a buffer with a matching filetype is opened, but can be triggered manually via the :Mkdnflow command.
- Parameters:
opts: (table) Table of options.opts[1]: (string) Pass'silent'to suppress the startup message.
require('mkdnflow').links.createLink(args)
Creates a markdown link from the text under the cursor or visual selection.
- Parameters:
args: (table) Arguments to customize link creation.from_clipboard: (boolean) If true, use the system clipboard content as the link source.style: (string|nil) Link style override:'markdown'or'wiki'. Defaults tolinks.stylefrom config.transform_scope: (string|nil) Transform scope override:'path'or'filename'. Defaults tolinks.transform_scopefrom config.
require('mkdnflow').links.createFootnote(args)
Creates a footnote reference at the cursor position and a definition at the end of the document. Jumps to the definition line in insert mode.
- Parameters:
args: (table) Arguments to customize footnote creation.label: (string|nil) If provided, uses this string as the footnote label (e.g.,'myref'creates[^myref]). If nil, auto-increments from the highest existing numeric footnote.
require('mkdnflow').links.renumberFootnotes()
Renumbers all footnote references and definitions (including string-labeled) to form a sequential integer series based on order of first appearance. Consolidates definitions under the configured heading. Warns and aborts if duplicate definitions are found.
require('mkdnflow').links.refreshFootnotes()
Refreshes footnote numbering (numeric labels only) and consolidates definitions under the configured heading in appearance order. String-labeled footnotes are preserved. Warns and aborts if duplicate definitions are found.
require('mkdnflow').links.followLink(args)
Follows the link under the cursor, opening the corresponding file, URL, or directory. Image links are opened in the system's default image viewer.
- Parameters:
args: (table) Arguments for following the link.path: (string|nil) The path/source to follow. Ifnil, a path from a link under the cursor will be used.anchor: (string|nil) An anchor, either one in the current buffer (in which casepathwill benil), or one in the file referred to inpath.range: (boolean|nil) Whether a link should be created from a visual selection range. This is only relevant ifcreate_on_follow_failureistrue, there is no link under the cursor, and there is currently a visual selection that needs to be made into a link.
require('mkdnflow').links.destroyLink()
Destroys the link under the cursor, replacing it with plain text.
require('mkdnflow').links.tagSpan()
Tags a visual selection as a span, useful for adding attributes to specific text segments.
require('mkdnflow').links.getLinkUnderCursor(col)
Returns the link under the cursor at the specified column.
- Parameters:
col: (number|nil) The column position to check for a link. The current cursor position is used if this is not specified.
require('mkdnflow').links.getLinkPart(link_table, part)
Retrieves a specific part of a link, such as the source or the text.
- Parameters:
link_table: (table) The table containing link details, as provided byrequire('mkdnflow').links.getLinkUnderCursor().part: (string|nil) The part of the link to retrieve (one of'source','name', or'anchor'). Default:'source'.
require('mkdnflow').links.getBracketedSpanPart(part)
Retrieves a specific part of a bracketed span.
- Parameters:
part: (string|nil) The part of the span to retrieve (one of'text'or'attr'). Default:'attr'.
require('mkdnflow').links.hasUrl(string, to_return, col)
Checks if a given string contains a URL and optionally returns the URL.
- Parameters:
string: (string) The string to check for a URL.to_return: (string) The part to return (e.g., "url").col: (number) The column position to check.
require('mkdnflow').links.transformPath(text, scope)
Transforms the given text according to the default or user-supplied explicit transformation function.
- Parameters:
text: (string) The text to transform.scope: (string|nil) Transform scope:'path'(transform entire text) or'filename'(transform only the filename portion after the last/). Defaults tolinks.transform_scopefrom config.
require('mkdnflow').links.formatLink(text, source, part, style, transform_scope)
Creates a formatted link with whatever is provided.
- Parameters:
text: (string) The link text.source: (string) The link source.part: (integer|nil) The specific part of the link to return.nil: () Return the entire link.1: () Return the text part of the link.2: () Return the source part of the link.
style: (string|nil) Link style override:'markdown'or'wiki'. Defaults tolinks.stylefrom config.transform_scope: (string|nil) Transform scope override:'path'or'filename'. Defaults tolinks.transform_scopefrom config.
require('mkdnflow').paths.moveSource()
Moves the source file of a link to a new location, updating the link accordingly.
require('mkdnflow').paths.handlePath(path, anchor)
Handles all 'following' behavior for a given path, potentially opening it or performing other actions based on the type.
- Parameters:
path: (string) The path to handle.anchor: (string|nil) Optional anchor within the path.
require('mkdnflow').paths.formatTemplate(timing, template)
Deprecated: Use require('mkdnflow').templates.formatTemplate() instead.
This function is a backward-compatible shim that delegates to the templates
module. It will be removed in a future major version.
- Parameters:
timing: (string) "before" or "after" specifying when to perform the formatting.template: (string|nil) The template to format. If not provided, the default new file template is used.
require('mkdnflow').paths.updateDirs()
Updates the working directory after switching notebooks or notebook folders (if nvim_wd_heel is true).
require('mkdnflow').paths.pathType(path, anchor, link_type)
Determines the type of the given path. Returns 'external' for image links, file:-prefixed paths, and paths with non-notebook file extensions (e.g. .pdf, .docx); 'url' for web URLs; 'citation' for @-prefixed paths; 'anchor' for same-page anchors; 'nb_page' for notebook pages (extensionless paths or paths with a notebook extension like .md); or nil if no path is provided.
- Parameters:
path: (string) The path to check.anchor: (string|nil) Optional anchor within the path.link_type: (string|nil) The link type from the parser (e.g.'image_link').
require('mkdnflow').paths.transformPath(path)
Transforms the given path based on the plugin's configuration and transformations.
- Parameters:
path: (string) The path to transform.
require('mkdnflow').templates.formatTemplate(timing, template, opts)
Formats the new file template by resolving all placeholders in a single
pass. Function placeholders receive a ctx table with resolved built-in
values: link_title, os_date, source_file, filename, and
heading_context.
- Parameters:
timing: (string|nil) Kept for API compatibility; no longer affects behavior. Previously distinguished "before" and "after" buffer creation.template: (string|nil) The template to format. If not provided, the default new file template is used.opts: (table|nil) Optional parameters.target_path: (string|nil) The path of the new file being created. Used to derive thefilenamefield in thectxtable. If not provided, the current buffer name is used as fallback.
require('mkdnflow').templates.apply(template)
Injects a formatted template string into the current buffer (replacing all content). This is typically called after a new file buffer has been opened.
- Parameters:
template: (string) The template string produced byformatTemplate().
require('mkdnflow').buffers.goBack()
Navigates to the previously opened buffer.
require('mkdnflow').buffers.goForward()
Navigates to the next buffer in the history.
require('mkdnflow').cursor.goTo(pattern, reverse)
Moves the cursor to the next or previous occurrence of the specified pattern.
- Parameters:
pattern: (string|table) The Lua regex pattern(s) to search for.reverse: (boolean) If true, search backward.
require('mkdnflow').cursor.goTo("%[.*%](.*)", false) -- Go to next markdown linkrequire('mkdnflow').cursor.toNextLink()
Moves the cursor to the next link in the file.
require('mkdnflow').cursor.toPrevLink()
Moves the cursor to the previous link in the file.
require('mkdnflow').cursor.toHeading(anchor_text, reverse)
Moves the cursor to the specified heading.
- Parameters:
anchor_text: (string|nil) The text of the heading to move to, transformed in the way that is expected for an anchor link to a heading. Ifnil, the function will go to the next closest heading.reverse: (boolean) If true, search backward.
require('mkdnflow').cursor.toId(id, starting_row)
Moves the cursor to the specified ID in the file.
- Parameters:
id: (string) The Pandoc-style ID attribute (in a tagged span) to move to.starting_row: (number|nil) The row to start the search from. If not provided, the cursor row will be used.
require('mkdnflow').cursor.changeHeadingLevel(change)
Increases or decreases the importance of the heading under the cursor by adjusting the number of hash symbols.
- Parameters:
change: (string) "increase" to decrease hash symbols (increasing importance), "decrease" to add hash symbols, decreasing importance.
require('mkdnflow').cursor.yankAsAnchorLink(full_path)
Yanks the current line as an anchor link, optionally including the file path (relative to the path resolution base) depending on the value of the argument.
- Parameters:
full_path: (boolean) If true, includes the file path relative to the configured path resolution base.
require('mkdnflow').lists.newListItem({ carry, above, cursor_moves, mode_after, alt })
Inserts a new list item with various customization options such as whether to carry content from the current line, position the new item above or below, and the editor mode after insertion.
- Parameters:
carry: (boolean) Whether to carry content following the cursor on the current line into the new line/list item.above: (boolean) Whether to insert the new item above the current line.cursor_moves: (boolean) Whether the cursor should move to the new line.mode_after: (string) The mode to enter after insertion ("i" for insert, "n" for normal).alt: (string) Which key(s) to feed if this is called while the cursor is not on a line with a list item. Must be a valid string for the first argument ofvim.api.nvim_feedkeys.
require('mkdnflow').lists.hasListType(line)
Checks if the given line is part of a list.
- Parameters:
line: (string) The (content of the) line to check. If not provided, the current cursor line will be used.
require('mkdnflow').lists.toggleToDo(opts)
Toggles (rotates) the status of a to-do list item based on the provided options.
- Parameters:
opts: (table) Options for toggling.
require('mkdnflow').lists.updateNumbering(opts, offset)
Updates the numbering of the list items in the current list.
- Parameters:
opts: (table) Options for updating numbering.opts[1]: (integer) The number to start the current ordered list with.
offset: (number) The offset to start numbering from. Defaults to0if not provided.
Warning
require('mkdnflow').lists.toggleToDo(opts) is deprecated. For convenience, it is
now a wrapper function that calls its replacement, require('mkdnflow').to_do.toggle_to_do(opts).
See require('mkdnflow').to_do.toggle_to_do() for details.
require('mkdnflow').to_do.toggle_to_do()
Toggle (rotate) to-do statuses for a to-do item under the cursor.
require('mkdnflow').to_do.get_to_do_item(line_nr)
Retrieves a to-do item from the specified line number.
- Parameters:
line_nr: (number) The line number to retrieve the to-do item from. If not provided, defaults to the cursor line number.
require('mkdnflow').to_do.get_to_do_list(line_nr)
Retrieves the entire to-do list of which the specified line number is an item/member.
- Parameters:
line_nr: (number) The line number to retrieve the to-do list from. If not provided, defaults to the cursor line number.
require('mkdnflow').to_do.hl.init()
Initializes highlighting for to-do items. If highlighting is enabled in your configuration, you should never need to use this.
require('mkdnflow').tables.formatTable()
Formats the current table, ensuring proper alignment and spacing.
require('mkdnflow').tables.addRow(offset)
Adds a new row to the table at the specified offset.
- Parameters:
offset: (number) The position (relative to the current cursor row) in which to insert the new row. Defaults to0, in which case a new row is added beneath the current cursor row. An offset of-1will result in a row being inserted above the current cursor row; an offset of1will result in a row being inserted after the row following the current cursor row; etc.
require('mkdnflow').tables.addCol(offset)
Adds a new column to the table at the specified offset.
- Parameters:
offset: (number) The position (relative to the table column the cursor is currently in) to insert the new column. Defaults to0, in which case a new column is added after the current cursor table column. An offset of-1will result in a column being inserted before the current cursor table column; an offset of1will result in a column being inserted after the column following the current cursor table column; etc.
require('mkdnflow').tables.newTable(opts)
Creates a new table with the specified options.
- Parameters:
opts: (table) Options for the new table (number of columns and rows).opts[1]: (integer) The number of columns the table should haveopts[2]: (integer) The number of rows the table should have (excluding the header row)opts[3]: (string) Whether to include a header for the table or not ('noh'or'noheader': Don't include a header row;nil: Include a header)
require('mkdnflow').tables.alignCol(alignment)
Sets the alignment of the table column under the cursor and reformats the table. Works with both pipe tables and Pandoc grid tables.
- Parameters:
alignment: (string) The alignment to set for the column. One of'left','right','center', or'default'.
require('mkdnflow').tables.pasteTable(opts)
Pastes delimited data from the system clipboard as a formatted markdown table, inserted below the current cursor line. Auto-detects the delimiter unless one is specified.
- Parameters:
opts: (table) Options for pasting.delimiter: (string|nil) The delimiter character to use. Ifnil, the delimiter is auto-detected from the clipboard content. Supported delimiters: tab, comma, semicolon, pipe.header: (boolean) Whether to treat the first row as a header and insert a separator row after it. Default:true.
require('mkdnflow').tables.tableFromSelection(line1, line2, opts)
Converts visually-selected delimited lines into a formatted markdown table, replacing the selected lines. Auto-detects the delimiter unless one is specified. Supports CSV, TSV, and other delimited formats including RFC 4180-style quoted fields.
- Parameters:
line1: (integer) The start line of the selection (1-indexed).line2: (integer) The end line of the selection (1-indexed).opts: (table) Options for conversion.delimiter: (string|nil) The delimiter character to use. Ifnil, the delimiter is auto-detected. Supported delimiters: tab, comma, semicolon, pipe.header: (boolean) Whether to treat the first row as a header and insert a separator row after it. Default:true.
require('mkdnflow').tables.isPartOfTable(text, linenr)
Guesses as to whether the specified text is part of a table.
- Parameters:
text: (string) The content to check for table membership.linenr: (number) The line number corresponding to the text passed in.
require('mkdnflow').tables.moveToCell(row_offset, cell_offset)
Moves the cursor to the specified cell in the table.
- Parameters:
row_offset: (number) The difference between the current row and the target row.0, for instance, will target the current row.cell_offset: (number) The difference between the current table column and the target table column.0, for instance, will target the current column.
require('mkdnflow').folds.getHeadingLevel(line)
Gets the heading level of the specified line.
- Parameters:
line: (string) The line content to get the heading level for. Required.
require('mkdnflow').folds.foldSection()
Folds the current section based on markdown headings.
require('mkdnflow').folds.unfoldSection()
Unfolds the current section.
require('mkdnflow').yaml.hasYaml()
Checks if the current buffer contains a YAML header block.
require('mkdnflow').yaml.ingestYamlBlock(start, finish)
Parses and ingests a YAML block from the specified range.
- Parameters:
start: (number) The starting line number.finish: (number) The ending line number.
require('mkdnflow').bib.handleCitation(citation)
Handles a citation, potentially linking to a bibliography entry or external source.
- Parameters:
citation: (string) The citation key to handle. Required.
The following functions are designed for use in statusline, winbar, or tabline components. They return information about the plugin's current state and are safe to call frequently (e.g. on every statusline redraw).
require('mkdnflow').getNotebook()
Returns information about the current notebook (root directory), or nil
if no root is active (e.g. when path_resolution.primary is not 'root',
or no root marker was found). Designed for use in statusline, winbar, or
tabline components.
Example: lualine component
require('lualine').setup({
sections = {
lualine_x = {
{
function()
local nb = require('mkdnflow').getNotebook()
return nb and nb.name or ''
end,
cond = function()
return require('mkdnflow').getNotebook() ~= nil
end,
},
},
},
})Example: custom statusline
vim.o.statusline = '%f %m%=%{%v:lua.require("mkdnflow").getNotebook() '
.. '~= nil and " " .. require("mkdnflow").getNotebook().name or ""%}'See CONTRIBUTING.md
Mkdnflow uses Semantic Versioning. Version numbers follow the format MAJOR.MINOR.PATCH:
- MAJOR: Incompatible API or configuration changes
- MINOR: New functionality in a backward-compatible manner
- PATCH: Backward-compatible bug fixes
For a detailed history of changes, see CHANGELOG.md.
- Obsidian.md
- clipboard-image.nvim
- mdeval.nvim
- In-editor rendering
- Preview plugins