Skip to content

1.5.0

Choose a tag to compare

@hebertialmeida hebertialmeida released this 11 Nov 01:13
· 9 commits to master since this release
e713386

Adds syntax extensions and makes the parse 2.4–3.6× faster.

Syntax extensions. Markdown that cmark doesn't know, such as callouts, ==highlight==, {…} attributes or wikilinks, can now be recognized inside the one walk that builds the tree. It comes out as typed nodes with exact source positions, so a reader of the tree handles it the way it handles cmark's own nodes. Conform to MarkdownExtension, name the NodeKinds your syntax starts in (its anchors, such as .blockquote or .text), and pass it as Markdown(text:syntaxExtensions:).

ParseContext gives a recognizer:

  • the anchor as a SourceNode, with its kind, literal and neighbours;
  • source ranges and Positions, always from what was written;
  • claim(through:) for syntax that spans siblings;
  • cmark's own reading of a node, for the fallback;
  • wrapHTML(onEnter:onExit:), which makes renderHtml() emit the node as a cmark custom node. The HTML is built only when a page renders.

An ExtensionContent node carries a plain fallback, so a reader that doesn't know it can still read cmark's version of the same source. The README section Extending the syntax walks through a ==highlight== extension, which a test compiles and runs, and the DocC catalog has articles on anchors, ranges, plain and HTML.

With extensions, parse() builds the tree once and returns it on every call, and document is its own parse, which renderHtml() never changes.

Faster parse. Line starts are found with a UTF-8 byte scan instead of a walk by Character, which was about 38 % of a parse. The tree is built straight from cmark's node pointers. Release-build median, from 1.4.1 to 1.5.0:

Chapter 1.4.1 1.5.0
86 kB prose 4.70 ms 1.69 ms
86 kB with 84 callouts 4.05 ms 1.26 ms
52 kB code and tables 2.12 ms 0.59 ms
128 kB generated 14.8 ms 7.8 ms

Doubling the text costs 2.02–2.03×.

No breaking API change. Without syntax extensions, the tree is byte-identical to 1.4.1's. A tree oracle checks this across line endings and a missing final newline. Every renderer now runs synchronously on the actor.

158 tests, 1 skipped, run plain, under ASan and under TSan. CI also builds the docs with warnings as errors. (#12)