Simple and improved Markdown note taking.
Mdnotes aims to be a lightweight plugin that improves the Markdown note-taking experience in Neovim, with minimal configuration required. It also exposes most of the functions used internally, so that the user can create a hyper-extensible note-taking experience similar to Neovim's philosophy.
It provides the typical Markdown features like inserting/editing inline links, ordered/unordered/task lists, generating ToC, table helpers, and formatting. The highlights are that it provides better WikiLink support, managing/inserting/deleting assets, sequential Markdown buffer history, link referencing/renaming, and outliner-style indentation. Please see the Features below for a descriptive list of features and their commands!
In the Recommendations section I've written some notes on my recommended mdnotes setup, and please see the Supported Markdown Format section to see how mdnotes aims to format your notes.
If you are migrating from another note-taking application, then MIGRATING.md might be of interest to you, and I've also written some useful tips in TIPS.md for when writing notes in out-of-the-box Neovim. Lastly, a disclaimer I must unfortunately say, is if you are executing any mass data-altering commands, ensure you have a notes backup!
All documentation is available with :h mdnotes.txt. Execute :checkhealth mdnotes to ensure there are no problems with your plugin config.
All the features of mdnotes and their associated commands are listed and categorised below.
:Mdn inline_link open.:Mdn inline_link toggle which pastes your copied text over the selected text or word under cursor. This command also removes the inline link and saves it to be used later with the same command.:Mdn inline_link rename. :Mdn inline_link relink. :Mdn inline_link normalize to have consistent paths. :Mdn inline_link validate. This ensures that your inline link has a valid destination.Mdn inline_link convert_fragment_to_gfm. Useful when using LSP auto-completion and you want to create valid Markdown links on GitHub.:Mdn wikilink create.:Mdn wikilink follow.:Mdn wikilink rename_references. Also rename references of the current buffer when not hovering over a Wikilink.:Mdn wikilink show_references. Also show references of the current buffer when not hovering over a Wikilink.:Mdn wikilink undo_rename. Only available when prefer_lsp = false.:Mdn wikilink delete. :Mdn wikilink normalize. :Mdn wikilink find_orphans.:Mdn assets unused_delete to easily cleanup assets that you no longer use.:Mdn assets unused_move to move unused assets to a separate folder.:Mdn assets insert_image or :Mdn assets insert_file which creates the appropriate link and copies or moves the image to your assets folder. Requires xclip or wl-clipboard for Linux.:Mdn assets open_containing_folder. :Mdn assets download_website_html.:Mdn assets delete.mdnotes integrates with Neovim to edit tables.ROW by COLS table with :Mdn table create ROW COLS.:Mdn table best_fit and can also add padding around your cells (table_best_fit_padding in config).:Mdn table column_insert_left/right.:Mdn table column_move_left/right.:Mdn table column_delete.:Mdn table column_duplicate.:Mdn table column_alignment_toggle.:Mdn table column_sort_ascending/descending. Can also use the API to create custom sorting.:Mdn table row_insert_above/below.:Mdn index and :Mdn journal.:Mdn history go_back and :Mdn history go_forward.:Mdn heading next/previous to easily navigate headings.:Mdn formatting strong/emphasis/inline_code/strikethrough/autolink_toggle.<CR>, o, and O and can be disabled.auto_list_renumber = true by default, can also be done manually).:Mdn formatting task_list_toggle. Also works with linewise visual mode to toggle multiple tasks at a time.:Mdn formatting unformat_lines.:Mdn toc generate. Can also customise the depth of the ToC by changing the toc_depth = 4 or by specifying the depth in the command e.g. :Mdn toc generate 2.:Mdn outliner_toggle. Make sure to exit afterwards by re-toggling. Can also use outliner-like indentation with :Mdn outliner indent/unindent.:Mdn journal insert_entry. :Mdn miscellaneous open_containing_folder. prefer_lsp = true.:Mdn user namespace for better organisation.:h mdnotes-api.Using the lazy.nvim package manager,
{
"ymich9963/mdnotes.nvim",
}
and specify your config using opts = {} or with a setup({}) function,
{
"ymich9963/mdnotes.nvim",
opts = {
-- Config here
}
-- or
config = {
require("mdnotes").setup({
-- Config here
})
}
}
{
index_file = "",
journal_file = "", -- path or function returning string for dynamic journal file
assets_path = "", -- path or function returning string for dynamic asset path
asset_insert_behaviour = "copy",-- "copy" or "move" files when inserting from clipboard
overwrite_behaviour = "error", -- "overwrite" or "error" when finding assset file conflicts
open_behaviour = "buffer", -- "buffer", "tab", "split", or "vsplit" to open when following links
date_format = "%a %d %b %Y" -- date format based on :h strftime()
prefer_lsp = false, -- to prefer LSP functions than the mdnotes functions
auto_list_continuation = true, -- automatic list continuation
default_keymaps = false,
autocmds = true, -- enable or disable plugin autocmds, check docs for enabling/disabling individual ones
table_best_fit_padding = 0, -- add padding around cell contents when using tables_best_fit
toc_depth = 4 -- depth shown in the ToC
user_commands = {} -- table with user commands in {command_name = function} scheme
}
Sample directory structure for mdnotes is shown below. See RATIONALE.md for reasons regarding the accepted file structure.
notes/
ββββassets/
β ββββfire.png
β ββββwater.pdf
ββββmusic.md
ββββelectronics.md
etc.
This plugin was made with this type of directory structure in mind because this is how I use it. If this directory configuration doesn't suit you please make an issue and hopefully I'll be able to accomodate anyone's needs.
I've specified below some recommended plugins, keymaps, and optional settings for a great experience with mdnotes.
For the best Neovim Markdown note-taking experience, I've listed some other projects to optionally install alongside mdnotes,
markdown, markdown_inline, and latex parsers. The keymappings below can be enabled by setting default_keymaps = true as they are not enabled by default, and they will only be available in Markdown buffers. Place any mdnotes keymaps in a <Neovim config path>/after/ftplugin/markdown.lua file so that they're also Markdown specific. For organisation they use the <leader>m prefix.
vim.keymap.set('n', '<leader>mgx', ':Mdn inline_link open<CR>', { buffer = true, desc = "Open inline link URI under cursor" })
vim.keymap.set('n', '<leader>mgf', ':Mdn wikilink follow<CR>', { buffer = true, desc = "Open markdown file from WikiLink" })
vim.keymap.set('n', '<leader>mgrr', ':Mdn wikilink show_references<CR>', { buffer = true, desc = "Show references of link or buffer" })
vim.keymap.set('n', '<leader>mgrn', ':Mdn wikilink rename_references<CR>', { buffer = true, desc = "Rename references of link or current buffer" })
vim.keymap.set({"v", "n"}, "<leader>mk", ":Mdn inline_link toggle<CR>", { buffer = true, desc = "Toggle inline link" })
vim.keymap.set("n", "<leader>mh", ":Mdn history go_back<CR>", { buffer = true, desc = "Go to back to previously visited Markdown buffer" })
vim.keymap.set("n", "<leader>ml", ":Mdn history go_forward<CR>", { buffer = true, desc = "Go to next visited Markdown buffer" })
vim.keymap.set({"v", "n"}, "<leader>mb", ":Mdn formatting strong_toggle<CR>", { buffer = true, desc = "Toggle strong formatting" })
vim.keymap.set({"v", "n"}, "<leader>mi", ":Mdn formatting emphasis_toggle<CR>", { buffer = true, desc = "Toggle emphasis formatting" })
vim.keymap.set({"v", "n"}, "<leader>mt", ":Mdn formatting task_list_toggle<CR>", { buffer = true, desc = "Toggle task list status" })
vim.keymap.set("n", "<leader>mp", ":Mdn heading previous<CR>", { buffer = true, desc = "Go to previous Markdown heading" })
vim.keymap.set("n", "<leader>mn", ":Mdn heading next<CR>", { buffer = true, desc = "Go to next Markdown heading" })
Place these settings in your <Neovim config path>/after/ftplugin/markdown.lua file so that they are Markdown-specific. First one here is to enable wrapping only for the current Markdown buffer.
vim.wo[vim.api.nvim_get_current_win()][0].wrap = true -- Enable wrap for current .md buffer
Second one is to disable LSP diagnostics in the current Markdown buffer.
vim.diagnostic.enable(false, { bufnr = 0 }) -- Disable diagnostics for current .md buffer
Last one here is for the glorious Neovim Windows users. Setting this keymap will allow you to use the built in <C-x> <C-f> file completion for WikiLinks or just for using file paths in Markdown buffers.
vim.keymap.set("i", "<C-x><C-f>", "<cmd>set isfname-=[,]<CR><C-x><C-f><cmd>set isfname+=[,]<CR>",
{
desc = "Mdnotes i_CTRL-X_CTRL-F smart remap to allow path completion on Windows",
buffer = true
})
mdnotes tries to complement Neovim functionality to make editing tables as easy as possible. See the table below for what functions Neovim does and what functions are done by mdnotes.
| Feature | mdnotes | Neovim |
|---|---|---|
| Insert empty rows | Y (:Mdn table row_insert_above/below) |
N |
| Duplicate row | N | Y (:h yy) |
| Delete row | N | Y (:h dd) |
| Move row | N | Y (:h dd and :h p) |
| Insert empty columns | Y (:Mdn table column_insert_left/right) |
N |
| Duplicate column | Y (:Mdn table column_duplicate) |
Y (:h visual-block) |
| Delete column | Y (:Mdn table column_delete) |
Y (:h visual-block) |
| Move column | Y (:Mdn table column_move_left/right) |
N |
Note: Not all of the features of mdnotes are listed in this table, just the ones that are relevant to this section.
Here is the supported Markdown formatting for mdnotes.nvim. The plugin tries to adhere to the CommonMark and GitHub Flavoured Markdown (GFM) spec as well as providing WikiLink support. If any problems arise please don't hesitate to create an issue for it!
Opened with :Mdn inline_link open. Inserted with the :Mdn assets insert_file/image and :Mdn inline_link toggle commands. If no extension is given to file below, it is treated as .md.
[link](https://neovim.io)
[link](path/to/file#fragment)
[link](path/to/file#GFM Style Fragment Wth Spaces)
[link](path/to/file#gfm-style-fragment-wth-spaces)
[link](<path/to/file with spaces.md#fragment>)
[link](#Original Fragment)
[link](#original-fragment)
[link](path/to/file.extension)

Opened with :Mdn wikilink follow. Can only be filenames, so link can also be link.md.
[[link]]
[[link#fragment]]
[[link#fragment with spaces]]
[[link#fragment-with-spaces]]
Toggled with :Mdn formatting <format>_toggle. Using _ for the strong and emphasis formats needs to be specified in the strong_format and emphasis_format config options. The strong emphasis format can be done by first applying emphasis and then strong.
**strong**
__strong__
*emphasis*
_emphasis_
~~strikethrough~~
`inline code`
<autolink>
All ordered and unordered CommonMark lists along with GFM task lists are supported.
- Item
+ Item
* Item
1) Item
2. Item
- [x] Task lists with all ordered and unordered lists above
The GFM table specification is supported.
|1r1c|1r2c|1r3c|
|----|----|----|
|2r1c|2r2c|2r3c|
|3r1c|3r2c|3r3c|
I wanted to make a more Neovim-centric Markdown notes plugin that tries to work the available Markdown LSPs, is command/subcommand focused, concise, adheres to the CommonMark and GFM specs, while also providing the more widespread WikiLink support other note-taking apps provide. I hope I did in fact accomplish this (and more) for you as well as for me, and if I have not then please create an issue or contribute! Thanks for reading this :).
Using mini.test for testing. For this project, if you want to run the tests then you need to install mini.test as a plugin locally. This was done to minimise dependencies in the repo. If you're not using lazy then you need to specify the mini.test location, using the mini_path variable in scripts/minimal_init.lua. To run the tests execute the following command in the project root,
nvim --headless --noplugin -u ./scripts/minimal_init.lua -c "lua MiniTest.run()"