Sashmark / Blog

Markdown inline code syntax highlighting with pandoc

Bobby Huang ·

The section Code attributes and the CommonMark spec lists four grep counts plus a control count, taken from the spec file. For icl.md, quoted HTML from a pandoc run with the markdown reader sits in Add a language class with the markdown reader. With the extension switched off, output for that file appears in Turning off inline_code_attributes. Plain commonmark sits beside commonmark+attributes under Two commonmark runs. Four reader runs on icl-space.md, where one space comes ahead of the braces, get reported under Braces after a space. Six numbered steps using cat, pandoc and grep make up Check a code span with grep.

Key takeaways

  • Spec search counts, plus one control, appear in Code attributes and the CommonMark spec.
  • The class and spans pandoc wrote for icl.md are quoted in Add a language class with the markdown reader.
  • Pandoc's HTML for icl.md, minus the extension, is quoted in Turning off inline_code_attributes.
  • Both commonmark reader settings, with what pandoc printed for each, are set out in Two commonmark runs.
  • A file with one space ahead of the braces is tested in Braces after a space.

You have a short snippet sitting mid-sentence, like total = 0, and you want markdown inline code syntax highlighting for it. In the tests below, pandoc 3.8.3 gave a tagged snippet the sourceCode python class, with op and dv spans inside, under two of four reader settings. A plain pair of backticks got neither under any of them.

One way to tag a code span is a pair of braces holding a class, typed right after the closing backtick. This post feeds that form to pandoc with four reader settings and quotes the classes and spans in each HTML result. The tests ran on macOS with pandoc build 3.8.3. Pandoc's HTML is where the test ends. Fenced blocks and their language tags get their own post that covers fences.

Code attributes and the CommonMark spec

Lines 5435 to 5439 of CommonMark 0.31.2 define a code span: a backtick string opens it, and a backtick string of equal length closes it. Lines 5435 to 5449, which hold that definition and its first rules, contain no brace character.

Searching that text file for four terms, ignoring case and matching fixed strings, gave a count of 0 for each one. The terms were inline_code_attributes, sourceCode, syntax highlight and `{.. The control term, code span, matched 26 lines of the same file.

That leaves pandoc as the source of the class names and spans shown next. Treat them as pandoc's output for this test.

The test files

Running cat icl.md printed one line:

Run `total = 0`{.python} first.

The braces touch the closing backtick, with no space between them, and they hold a single class, .python. The second file, icl-plain.md, drops the braces and keeps the sentence: Run `total = 0` first.. A third file, icl-space.md, adds one space between the closing backtick and the opening brace.

Pandoc lists its extensions per reader. Here pandoc --list-extensions=markdown included +inline_code_attributes. The same listing for commonmark held -attributes.

Braces after a fence, used for line numbers, are tested in the code block line numbers post. This post stays with code spans.

Add a language class with the markdown reader

Convert the first file with the markdown reader:

pandoc -f markdown -t html icl.md

The HTML came back over three lines, and those breaks are kept here as pandoc printed them:

<p>Run <code
class="sourceCode python">total <span class="op">=</span> <span class="dv">0</span></code>
first.</p>

The code element got class="sourceCode python". Pandoc then cut the snippet into parts. The = sign was wrapped in a span carrying the class op, and the digit 0 in a span carrying the class dv. The word total stayed as bare text inside the code element. No brace character and no .python text made it into the output.

The first line break falls inside the opening tag, between <code and class=. The second falls before first., the last word of the sentence. Both are in the output exactly as pandoc wrote it.

For the plain file, pandoc -f markdown -t html icl-plain.md gave <p>Run <code>total = 0</code> first.</p>. That code element has no class, and its text has no spans.

Turning off inline_code_attributes

Next, the same file went through the markdown reader with the extension removed:

pandoc -f markdown-inline_code_attributes -t html icl.md

Pandoc wrote one line:

<p>Run <code>total = 0</code>{.python} first.</p>

This code element has no class, and the snippet inside it has no spans. The backticks still made a code span. The brace part is what changed: {.python} now shows up as loose paragraph text, right after the closing </code> tag.

The plain file under this setting printed <p>Run <code>total = 0</code> first.</p>, the same line the markdown reader gave it.

Two commonmark runs

The commonmark reader came next, with its default extension list:

pandoc -f commonmark -t html icl.md

The result matched the run with inline_code_attributes turned off, byte for byte:

<p>Run <code>total = 0</code>{.python} first.</p>

Again {.python} was left as text following a plain code element. That matches the -attributes entry pandoc listed for the commonmark reader in this test.

With +attributes added, the output changed:

pandoc -f commonmark+attributes -t html icl.md

Under commonmark+attributes, pandoc printed the same three lines as the markdown reader run. The code element carried class="sourceCode python", with the op span around = and the dv span around 0.

The plain file gave <p>Run <code>total = 0</code> first.</p> under both commonmark settings. Under all four reader settings, then, the brace-free code span became a plain code element.

Braces after a space

The third file moves the braces one space away from the code span:

Run `total = 0` {.python} first.

Under markdown, markdown-inline_code_attributes and commonmark, pandoc printed the same line for this file: <p>Run <code>total = 0</code> {.python} first.</p>. Pandoc left the braces as text and kept the space ahead of them.

Under commonmark+attributes, the output was different:

<p>Run <code>total = 0</code><span class="python" data-wrapper="1">
</span> first.</p>

Here the code element has no class. Pandoc wrote a span after it with class="python" and data-wrapper="1", and a line break sits between that span's opening and closing tags. This output has no {.python} text.

In all four runs of icl-space.md, the code element came out with no class at all. The flush form in icl.md was the one that put a class on the code element, under markdown and commonmark+attributes.

Check a code span with grep

Try these steps if a code span with braces produces HTML you didn't expect.

  1. Print the source with cat icl.md. The opening brace should touch the closing backtick.
  2. Call the converter, pandoc -f markdown -t html icl.md, and look for class="sourceCode python" on the code element.
  3. Count the class. pandoc -f markdown -t html icl.md | grep -c 'sourceCode python' printed 1. Swapping in -f commonmark gave 0. Under -f commonmark+attributes the count went back to 1.
  4. Count leftover braces. pandoc -f markdown-inline_code_attributes -t html icl.md | grep -c '{.python}' printed 1, while the same count on the markdown run printed 0.
  5. Compare the plain file. pandoc -f markdown -t html icl-plain.md | grep -c 'sourceCode' printed 0, and so did the other three reader settings on that file.
  6. If a class count is 0 where you wanted 1, look at the source line for a space before the opening brace. The section Braces after a space shows what that space did in this test.

Where Sashmark fits

As planned for v1, Sashmark would let you rewrite a sentence on the page as it would look once rendered. Each save would lean on the plan's clean Round-Trip, so a line nobody touched would keep each of its bytes. There would also be a Changes View: it would point to what moved after your previous look at the file and would ask for no git. It is in development and has not been released. The app itself has no AI features. See the planned features, the help pages and the roadmap for where each part stands.

More at sashmark.com.

Questions

Can inline code in Markdown carry a language name?
The class pandoc put on the code element is quoted under Add a language class with the markdown reader.
Why did the braces stay as text after my code?
The section Turning off inline_code_attributes quotes HTML where the braces follow the code element.
Does the commonmark reader read the braces?
Two runs of icl.md, one per commonmark setting, appear in Two commonmark runs.
What happens if I leave a space before the braces?
Runs of icl-space.md under four reader settings are reported in Braces after a space.

What Sashmark plans for v1: Features · Roadmap

View as Markdown