21 Aug 2015

CommonMark for CHICKEN

I've recently been 'incubating' lots of CHICKEN eggs and it's about time they hatched. I'll try to publish one each week until the backlog is cleared. We're going to start easy and work towards the interesting. This week, CommonMark.

If you've ever worked with Markdown parsers, you'll know they often have different interpretations of the format. This can be a problem if you want to render both on the server, and on the client. For improved compatibility, I prefer CommonMark; a highly specified variant of Markdown, which includes most of the niceties found in modern Markdown parsers.

Implementation

I originally planned to write this in pure Scheme using comparse - a library of parser combinators similar to Haskell's Parsec - having previously enjoyed writing a TOML parser with it. Unfortunately, CommonMark is a more complicated format than TOML, and would take a while to implement. Since CHICKEN already has good Markdown parsers, I considered updating one to suit my needs - in the end, it was much quicker and easier to write a binding for the cmark C library, so that's what I did.

Installation

The cmark egg is available via the CHICKEN egg index:

chicken-install cmark

You must also install cmark, since the egg uses the libcmark.so shared library - If your package manager doesn't provide a cmark package, you can install from source using the usual make && make install dance.

Usage

(use cmark)

(commonmark->html "# Hello world!")

;; for embedded HTML support, turn off safe mode:
(commonmark->html "<script>alert('hello');</script>" safe: #f)

Speaking of use, it currently powers this blog! (EDIT: posts on this blog has since been changed to the org-mode format <2016-10-30 Sun>).

Improvements

This is a very simple Scheme binding which provides CommonMark string to HTML string conversion. It would be nice to support SXML output too, so we could use the SXML tooling to query, transform and render the result. The cmark C library provides iterators for it's parsed node tree, which might help with this - pull requests welcome!