Using Markdown in Vim

Vim does a pretty good job of giving you a stylized preview of your Markdown. Especially when you consider the inherent limitations of an editor that must be able to run within the terminal. For example:

an example of markdown preview styling in Gui Vim

Note that italics are handled differently in terminal Vim, because most terminals can’t display italics.

an example of markdown preview styling in terminal Vim

If you prefer a more streamlined look, where your text isn’t cluttered by formatting characters for your bold and italic text you can “conceal them.

Here’s an example of the same text as in the first image, but after running :set conceallevel=2

an example of markdown preview styling in Gui Vim with conceallevel set to 2

You’d think this would cause problems for editing because the formatting characters are literally not there, but don’t worry. Vim has a solution. When you put your cursor in a line with concealed characters the concealed characters are revealed. This also works when the line is part of a visual selection.

an example of concealed characters being revealed via cursor presence

I’ll leave it as an exercise for the reader to figure out what conceallevel=1 does in Markdwon.

In addition to a stylized preview, Vim will also help you make lists. For example: the list below has lines that wrap, but were indented automatically by Vim. As you can see it also works with sub-lists. Without that auto-indentation the lines would be much harder to read.

* foo bar baz bum beedle fonk fink zump
  whiff
* zoodle zeedle miffle mop krinkle
  cromple wheedle wump
  * fundle finkle zumple zimp tomple
    creegle

Unfortunately, it has issues when you have bullet items longer than 2 lines if you don’t have autoindent turned on.

* foo bar baz bum beedle fonk fink zump
  zoodle zeedle miffle mop krinkle
cromple wheedle wump

To correct this you’ll want to make sure that autoindent is turned on. If you want it on by default for all file types (not a bad default) you can add set autoindent to your ~/.vimrc.

Alternately you can set it just for markdown files.

Markdown Flavors and Newlines

Markdown comes in a variety of flavors. The original Markdown (now codified by the CommonMark spec ) was designed with very limited capabilities. Since then a lot of different sites and webapps have said “I wish it could just…” and added a tweak, or twenty, to their “flavor” of Markdown. One of the most common flavors is GitHub Flavored Markdown (GFM). The flavor you’re using is important for two reasons:

  1. If you choose any markdown rendering plugins you need to be aware of what flavor they’re assuming your markdown is.
  2. How your chosen flavor of Markdown handles newlines will affect how you need to configure hard-wraps when editing.

Newline handling is… a pain in the butt for people who really love using Markdown.. It seems completely random which sites (or tools) are going to insert a <br /> for each newline and which ones won’t.

In “pure” Markdown, as defined by its creator and the CommonMark spec single newline characters (hitting return) do not cause a newline to appear in the final HTML output. You end a line with two spaces “ ” to get a <br /> or hit return twice to start a new paragraph (<p>...</p>) in the generated HTML.

Two invisible characters at the end of a line is not intuitive to new users. So, most places you use Markdown (like GitHub README.md files) will insert a <br /> wherever you have a newline. ThisV is problematic if, like me, you have your vim hard-wrap. Every time Vim adds that helpful newline you have an unexpected break in a weird place when it renders at a different width.

The easiest solution to this is to just turn off hard-wrap when working on files for these systems / tools.

:set textwidth=0

One solution is to use a separate extension for the different flavors. Maybe *.md for one and *.mkd for the other. Then use an autocmd in filetype.vim to set the wrap for just one of the extensions

autocmd bufreadpre *.mkd setlocal textwidth=0

You could even teach Vim about a new extension of your own creation that acts like Markdown.

If you are working with something that works like CommonMark and does not insert a <br /> for every newline character then you’ll probably want to display trailing spaces, so that you know when you actually have the two trailing spaces needed to insert a <br />. See Showing Invisible Things In Vim for how to do this.

For more details on soft and hard wrapping see the page on wrapping text.

Troubleshooting

In the course of writing this I encountered a number of problems.

No inline preview

Terminal Vim displayed a background color for italic text and bold text was bolded, but in my Gui Vim they both just looked like all the other text. It turned out the problem was my font.

Once I told it to stop using the offending font the bold text became bolded and the italic text was italic. I installed and tried a number of fonts before I found one that worked and I enjoyed the look of. It was Roboto Mono by Christian Robertson.

If you need to hunt down a new font. I’d recommend checking out ProgrammingFonts.org. Find one you like the look of, install it, and try it out on a test markdown file that has _italic_ and **bold** text. Better yet, install a few you like, and iterate through them until you find one that works.

Hidden Characters

A common thing with Markdown plugins is to muck with the conceallevel (see above). They seem to want to set it to 2 which hides bold and italic formatting characters entirely. Personally, I hate it when my editor is hiding things I typed without asking. If the plugin doesn’t have a configuration for this you may have to add a set conceallevel=0 line to your ~/.vimrc. Preferably after the section where plugins are loaded.

Markdown Plugins

Previewing Plugins

One of the most common requests is for the ability to preview your markdown as you type it. Vim can’t do that internally, but you can wire it up to external tools. Most of them watch for changes to your file, run it through a markdown to html conversion, and open it up in your browser window.

Mac Users

I’m a Mac user so I can leverage the spectacular Marked 2 markdown preview app. With the help of the marked.vim plugin I can type :MarkedOpen and the file I’m currently working on opens up in Marked. Every time I save it, Marked handles re-rendering it (in a variety of flavors). If you’re on the Mac and you write a lot of Markdown I highly recommend buying Marked.

Everyone Else

What follows are links to ones I’ve found. I recommend a pause for thought before installing any of them. You must consider what rendering engine they’re using. A lot of them seem to render GitHub Flavored Markdown which handless newlines differently than CommonMark.

  • vim-instant-markdown requires Nodejs for rendering. Renders GitHub flavored Markdown. - macOS, Linux, Windows
  • vim-markdown-preview can use Markdown or grip to give you Common Mark and GFM - macOS, Linux
  • markdown-preview.vim requires Vim >= 8.1 or Neovim. This supports a number of interesting markdown extensions like mermaid, chart.js. It’s not clear what the core Markdown flavor is. - macOS & Linux?
  • previm requires Python 2.7.5 and supports CommonMark and PHP Markdown
  • livedown.vim requires the Livedown npm module. It’s not clear what Markdown flavor it supports

Advanced Geekery

You don’t actually need a plugin to render Markdown and load it in the browser. This Reddit post shows examples of a Vim function that can use whatever rendering engine you want.

Personally, I’ll just use a plugin.

Feature Enhancements

mkdx

mkdx is a Swiss Army Knife for people who love Markdown. It also supports things from markdown variants like Github Flavored Markdown. For example, it can highlight “checkboxes” and “tables”. Two things which don’t normally exist in markdown.

An example feature that I find useful is the ability to create a link out of any visually selected text. For example if you visually selected “foo” in

The word foo is a metasyntactic variable.

and then typed <Leader>ln mkdx would convert it to

The word [foo]() is a metasyntactic variable.

and move your cursor between the parentheses and switch to insert mode. mkdx is filled with lots of little features like that. It also supports things like highlighting “checkboxes” and tables from GFM.

vim-markdown

vim-markdown adds support for GFM, fenced code block languages for syntax highlighting within them, LaTeX math, YAML Front Matter, TOML Front Matter, JSON Front Matter, Strikethroughs, and more.

vim-renumber

When creating ordered (numbered) lists, it’s just a matter of time before you find yourself needing to reorder them, or inserting a new item in the middle. Editing all those numbers is annoying. That’s where vim-renumber comes in.

It’ll convert

3. baz
1. foo
2. bar

to

1. baz
2. foo
3. bar

Folding

mkdx does handle folding, although it’s not on by default.

If you’re not using mkdx you’ll want vim-markdown-folding.

Vim acts as if text was never folded when you tell a GUI client to print. The suggested workaround is to use the :TOhtml command that generates an HTML version of the current window, save that in a file, open that in a browser, and then print from the browser.

Think the behavior should be different? Add your 👍 to this ticket on GitHub.

Other

markdown-drawer provides you with a hierarchical sidebar with all the headings in your document. More importantly, it allows you to easily jump your cursor to the one you want. Speaking as someone who works on multi-page markdown documents every week, this is a big deal.

Here’s the example gif from the project

markdown-drawer example usage gif

markdown-drawer doesn’t currently (March 2019) update itself when you save, but if you simply invoke it again (no need to close it) it will refresh its data.

Writing Mode

goyo.vim is an interesting plugin. It doesn’t add functionality, but instead helps transform your Vim into a distraction free writing environment.

goyo.vim screenshot

Bonus Points

If you’re using vim-plug as your Plugin Manager, remember to specify that your markdown plogins should only be loaded on markdown files. For example:

Plug 'masukomi/vim-markdown-folding', { 'for': 'markdown' }

Full disclaimer, I’m the maintainer of the vim-markdown-folding plugin.