A lightweight, easy-to-use Markdown preview and outline and incrementally search plugin for NeoVim, which live updates and feature-rich, to fully unleash your Markdown imagination.
Yes, we preview, outline and incrementally search Markdown in one plugin: "cnshsliu/smp.nvim", by Markdown lover for Markdown lover. If you love this plugin also, pin me a star or buy me a coffee.
1️⃣ Quick Start 2️⃣ Screenshots 3️⃣ All Features
Use your markdown as a slide deck. We support Remark now.
you can use :Smp<cr>
to bring up command palette, then choose "remark slideshow" to preview your markdown as a slide deck.
- press Control-Enter on a wiki under cussor, will open it;
- toggle auto preview on/off, see this command in command palette;
- on MacOS, previewing MD will not lose focus of current Neovim window;
😀 Show Tags, links, backlinks in preview browser tab. Can disable by setting
show_navigation_panel = false,
show_navigation_content = false,
Tags, links, backlinks allow you navigate among MDs conveniently.
😀 Update browser extension: 1. keep only one preview tab for each MD; 22. Active preview tab for current MD; update now, place three files into a folder and follow chrome/edge extension instruction to install it manually to Edge or Chrome browser.
😀 Excited to let you know another new feature: "Edit back in Neovim", the scenario is: 1. edit one markdown FILE_A, 2. preview FILE_A. 3. in previewing browser, navigate to another markdown FILE_B, 4. click on "Edit in Neovim", 5, the FILE_B markdown is opend in Neovim. exremely improve my markdown editing experience, give it a try by yourself
😀 TOC 1. genrated TOC right in MD; 2. include TOC with {toc}
😀 Command Panel with :Smp<cr>
😀 Break long line, break long line into multiple lines
😀 Convert URL into markdown link automatically, scenario: visiting a site, copy & paste it's URL from browser to Neovim, or drag a link to NeoVim, the URL will be converted into a link: [Web Page Title](web page url)
automatically.
😀 Switch browser tab automatically when we edit multiple Markdowns
You may be editing several Markdown files in NeoVim at the same time, when you switch from one file to another, you'd like to let browser to switch previewing tab to your current editing Markdown.
😀 Make a Markdown link on Drag and dropping file from Finder, this one is very useful for me, I can use it to manage files on local disk, or.... drag files from IM group other people sent into Markdown.
🎉🎉🎉 See more exiting features for Markdown lover...
Or, take a look at what commands we have, you will have a quick glance of what this plugin can do:
use {
'cnshsliu/smp.nvim',
run="cd server && npm install", -- yes, we should have node & npm installed.
requires = {
"nvim-telescope/telescope.nvim",
"MunifTanjim/nui.nvim",
},
}
require("smp").setup({
--where are your MDs
home = vim.fn.expand("~/zettelkasten"),
-- for Telekasten user, don't use Telekasten? keep this line, no harm
templates = home .. "/" .. "templates",
-- your custom markdown css, if not defined or not exist,
-- will use the default css
smp_markdown_css = "~/.config/smp/my_markdown.css",
-- your markdown snippets, if not defined or not exist,
-- snippets like {snippet_1} will keep it's as-is form.
smp_snippets_folder = "~/.config/smp/snippets",
-- copy single line filepath into 'home/assets' folder
-- default is true
copy_file_into_assets = true,
})
Untitled.mp4
Besides the basic features of markdown preview, this plugin has the following:
-
- Command Panel with
:Smp<cr>
- Clickable wiki links
- Show images on web and local disk
- Clickable Telekasten note (zk etc.)
- A red block indicator points to current editting line
- Example Setup
- Highlight current line in code blocks
- PlantUML
- Latex
- Mermaid
- References link
- Custom Markdown CSS support
- Markdown Template Snippet
- A simple requirement scenario is to have the same {header} and {footer} for all your Markdown.
- Smooth scrolling to current line, sync between NeoVim and browser
- Drop files from Finder into Neovim, and convert it to link automatically. 🎉
- Switch browser tab automatically when you switch among multiple Markdown files
- Convert URL into markdown link automatically
- TOC
- Break long line into multiple lines
- Insert blank lines between lines
- Command Panel with
-
- Show Book in a standalone buffer
:SmpBook
- Show Book in a standalone buffer
-
- Search by tags incrementally
:SmpSearchTag
- Search by text incrementally
:SmpSearchText
- Saved search
- Search by tags incrementally
-
- Sync Todo with MacOS Reminder Application 🎉 so we can
sync todo lists among iPhone Reminder, Mac Book Reminder and Neovim
- Sync Todo with MacOS Reminder Application 🎉 so we can
-
On the roads:
- Fully customizable
- One key (command) in NeoVim to start print in browser, there, you could
choose to send to a physical printer or print to PDF. - and more... (fully unleash your imagination, you ask, I implement )
Preview your markdown on-the-fly.
Clickable Wiki link or telekasten link in double bracket form: [[WIKI_WORD]] If the target local MD file does not exist, show it in warning color.
Show images both from web URL and local disk. for example:
![img1](https://someserver-URL/image.jpg)
![img1](images/image.jpg)
The first image is loaded from it's web URL, the second is loaded from local disk.
Same as Wiki links actually, a Telekasten Note named "Work" is written as [[Work]]
,
and there is a file named Work.md
accordingly on the disk.
If this file does not exist, it will be shown in warning color, or else, you can
click it to jump to the note directly in the preview.
A red block indicator always locates at the current line you are editting
Untitled.mp4
If you don't like it, just disable it by including
show_indicator = false,
in your setup()
Or, SmpIndicator 0
to disable, SmpIndicator 1
to enable,
and SmpIndicator -1
to use "show_indicator" value defined in setup()
require("smp").setup({
home = require("telekasten").Cfg.home or vim.fn.expand("~/zettelkasten"),
templates = home .. "/" .. "templates",
smp_markdown_css = "~/.config/smp/my_markdown.css",
smp_snippets_folder = "~/.config/smp/snippets",
copy_file_into_assets = true,
show_indicator = true,
auto_preview = true,
show_navigation_panel = true,
show_navigation_content = true,
})
If you move cursor into a line within a code block, that line will also be highlighted.
For example, if you have following Markdown text,
the [Marked]
and [Markdown]
will be displayed as
linkes to https://github.com/markedjs/marked/
and http://daringfireball.net/projects/markdown/
[Marked] lets you convert [Markdown] into HTML. Markdown
is a simple text format whose goal is to be very easy to read and write,
even when not converted to HTML. This demo page will let you type
anything you like and see how it gets converted. Live. No more waiting around.
[Marked]: https://github.com/markedjs/marked/
[Markdown]: http://daringfireball.net/projects/markdown/
You may use your own markdown CSS file by define smp_markdown_css in setup() , for example:
require("smp").setup({
smp_markdown_css = "~/.config/smp/my_markdown.css",
})
If the file does not exist, it will fallback to the default CSS.
You can include a snippet (template) in your Markdown file, each template is a file under your snippets folder.
snippets folder is defined by smp_snippets_folder
, for example:
require("smp").setup({
smp_snippets_folder = "~/.config/smp/snippets",
})
For exmaple, you may define snippets named "myHeader" and "myFooter",
you should accordingly have "myHeader.md" and "myFooter.md" files in
smp_snippets_folder
, and then, you could include them in your
Markdown files with {myHeader}
or {myFooter}
.
{myHeader} will be replaced with the content of "myHeader.md" file,
{myFooter} will be replaced with the content of "myFooter.md" file,
Tempalte can be used in a cascaded way, that means, you can include snippets in another snippets.
And, please make sure:
- Keep one and only {snippet} on single line, keep only one snippet on one line,
- Must avoid having looped includes!!!
- If the "snippet.md" file does not exist, no expansion will happen and the
text will be kept in {snippet} form
In browser previewing, snippets will be automatically displayed as their contents, however, if you want to expand them in place right within your Markdown file, that means, to repalce {snippets} with it's content, you could:
- replace one by one:
While you are on a line of {snippet} call:SmpExpandSnippet
to expand it. - replace all snippets in current buffer
call:SmpExpandAllSnippets
to expand them all.
Simple Markdown Preview does not provide default keymappings for these two functions, please define by yourself as needed.
You may drop a file from MacOS Finder into NeoVim, the full file pathname will be inserted into your Markdown. SMP could convert this file into a Markdown link automatically after dropping.
For example, you select a file named "abcd.jpg" in your home folder in Finder, drop this file into NeoVim, "/Users/your_user_name/abcd.jpg" will be inserted into your Markdown file.
If "/Users/your_user_name/abcd.jpg" does exist (If you drag and drop it from Finder, it does exist, if you type this file path, may not exist, SMP will check the existance anyway), it will be converted into
[abcd](/SMP_MD_HOME/assets/xxxxxxxxxxxx.jpg)
SMP_MD_HOME means the home folder you defined in setup,
The file "/Users/your_user_name/abcd.jpg" will be copied to "SMP_MD_HOME/assets/xxxxxxxxxxxxx.jpg"
This way, we keep all dropped file in 'assets' folder.
If you don't like this function, you could disable it by set the following flag to false explicitly in your setup().
"copy_file_into_assets = false"
Keep a valid URL on a single line, it will be converted into a link automatically. the page title will also be extracted automatically for you.
:SmpBreakLineIfLong
default break line length is 80, you can change it by:
require("smp").setup({
...
break_long_line_at = 80,
...
})
:SmpBreakLineIfLong 1
:SmpBreakLineIfLong 40
Select multiple lines, press <C-CR>
to insert blank lines between lines.
Sometime, we may paste text from elsewhere into neovim, and there is only 'carriage return' but no blank lines between texts, in Markdown preview, all text will be concatenated into one line, no paragraph, this is not what we want.
By inserting blank lines, we see paragraphs in preview.
Switch files in Neovim, browser will switch previewing tab automatically for you.
Just install a simple Edge/Chrome extension. you need to install it manually currently.
Follow Chrome/Edge extension installation instruction and install the extension manually to Edge or Chrome browser.
We support TOC in two ways:
- Generate TOC automatically, and insert it into your Markdown file.
:Smp<CR>
to bring up command panel, select "insert toc here"<C-CR>
on a TOC item will jump to the corresponding header. press't
will jump back to TOC. - Expand
{toc}
at previewing stage Include{toc}
in your Markdown file, and it will be expanded into TOC in previewing window
:Smp<cr>
will bring up all SMP commands, press enter on one of them to invoke corresponding command.
You may map :Smp<cr>
to your favorite key in "init.lua", for example:
vim.keymap.set("n", "<leader>m", "<cmd>Smp<CR>", { silent = true })
Outline markdown structures in a standalone buffer, list out all tags, backlinks, and forward links. todos, and headers
:SmpBook
Press on each item will bring you to there.
While you are on a markdown header entry, use '>>' to demote it, use '<<' to promote it.
press '?' in the book buffer to bring up help
Search by multiple tags delimitered with space or ',', "-tagA" to exlude "tagA", ":short-name" to give it a name to save the query condition for later reuse.
:mysearch -tagA tagB tagC
means you'd like to search all markdown fiels which have #tagB, #tagC, but not tagA. and save it as "mysearch". The order of these element does not matter.
Search by multiple text delimitered with space or ',',
textA textB :mytextsearch -textC
means you'd like to search all markdown fiels which contain textA, textB, but not textC. and save it as "mytextsearch". The order of these element does not matter.
Use search syntax described above to save your query, next time, you could pick a saved search with Telescope picker,
and re-run it by hitting <CR>
.
:SmpSyncTodo
will sync your Markdown todos with MacOS Reminder application, since reminders are kept synchronized between iPhone and MacBook already, so you are now able to access your todos anywhere, anytime with either your iPhone, MacBook.
The synchronization is bidirectional.
-
NeoVim v0.6.0 or higher.
-
Node.js v14.0 or higher.
Packer (packer.nvim)
use {
'cnshsliu/smp.nvim',
run="cd server && npm install"
}
I don't use other package manager than Packer, if you are familiar with them, kindly update this README.
require("smp").setup({
-- home = require("telekasten").Cfg.home or vim.fn.expand("~/zettelkasten"),
home = vim.fn.expand("~/zettelkasten"),
templates = home .. "/" .. "templates",
smp_markdown_css = "~/.config/smp/my_markdown.css",
smp_snippets_folder = "~/.config/smp/snippets",
})
Press
:SmpPreview
to start to preview the current buffer.
:SmpPreview
: start service and preview the current buffer`:SmpStart
: start background service without open browser:SmpStop
: stop background service
Normally, you only use SmpPreview command, if service is not started, it will start service first, then open browser for previewing, otherwise, it will preview directly.
When you close NeoVim window, the background service will be shutdown as well. you don't have to close it manually.
The background service is written with Node.js, that's why Node.js is in the dependency list of this plugin.
require('smp').preview()
: "preview current markdown file"
require('smp').book()
: "open the markdown book in a splitted window on right"
require('smp').synctodo()
: "Sync all todos in Markdown to MacOS Reminder"
require('smp').expand_snippet()
: "Expand current snippet in place"
require('smp').expand_all_snippets()
: "Expand all snippets in place"
require('smp').breakIfLong()
: "Break line length if it's too long for easier editting"
require('smp').insert_blank_line()
: "Insert blank lines between multiple lines of text"
require('smp').bookthis()
: "Show book of this markdown file"
require('smp').search_text()
: "Incremental search all markdown files by content"
require('smp').search_tag()
: "Incremental search all markdown files by tags"
require('smp').insert_toc_here()
: "Insert TOC here"
require('smp').indicator_on()
: "Show current line indicator in previewer"
require('smp').indicator_off()
: "Don't show line indicator in previewer"
require('smp').indicator_as_config()
: "Show line indicator in previewer as configured"
require('smp').wrapwiki_visual()
: "Wrap selected text into a wiki link"
require('smp').wrapwiki_word()
: "Wrap word under cursor into a wiki link"
require('smp').wrapwiki_line()
: "Wrap current line into a wiki link"
require('smp').paste_url()
: "Paste url from clipboard into a link"
require('smp').paste_wiki_word()
: "Paste word from clipboard into a link"
require('smp').open_file_in_this_line()
: "System open the linked file in this line"
require('smp').locate_file_in_this_line()
: "System locate the linked file in this line"
require('smp').gotoHeaderFromTocEntry()
: "Jump to header from TOC entry"
require('smp').start()
: "Start background server"
require('smp').stop()
: "Stop background server"
:Smp
will bring up a command palette with all these commands. You can also map them to your own keys.
Feel free to open issues or submit pull requests to contribute to this project.
Need your help, and welcome your contribution
-
Test on different OSs, environments.
-
Raise issues
-
Submit PRs
-
Give Suggestions
Thanks a lot, together we make SMP nicer.
SMP uses port 3030, a configuration to enable other port you choose has not been implemented at this moment, 3030 may cause confliction with your other program, if this is your case and you find out that port configuration is must-to-have for you, please raise an issue. I will add it ASAP.
For note taking, suggest Telekasten I take notes with Telekasten everyday, and just found I need another Markdown previewer, so I wrote this one, I am with a Macbook Pro, and this plugin is tested on MacOS only, If you find any bugs on other OSs, kindly raise an issue, I will fix it ASAP. thanks a lot.