Menu

Search toolsChangelog

to move to openDescribe the problem, not the tool

guide

Markdown is not one renderer

A Markdown heading is portable structure; its automatic URL fragment is not. Hosts make different choices about punctuation, Unicode, duplicate suffixes and raw HTML. A table of contents becomes more predictable when its target ids are explicit and its assumptions are visible in the document.

Structure travels farther than convention

## Installation is recognisable as a level-two ATX heading across CommonMark renderers. Installation followed by hyphens is a Setext level-two heading. That agreement is about document structure.

The fragment after a URL’s # belongs to HTML navigation. A renderer may lower the heading, remove punctuation and replace spaces with hyphens, but Markdown’s core specification does not require that algorithm. The difficult cases expose the gap:

Visible headingsQuestions a host must answer
Café & crèmePreserve Unicode, decompose accents, or encode the original?
Install! and InstallDo punctuation differences survive slugging?
Three copies of UsageIs the suffix -1, -2, _2, or something else?

Two conforming Markdown tools can answer differently because heading parsing and automatic id generation are separate jobs.

Parse blocks before scanning hashes

A line beginning ## is not necessarily a document heading. Inside a fenced code block it is literal example content. Four-space-indented text is code too. CommonMark’s block phase takes precedence for this reason: decide where code and other blocks are, then interpret heading syntax in the remaining structure.

Before you read on

A README contains `## Delete everything` inside a fenced shell example. Should a table-of-contents scanner link it?

  • Inside the fence, those hashes are literal code content.

  • Right. Block context decides whether heading syntax is active.

  • The code-block distinction is part of parsing, not a host-specific navigation choice.

No. A scanner has to track fenced and indented code before it interprets heading markers. Otherwise documentation examples become false navigation entries.

The Markdown table of contents maker follows that order and publishes its supported subset. It does not call itself a universal renderer for every extension.

An authored <a id="install"></a> supplies the target instead of asking a host to invent one. A generated list can link to exactly #install, and duplicate ids can be resolved before the document leaves the tool.

That improves portability, but it is not magic. Raw HTML is allowed by CommonMark and can still be removed by a site’s sanitiser. The honest workflow is to know the destination policy, generate explicit ids when it permits them and preview one published document before applying the convention everywhere.

Generated text should be inspectable and replaceable

A generator needs ownership boundaries. Start and end comments identify the table it may replace later; marked anchor lines identify the targets it owns. Unmarked HTML remains the author’s. That makes regeneration idempotent without turning “remove the old table” into a broad deletion heuristic.

The text diff maker provides the second half of that discipline. Compare source and output with three context lines to see the table and anchors in place, or zero context to isolate only inserted lines. A plain line tool is useful for sorting content, but it does not preserve a document’s heading hierarchy and should not be used as a Markdown parser.

Common questions

Does CommonMark define GitHub-style heading anchors?

No. CommonMark defines headings and links, while GitHub-style automatic ids are a renderer convention. Another host can produce a different fragment from the same visible heading.

Are explicit HTML anchors valid in Markdown?

CommonMark permits raw HTML blocks and inline HTML, and an HTML `id` can be a fragment target. A publishing service can still sanitise that HTML as a product or security policy.

How can I review what a generator changed?

Compare the original and generated Markdown line by line. A unified diff makes every inserted table line, marker and anchor visible without asking you to reread the unchanged prose.

Tools for this

Sources