Skip to content

Step 1 of 5 · Reading · ~4 min

Read

Block Elements

Setext Headings

Markdown's older heading style underlines the text instead of prefixing it:

Release 2.1
===========

Known issues
------------

Same output as # Release 2.1 and ## Known issues. Only two levels exist: = gives H1, - gives H2, and there is no setext H3. A parser has to support both styles anyway, because a decade of real-world documents contains both. Your program will turn setext headings into <h1> and <h2>, print a bare row of dashes as <hr />, and leave everything else alone.

How long does the underline have to be?

Any length. The spec says "a sequence of = characters or a sequence of - characters" and imposes no minimum, so Release 2.1 followed by a single = is a perfectly valid H1. Length is decoration, not syntax.

What the underline may not contain is internal whitespace: = = is not an underline, and that document is just a paragraph. Up to three spaces of indentation before the underline is fine; four is too many and the line is no longer an underline.

Why is a row of dashes the hardest line in Markdown?

Because --- means three different things depending on what sits above it.

Rendering diagram…

This is the first place in the course where a line cannot be classified on its own. The block scanner needs lookbehind: it has to know what the previous lines turned out to be.

LineText above it?Result
===yessetext H1
===noparagraph text (a lone === is not a break of any kind)
---yessetext H2
---nothematic break
-yessetext H2
-noan empty bullet item

What counts as "text above"?

Only lines that would otherwise be a paragraph. A blockquote line, a list item, an ATX heading or another thematic break above the dashes does not get underlined:

Above the dashesResult
Release 2.1<h2>Release 2.1</h2>
> Release 2.1the quote line, then a separate <hr />
- Release 2.1the list item, then a separate <hr />
# Release 2.1the heading, then a separate <hr />
nothing (start of file or a blank line)<hr />

And the sharpest edge of all: the heading swallows every paragraph line above it, not just one. Foo, then Bar, then --- is a single two-line H2, not a paragraph followed by a heading. If you want them separate, put a blank line between them.

A worked trace

Input lines, one per row. The scanner holds the current run of paragraph lines and looks at the line after the run:

Lines heldNext lineDecision
Title=====underline: write <h1>Title</h1>, skip both
Foo, Bar---underline: write <h2>Foo Bar</h2> (course convention: join lines with a space)
Foo, = =blankno underline, write the two lines unchanged
(nothing)---thematic break, write <hr />

Common mistakes

  • Checking for the thematic break first. para over --- then comes out as para and <hr />, when the spec wants one H2.
  • Underlining a single line only. The whole run of paragraph lines above the underline belongs to the heading.
  • Forgetting to consume the underline. After you emit the heading, advance past both the text and the underline, or the === reappears in the output.
  • Accepting = = or a four-space indent. Neither is an underline.

Your exercise

Convert setext headings, print <hr /> for a bare thematic break, and pass every other line through unchanged. The starter supplies the classification helpers; you write the loop that groups paragraph lines and decides what follows them.

Up nextBold and ItalicInline Elements

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…