Full text-based document generation using asciidoc and ditaa

I'm not a big fan of wordprocessors like OpenOffice.org or MS Office for writing technical documentation. I always end up focussing on how things are outlined and styled instead of the contents. Especially with technical documentation, content and structure are more important (in my opinion). Also, I like typing text in Vim :)

That's why, when I recently had to write documentation for a project, I went searching for a structured text based solution . After asking around a bit, asciidoc seemed to be a good option. There are many structured text solutions for the web, but only a few that will work standlone from the commandline (and support conversion to multiple target formats).

Coincidentally, I ran into "ditaa" which converts ascii linedrawings to png diagrams. Combining these two would mean I could do everything from within a single document that, by itself, remains perfectly readable but also renders nicely to HTML and PDF (and, therefore, print).

Combining the two required a small pythonscript that acts as a filter. It parses your asciidoc document and scans for '[ASCIIART ..]' and '[TRAIICSA]' markers. Everything in between is fed to ditaa, and an asciidoc image reference is included in the filtered document, which can then be passed to asciidoc for forther processing. You are required to supply a filename which will be created and included, and you can optionally supply arguments between parenthesis which are passed directly to the asciidoc image: markup. By default, this means the title for the document.

I.e. the following markup:

= Sample =

- look at the nifty
- drawings!

[ASCIIART sample.png (Sample drawing)]
/----------\  /--------\  /---------\
| asciidoc |  | mumble |  |         |
|    +     |->| mumble |->| PROFIT! |
|  ditaa   |  | mumble |  |         |
\----------/  \--------/  \---------/
[TRAIICSA]

Will result in the following asiidoc markup after filtering

= Sample =

- look at the nifty
- drawings!

image:sample.png[Sample drawing]

which will render to the following HTML (somewhat scaled)

 asciidoc ditaa

The script ("handleimages.py") is rather trivial and doesn't handle errors too well (actually, not at all). But for me it gets the job done.

#!/usr/bin/env python
import sys
import re
import subprocess

header = re.compile("\[ASCIIART\s+(\S+?)\s*\((.*?)\)?\]")

def main(document):
    parsed = []
    parsing = False
    filename = ""
    worklist = {}
    for line in document:
        if line.strip().startswith("[ASCIIART"):
            filename, flags = header.match(line).groups()
            if flags:
                flags = "[%s]" % flags
            else:
                flags = ""
            parsed.append("image:%s%s\n\n" % (filename, flags))
            parsing = True
            worklist[filename] = ""
        elif line.strip() == "[TRAIICSA]":
            a = open("/tmp/asciiart.txt", "w")
            a.write(worklist[filename])
            a.close()
            parsing = False
            job = subprocess.Popen(["java", "-jar", "ditaa0_6b.jar", "-o", "/tmp/asciiart.txt", filename], stdout=subprocess.PIPE)
            job.wait()
        elif parsing:
            worklist[filename] += line
        else:
            parsed.append(line)

    print "".join(parsed)

if __name__ == "__main__":
    if len(sys.argv) == 2:
        document = open(sys.argv[1], "r").readlines()
    else:
        document = sys.stdin.readlines()
    main(document)

Invoke it, for example, using the following script ("create.sh")

#!/bin/sh 

if [ "$1" = "" ]; then
  echo "Specify an asciidoc file"
  exit
fi

TARGET=`basename $1 .txt`.html

./handleimages.py $1 | asciidoc -d book -o $TARGET - 

There's probably some plugin/extension system for asciidoc that I can use for a cleaner, tighter integration. But as I said, for now, this gets the job done.

 Closed comments

    Nice work Ivo, I put a link to your block in the AsciiDoc resources list http://www.methods.co.nz/asciidoc/index.html#X2

    Cheers, Stuart

Last updated April 18, 2013, 4:35 p.m.
comments powered by Disqus