If you write HTML by hand, you already know the pain of typing <ul><li> over and over. Here’s a trick that lets you write plain Markdown inline and convert it on the spot using pandoc as a Vim filter.

The Basic Idea
Vim’s ! command pipes a range of lines through an external program and replaces them with the output. Pandoc reads Markdown on stdin and writes HTML to stdout — a perfect match.
Three Useful Incantations
Original file:
Here is a thing.
- one
- two
Something else.
Convert just a few lines (current line plus the next):
:.,.+1!pandoc
Useful when you only want to convert a list or a short block without touching the surrounding content.
Output:
Here is a thing.
<ul>
<li>one</li>
<li>two</li>
</ul>
Something else.
Convert from the cursor to end of file:
:.,$!pandoc
Wraps everything in proper block-level tags (<p>, <ul>, etc.) but leaves out the <html> boilerplate — great for partials or template fragments.
Output:
<p>Here is a thing.</p>
<ul>
<li>one</li>
<li>two</li>
</ul>
<p>Something else.</p>
Generate a complete standalone HTML document:
:.,$!pandoc -s
The -s flag produces a full page with <!DOCTYPE html>, <head>, default pandoc CSS, and <body>. Handy when you want a self-contained file you can open straight in a browser.
Output:
some.html<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>-</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
html {
color:
#1a1a1a;
background-color:
#fdfdfd;
}
body {
margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media (max-width: 600px) {
body {
font-size: 0.9em;
padding: 12px;
}
h1 {
font-size: 1.8em;
}
}
@media print {
html {
background-color: white;
}
body {
background-color: transparent;
color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color:
#1a1a1a;
}
a:visited {
color:
#1a1a1a;
}
img {
max-width: 100%;
}
svg {
height: auto;
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid
#e6e6e6;
color:
#606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
border: none;
border-top: 1px solid
#1a1a1a;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid
#1a1a1a;
border-bottom: 1px solid
#1a1a1a;
}
th {
border-top: 1px solid
#1a1a1a;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
</head>
<body>
<p>Here is a thing.</p>
<ul>
<li>one</li>
<li>two</li>
</ul>
<p>Something else.</p>
</body>
</html>
Why This Works So Well
The filter approach means you never leave your editor. Write a quick Markdown list, visually select it, run the filter, and the raw HTML is sitting right there — no browser tab, no separate tool, no copy-paste.
Pandoc supports a huge range of input and output formats, so the same trick works for converting to Markdown, reStructuredText, or even LaTeX if the mood strikes.