Markdown anchor link without heading: pandoc span tests
Bobby Huang ·
Sample input and the four reader settings applied to it are shown in Sample input with a blank span. Under Span and link under markdown, HTML and native output for that file are quoted. Text that one run left in place appears in Brackets left as text in commonmark, beside grep counts. A run with one extension added appears under Adding bracketed_spans to commonmark. Bytes from a second extension run sit under Adding attributes to commonmark. An extra file holding words between the brackets is covered in Putting words inside the span. Spec lines for links with a hash destination are listed in Fragment links in the spec. Numbered steps with pandoc and grep fill Add an id to a spot in your file.
Key takeaways
- Both elements pandoc wrote for one sample file are quoted under Span and link under markdown.
- Grep counts for a run where the brackets survived sit in Brackets left as text in commonmark.
- Look in Adding attributes to commonmark for pandoc's output with that extension, quoted byte for byte.
- Output for a span wrapped around a sentence is set out in Putting words inside the span.
- Commands that write the HTML and count ids make up Add an id to a spot in your file.
A markdown anchor link without heading text came down to two pieces in this test. One was an empty span carrying an id, set at the close of a sentence. The other was a link whose destination read #signed.
Each run happened once on one macOS machine, and the pandoc there was 3.8.3. Spec quotes and line numbers cite CommonMark at release 0.31.2. Everything below sticks to the HTML and native output pandoc printed, and it claims nothing past those bytes.
Sample input with a blank span
Running cat anc.md printed:
Jane Doe signed here. []{#signed}
Go back to [the signature](#signed).
Line 1 ends with a pair of square brackets holding nothing, then {#signed} in curly braces. Since no words sit between the brackets, any span built from them would be empty. Line 3 is an inline link. It reads the signature, and its destination is #signed.
Pandoc turned this file into HTML under four -f settings: markdown, commonmark, commonmark+bracketed_spans and commonmark+attributes. A second input, anc-text.md, was added by a script written for this post. It puts a whole sentence inside the brackets.
Ids that pandoc gives to headings are their own topic, and the guide to headings and anchor links handles them.
Span and link under markdown
The command:
pandoc -f markdown -t html anc.md
Output:
<p>Jane Doe signed here. <span id="signed"></span></p>
<p>Go back to <a href="#signed">the signature</a>.</p>
On line 1, the brackets and braces are gone. In their place pandoc wrote an empty span element with an id attribute set to signed. On line 2, the link became an a element carrying href="#signed". Strip the # from that href and what remains equals the span's id, letter for letter.
To see what pandoc built before it wrote any HTML, the extra test ran the same file with -t native. The first paragraph closed with this line:
, Span ( "signed" , [] , [] ) []
So the bracket pair became a Span element, and "signed" is the first value inside its parentheses. Further down, the second paragraph held a Link element ending in ( "#signed" , "" ).
Brackets left as text in commonmark
The command:
pandoc -f commonmark -t html anc.md
Output:
<p>Jane Doe signed here. []{#signed}</p>
<p>Go back to <a href="#signed">the signature</a>.</p>
Here, the empty brackets and {#signed} came through as ordinary characters. No span element was written, and no id attribute either. The link line matches the markdown run byte for byte.
The extra test counted both results. Run against the commonmark output, the id="signed" count came back 0, while the literal []{#signed} count came back 1. Against the markdown output, those two counts flipped, to 1 and 0.
So this run's output held href="#signed" with no element anywhere carrying that id. A fixed-string count of ]{# in the spec text found 0 lines. The phrase block quote, counted as a control, matched 54 lines in that same file.
Adding bracketed_spans to commonmark
bracketed_spans is a pandoc extension. The + in the reader name switches it on for the commonmark reader:
pandoc -f commonmark+bracketed_spans -t html anc.md
Output:
<p>Jane Doe signed here. <span id="signed"></span></p>
<p>Go back to <a href="#signed">the signature</a>.</p>
Those two lines are identical to the markdown output quoted above. This command ran three separate times across the test logs behind this post, and each of those three runs gave the same bytes.
For the empty-span pattern, then, this setting and the markdown reader agreed in this test.
Adding attributes to commonmark
A re-run swapped in the attributes extension:
pandoc -f commonmark+attributes -t html anc.md
Pandoc wrote this, line break included:
<p>Jane Doe signed here. [<span id="signed"
data-wrapper="1">]</span></p>
<p>Go back to <a href="#signed">the signature</a>.</p>
Read the bytes in order. An opening square bracket stays as text, ahead of the span tag. The tag carries two attributes, id="signed" and data-wrapper="1". A closing square bracket then sits inside the span, right before </span>.
Counting id="signed" in this output gave 1. Both square brackets remain in the paragraph here, while the runs quoted under Span and link under markdown and Adding bracketed_spans to commonmark dropped them.
Putting words inside the span
The extra file anc-text.md moves the sentence between the brackets:
[Jane Doe signed here.]{#signed}
Go back to [the signature](#signed).
Under markdown and under commonmark+bracketed_spans, pandoc wrote:
<p><span id="signed">Jane Doe signed here.</span></p>
<p>Go back to <a href="#signed">the signature</a>.</p>
This time the span wraps the words, and the id sits on that same element. Under plain commonmark, line 1 came out as [Jane Doe signed here.]{#signed} inside a p element, brackets and braces intact.
Spans used to color or mark text belong to other walkthroughs: see coloring Markdown text and highlighting Markdown text. Tags you type yourself are handled in the walkthrough on HTML inside Markdown.
Fragment links in the spec
The link half of this pattern is in the spec. Lines 6836-6837 say a link holds link text, a link destination, and a title that may be left out. Line 7060 reads: "A link can contain fragment identifiers and queries". Its first example, on line 7064, is [link](#fragment), and line 7070 gives the HTML as <p><a href="#fragment">link</a></p>.
Running grep -n -F '](#' on the spec matched one line, 7064. The id half, by contrast, came out in these runs under markdown and under commonmark with an extension added, and the plain commonmark run wrote no id at all.
Add an id to a spot in your file
These commands back the steps below, and each one ran in the extra test:
cat anc.md
pandoc -f markdown -t html anc.md -o anc-md.html
pandoc -f commonmark -t html anc.md -o anc-cm.html
pandoc -f commonmark+bracketed_spans -t html anc.md -o anc-bs.html
grep -c 'id="signed"' anc-bs.html
grep -c 'href="#signed"' anc-bs.html
grep -c -F '[]{#signed}' anc-cm.html
To give a spot in your text an id and link to it, work through these six steps.
- Choose the id. This test used
signed. - Type the span where the spot belongs, either as
[]{#signed}or as[Jane Doe signed here.]{#signed}. Undermarkdownandcommonmark+bracketed_spans, pandoc 3.8.3 wrote a span carrying the id for both inputs. Plaincommonmark, the comparison run, kept both as text and wrote no id. - Write the link with a hash before the same id, as in
[the signature](#signed). - Convert the file with
-f markdownor-f commonmark+bracketed_spans, the two settings that wrote the span with no leftover brackets in this test. The extra test wroteanc-md.htmlandanc-bs.htmlfrom those two, plusanc-cm.htmlfrom plaincommonmarkfor comparison. - Count ids and hrefs in the output. For
anc-bs.html, bothgrep -clines printed1. - Check for leftover brackets. On
anc-cm.html, the-Fcount printed1, matching the plaincommonmarkrun quoted under Brackets left as text in commonmark.
Where Sashmark fits
Suppose Sashmark's v1 ends up matching the plan: fixing a sentence could happen right inside the rendered page mid-read. Lines nobody edited would then reach disk holding identical bytes, which is what a clean Round-Trip on the plan sets out to do. A Changes View, slated for that version, would also flag any edit made since your previous read-through, with git left aside.
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
- Is a markdown anchor link without heading text possible?
- Steps that set an id and link to it are numbered in Add an id to a spot in your file.
- Why did my empty brackets show up as text?
- A run where they came through as characters is quoted in Brackets left as text in commonmark.
- Which pandoc setting wrote the span?
- Look under Adding bracketed_spans to commonmark for one setting quoted with its output.
- Can the span hold words?
- HTML written for a sentence placed inside the brackets is covered in Putting words inside the span.