Release: comrak (CommonMark/GFM compatible parser in Rust)

(Semi-crosspost from The Rust Programming Language Forum)

Hi all! I’m kivikakk, one of the engineers who worked on GitHub’s transition to CommonMark. I’ve also done a lot of work on our fork, cmark-gfm, of the reference CommonMark implementation cmark.

The work I did there made me interested in pushing CommonMark adoption in general — pulldown-cmark is great (and fast!), but is currently lagging behind the spec. I did a more or less straight port of cmark-gfm from C to Rust, resulting in comrak. It’s available on now.

The relative advantages of comrak are that it’s based on a 1:1 translation of the reference cmark implementation, meaning upstream spec changes can be translated and adapted with relative ease — the parsing strategy is identical, so the risk of a spec change being difficult to adapt is extremely low. Further, it’s based on the exact code we run in production at GitHub, including the extensions to CommonMark (table/strikethrough/autolink/etc.), so it’s guaranteed to e.g. render your the same way we do.

The relative _dis_advantage is that it’s a little slower than the competition. Raph reported pulldown-cmark ran faster than cmark in this discussion — comrak runs at about 1.9x the runtime of cmark. This still places it immediately behind cmark itself in the cmark benchmarks.

I’m also pleased to report that it’s now being used for rendering Markdown in as of onur/! :tada:

Thanks for reading!


1 Like

That’s neat. As I recall, part of the speed of
pulldown-cmark came from its lack of allocations;
where cmark creates an AST with strings copied from
the source document, pulldown-cmark just returns
offsets into the source document.

So one thought I’ve had for a better implementation
of cmark would be to have the AST include offsets
into the source document where it currently has
raw strings.

This would require quite a few changes, but it’s
possible rust’s type system would make this easier.

I’ll have to see how possible it’d be for me to do something similar in comrak!