class

Hwaro::Content::Processors::FenceTracker

Inherits Reference < Object

CommonMark-faithful fence state machine:

  • An opener is a run of 3+ backticks or tildes indented at most 3 spaces. A backtick fence's info string may not contain a backtick (CommonMark treats such a line as inline code, not a fence).
  • The closer must use the same character, be at least as long as the opener, and carry nothing but whitespace after the run. A shorter run, the other character, or trailing text is fence content — this is what keeps examples nested inside ```` fences (and "ruby" lines inside an open fence) verbatim.
  • Lines indented 4+ spaces (or starting with a tab) are indented-code context where ```/~~~ is literal text, never a delimiter. Whole indented-code runs are tracked as verbatim too: a 4+-indented non-blank line opens a run when nothing before it can absorb the indent — after a blank line, or directly after an ATX heading, which CommonMark (and Markd) let indented code follow with no blank line in between. Inside a list item the run opens only four columns beyond the item's content column (tabs expanded to 4-column stops), and it survives blanks until the first non-blank line back under that column.
  • List items are tracked as a stack of content columns, one entry per open item, at ANY indentation: a nested - b sits wherever its parent's content puts it, four spaces or a tab included. The stack errs toward keeping items open — a marker always pushes, an item is only popped by a marker left of its content or by a non-blank line left of its content after a blank line (the one case where Markd certainly closes it). A stale item can only make a line look less like code (today's under-protective behaviour); a missed one would make real list content look like code and silently skip every extension on it. Items are keyed by blockquote depth, so a quote inside an item never pops the item, while a > marker left of an item's content closes it. Column arithmetic mirrors Markd, including its quirks (tabs after a list marker and after > are measured from Markd's own column, not the true one). Lines inside a generic HTML block (<div> … blank line, <!-- … -->) never open indented code, since Markd passes them through as raw HTML; the block ends where Markd's does, including when its list item or quote ends. Walkers built with raw_html_code: false skip this, like raw code blocks. Known limit: a fence closer followed directly by indented code opens no run.
  • Fences inside blockquotes (> ```) are tracked too: the leading >markers are stripped before the opener/closer rules apply, and the marker depth is remembered. Because CommonMark gives fenced code no lazy continuation, a line missing the fence's markers ends the quote — and the fence with it — and is re-evaluated as a potential new opener. Inside an open fence, only the fence's own marker depth is stripped, so a> ```' line stays literal content of a top-level fence. Known limits: fences at 4+ absolute indent inside list items are still invisible, and tab-formed > markers (>\t) are not recognized.

Constants

ATX_HEADING_RE = /\A {0,3}\#{1,6}(?:[ \t]|\r?\n?\z)/

An ATX heading at up to 3 spaces indent: 1-6 # followed by a space/tab or nothing but the line ending. Only used to let an indented-code run open on the line right after a heading — the blank line the run otherwise needs is what CommonMark requires to keep indented code from interrupting a paragraph, and a heading is not a paragraph. Markd opens the code block there, so without this the walkers transformed lines Markd renders verbatim (a shortcode expanded on such a line left an escaped placeholder comment stranded inside <pre><code>). The other paragraph-ending blocks (setext underlines, thematic breaks, HTML blocks) are not recognized here: they are ambiguous line-locally, and missing them only keeps today's under-protective behavior.

HTML_BLOCK_END = {2 => "-->", 3 => "?>", 4 => ">", 5 => "]]>"}

What ends the HTML blocks that run to a marker, not a blank line (CommonMark types 2-5), keyed by @html_block.

HTML_BLOCK_LONE_TAG_RE = /\A {0,3}(?:<[A-Za-z][A-Za-z0-9-]*+(?:\s++[a-zA-Z_:][a-zA-Z0-9:._-]*+(?:\s*+=\s*+(?:[^"'=<>`\x00-\x20]++|'[^']*+'|"[^"]*+"))?+)*+\s*+\/?>|<\/[A-Za-z][A-Za-z0-9-]*+\s*+>)\s*\z/
HTML_BLOCK_TAG_RE = /\A {0,3}<\/?(?:address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|optgroup|option|p|param|section|source|title|summary|table|tbody|td|tfoot|th|thead|tr|track|ul)(?:\s|\/?>|\z)/i

Starts of CommonMark HTML blocks that run to a blank line (Markd's HTML_BLOCK_OPEN types 6 and 7, the latter with possessive quantifiers so a long line cannot exhaust the PCRE JIT stack).

LIST_MARKER_RE = /\A(?:[-*+]|\d{1,9}[.)])(?=[ \t]|\r?\n?\z)/

A bullet or ordered-list marker, matched after the line's leading whitespace (so at any indentation — which list it belongs to is decided by the item stack), followed by a space/tab or nothing (CommonMark's empty item). Over-matching (a * * * thematic break, a 2. that cannot interrupt a paragraph) only pushes a stale item, which errs toward "not code".

RAW_HTML_CODE_CLOSE_RE = /<\/(?:pre|script|style|textarea)\s*>/i
RAW_HTML_CODE_OPEN_RE = /\A {0,3}<(?:pre|script|style|textarea)(?:[\s>]|\z)/i

These CommonMark raw HTML blocks (type 1) leave their contents uninterpreted. Preprocessors must treat them like code so math, footnotes, and inline markup do not rewrite script/style or preformatted text. The tag name must end at whitespace, > or the line end — <style-guide> or <pre-view> is an ordinary element — and the block ends at the first line containing ANY of the closing tags, whichever element opened it.

Constructors

new(raw_html_code : Bool = true, html_blocks : Bool = raw_html_code)

raw_html_code: false turns off raw-HTML code-block tracking and generic HTML-block tracking. Only the Markdown-extension walkers treat <pre>/<script>/ <style>/<textarea> blocks as opaque; shortcode expansion (and the checks that must agree with it) keeps its long-standing behaviour of seeing inside. html_blocks: false keeps the raw code blocks opaque but turns generic HTML-block tracking off (definition-list extraction, which escapes raw-HTML term lines).

Source

Instance methods

fence_line?(line : String) : Bool

Feed the next line (with or without its trailing newline). Returns true when the line must pass through verbatim: a fence delimiter or any line inside an open fence.

Source
html_block_line?

The last line fed was raw HTML to Markd: it opened or continued a generic HTML block (no inline parsing happens there).

Source
list_item_line?

The last line fed opened a list item that Markd starts: a list marker, unless it sits in the open paragraph's container and is an item CommonMark forbids from interrupting a paragraph (an empty one, or an ordered one not starting at 1), which is continuation text.

Source