Asciideck: Asciidoc for Erlang

13 Jun

Asciideck is a new project I have been working on in my spare time that implements an Asciidoc parser and translation of Asciidoc documents into various output formats.

The Asciideck parser returns an AST for the document. That AST can be further manipulated should it be necessary: for example you may need to rewrite some relative links if you are not keeping the same file directory structure as the original Asciidoc documents. You could also enforce a certain document structure and validate it using the AST.

This AST can then be passed on to the translator modules. Asciideck currently comes with two: HTML and man page. The article you are currently reading was generated using the HTML translator module.

Asciideck has been tested against around 600 Asciidoc documents that I wrote. This website is now generated using Asciideck (Hugo will use the asciidoc script to generate HTML). But a lot of elements are not parsed properly, or are ignored by translator modules. It will take many more documents to get close to the original Asciidoc implementation in terms of features.

I wrote this project twice: first as an ugly prototype that generated man pages, and then I rewrote that using a different technique for parsing. I looked at a few different Asciidoc and Markdown implementations and found the Markdown code in Pandoc to be surprisingly readable despite being written in Haskell. I could not fully understand how it worked, but I could follow it based on my knowledge of the syntax.

I decided to write small functions that only contain the "happy path" for each possible blocks in an Asciidoc document. Take this function for example:

comment_line(St) →
    <<"//", Comment0/bits>> = read_line(St),
    Comment = trim(Comment0),
    {comment_line, #{<<"subs">> => <<"verbatim">>}, Comment, ann(St)}.

When the line begins with // this matches: we have a comment line and we return the block we just parsed. When the line doesn't begin with // the function will crash and Asciideck will try the next parse function in the list.

This makes the code easy to read and improve. I am very happy with how it turned out.

If you decide to use this parser and/or find issues with documents you have, please get in touch. I will be happy to fix issues on a short notice until the project gets close to a complete implementation.

You can find the code at the usual locations:

You can also donate to this project via BountySource. Thanks in advance!