A simple and useful set of toggle commands for Markdown. Similar to Obsidian
Handles quotes, headings, lists (unordered and ordered), and checkboxes
Cycle through different levels of headings, types of lists, and states of checkboxes
Automatically continue quotes, lists, and checkboxes when starting a new line
Use Vim's dot (.
) command to repeat toggle actions (only in Normal mode)
Change plugin settings on-the-fly
quote()
){
"roodolv/markdown-toggle.nvim",
config = function()
require("markdown-toggle").setup()
end,
},
use {
"roodolv/markdown-toggle.nvim",
config = function()
require("markdown-toggle").setup()
end,
}
Plug "roodolv/markdown-toggle.nvim"
For specific installation instructions, please refer to the documentation of your preferred plugin manager.
Include this single line in your init.lua
or config:
require("markdown-toggle").setup()
The default settings are as follows:
require("markdown-toggle").setup({
-- If true, the auto-setup for the default keymaps is enabled
use_default_keymaps = false,
-- The keymaps are valid only for these filetypes
filetypes = { "markdown", "markdown.mdx" },
-- Cycle the marks in user-defined table when toggling lists
enable_list_cycle = false,
-- The list marks table used in cycle-mode (list_table[1] is used as the default list-mark)
list_table = { "-", "+", "*", "=" },
-- Cycle the marks in user-defined table when toggling checkboxes
enable_box_cycle = false,
-- The checkbox marks table used in cycle-mode (box_table[1] is used as the default checked-state)
box_table = { "x", "~", "!", ">" },
-- Mimic the behavior of Obsidian's "Toggle bullet list" on `list()`
mimic_obsidian_list = true,
-- Mimic the behavior of Obsidian's "Cycle bullet/checkbox" on `checkbox()`
mimic_obsidian_cycle = true,
-- The heading marks table used in `markdown-toggle.heading`
heading_table = { "#", "##", "###", "####", "#####" },
-- Skip blank lines and headings in Visual mode (except for quotes)
enable_blankhead_skip = true,
-- Insert an indented quote for new lines within quoted text
enable_inner_indent = false,
-- Toggle only unmarked lines first
enable_unmarked_only = true,
-- Automatically continue lists on new lines
enable_autolist = true,
-- Maintain checkbox state when continuing lists
enable_auto_samestate = false,
-- Dot-repeat for toggle functions in Normal mode
enable_dot_repeat = true,
})
For a quick start with default keymaps, add this to your setup:
require("markdown-toggle").setup({
use_default_keymaps = true,
})
First, set up the common autocmd structure:
vim.api.nvim_create_autocmd("FileType", {
desc = "markdown-toggle.nvim keymaps",
pattern = { "markdown", "markdown.mdx" },
callback = function(args)
local opts = { silent = true, noremap = true, buffer = args.buf }
local toggle = require("markdown-toggle")
-- Keymap configurations will be added here for each feature
end,
})
If you set enable_dot_repeat = true
(default):
opts.expr = true -- required for dot-repeat in Normal mode
vim.keymap.set("n", "<C-q>", toggle.quote_dot, opts)
vim.keymap.set("n", "<C-l>", toggle.list_dot, opts)
vim.keymap.set("n", "<C-n>", toggle.olist_dot, opts)
vim.keymap.set("n", "<Leader><C-x>", toggle.checkbox_dot, opts)
vim.keymap.set("n", "<C-h>", toggle.heading_dot, opts)
opts.expr = false -- required for Visual mode
vim.keymap.set("x", "<C-q>", toggle.quote, opts)
vim.keymap.set("x", "<C-l>", toggle.list, opts)
vim.keymap.set("x", "<C-n>", toggle.olist, opts)
vim.keymap.set("x", "<Leader><C-x>", toggle.checkbox, opts)
vim.keymap.set("x", "<C-h>", toggle.heading, opts)
If you set enable_dot_repeat = false
:
vim.keymap.set({ "n", "x" }, "<C-q>", toggle.quote, opts)
vim.keymap.set({ "n", "x" }, "<C-l>", toggle.list, opts)
vim.keymap.set({ "n", "x" }, "<C-n>", toggle.olist, opts)
vim.keymap.set({ "n", "x" }, "<Leader><C-x>", toggle.checkbox, opts)
vim.keymap.set({ "n", "x" }, "<C-h>", toggle.heading, opts)
If you set enable_autolist = true
(default):
vim.keymap.set("n", "O", toggle.autolist_up, opts)
vim.keymap.set("n", "o", toggle.autolist_down, opts)
vim.keymap.set("i", "<CR>", toggle.autolist_cr, opts)
You can switch various options in the comfort of your active buffer, without the need to restart or reload Neovim.
vim.keymap.set("n", "<Leader>mU", toggle.switch_unmarked_only, opts)
vim.keymap.set("n", "<Leader>mB", toggle.switch_blankhead_skip, opts)
vim.keymap.set("n", "<Leader>mI", toggle.switch_inner_indent, opts)
vim.keymap.set("n", "<Leader>mS", toggle.switch_auto_samestate, opts)
vim.keymap.set("n", "<Leader>mL", toggle.switch_list_cycle, opts)
vim.keymap.set("n", "<Leader>mX", toggle.switch_box_cycle, opts)
This plugin provides the following set of API functions:
type | function | vim-mode |
---|---|---|
Quotes | quote() |
Normal, Visual |
quote_dot() |
Normal | |
Lists | list() |
Normal, Visual |
list_dot() |
Normal | |
Ordered Lists | olist() |
Normal, Visual |
olist_dot() |
Normal | |
Checkboxes | checkbox() |
Normal, Visual |
checkbox_dot() |
Normal | |
Headings | heading() |
Normal, Visual |
heading_dot() |
Normal | |
Autolist |
autolist_up() autolist_down()
|
Normal |
autolist_cr() |
Insert | |
Config-switch |
switch_unmarked_only() switch_blankhead_skip() switch_inner_indent() switch_auto_samestate() switch_list_cycle() switch_box_cycle() switch_mimic_obsidian_list() switch_mimic_obsidian_cycle()
|
Normal |
If you don't want to mimic Obsidian's behavior, set mimic_obsidian_list
and mimic_obsidian_cycle
to false
in your init.lua
or config.
These options are set to true
by default.
API functions are available, allowing you to set keymaps for switching them.
switch_mimic_obsidian_list()
switch_mimic_obsidian_cycle()
mimic_obsidian_list
mimic_obsidian_list = true
:- [ ] foo
↓ execute `list()`
foo
↓
- foo
↓
foo
↓
mimic_obsidian_list = false
:- [ ] foo
↓ execute `list()`
- foo
↓
foo
↓
- foo
↓
mimic_obsidian_cycle
mimic_obsidian_cycle = true
:foo
↓ execute `checkbox()` with `enable_box_cycle = true`
- foo
↓
- [ ] foo
↓
- [x] foo
↓
- [~] foo
↓
- foo
↓
- [ ] foo
↓
mimic_obsidian_cycle = false
:foo
↓ execute `checkbox()` with `enable_box_cycle = true`
- [ ] foo
↓
- [x] foo
↓
- [~] foo
↓
- [ ] foo
↓
quote()
to be used without whitespace at the beginning of a lineheading()
for lines that start with #
:MarkdownToggleQuote
) to call API functionsv:count
(vim.v.count
) support to handle repeated actions
2<C-h>
should invoke the heading()
function twice