#!/usr/bin/perl
# AsciiDoc (*.adoc) handler for ikiwiki.
# Inspired by Felix Obenhuber's work with asciidoc.
#
# Karl Mowatt-Wilson, May 2007.   http://mowson.org/karl
# (crudely hacked from otl.pm)

# Accepts one command-line parameter to ikiwiki:
#   ikiwiki --asciidoc-conf=/path/to/asciidoc.conf
#
# Or you can add it to ikiwiki.setup with a line like this:
#   asciidoc_conf => "/path/to/asciidoc.conf",
#
# Note that ikiwiki-generated html needs to be escaped so that asciidoc
# will pass it through untouched.  In general, this means prefixing and
# postfixing with '+++'
#
#  eg.    +++[[map pages="*"]]+++
#
# Things will get complicated if anything in your ikiwiki code generates
# a '+++' sequence...       (or anything else which asciidoc considers special)
#
# You can't use [[ .. ]] constructs in the asciidoc sections - they'll
# just get interpreted as being ikiwiki constructs, and probably make
# a mess.  You need to use asciidoc equivalents.
#  eg. instead of asciidoc [[anchor]] use [id="anchor"]

package IkiWiki::Plugin::asciidoc;

use warnings;
use strict;
use IkiWiki;
use File::Basename;

sub import {    #{{{
    hook( type => "htmlize", id => "adoc", call => \&htmlize );
    hook( type => "getopt",  id => "adoc", call => \&getopt );

}    # }}}

sub getopt () {    #{{{
    eval q{use Getopt::Long};
    error($@) if $@;
    Getopt::Long::Configure('pass_through');
    GetOptions( "asciidoc-conf=s" => \$config{asciidoc_conf} );
}    #}}}

sub htmlize (@) {    #{{{
    my %params = @_;

    # cd into dir of source file so that any asciidoc file-includes 
    # (eg. including a script listing in a page) have the correct dir to base 
    # relative paths from.
    # Normally, asciidoc would get this info from the source file path, but we
    # are feeding asciidoc through a pipe, so it doesn't know the path.
    chdir dirname( $config{srcdir} . "/" . $params{page} );

    # This forking business may not be necessary with asciidoc, but I don't know:
    # Can't use open2 since otl2html doesn't play nice with buffering.
    # Instead, fork off a child process that will run otl2html and feed
    # it the content. Then read otl2html's response.

    my $tries = 10;
    my $pid;
    do {
        $pid = open( KID_TO_READ, "-|" );
        unless ( defined $pid ) {
            $tries--;
            if ( $tries < 1 ) {
                debug("failed to fork: $@");
                return $params{content};
            }
        }
    } until defined $pid;

    if ( !$pid ) {
        $tries = 10;
        $pid   = undef;

        do {
            $pid = open( KID_TO_WRITE, "|-" );
            unless ( defined $pid ) {
                $tries--;
                if ( $tries < 1 ) {
                    debug("failed to fork: $@");
                    print $params{content};
                    exit;
                }
            }
        } until defined $pid;

        my @asciidoc_args = (
            defined $config{asciidoc_conf}
            ? ( '--conf-file', "$config{asciidoc_conf}" )
            : (),
            '--no-header-footer', 
            '--out-file', '-', 
            '-'
        );

        if ( !$pid ) {
            if ( !exec 'asciidoc', @asciidoc_args ) {
                debug("failed to run asciidoc: $@");
                print $params{content};
                exit;
            }
        }

        print KID_TO_WRITE $params{content};
        close KID_TO_WRITE;
        waitpid $pid, 0;
        exit;
    }

    local $/ = undef;
    my $ret = <KID_TO_READ>;
    close KID_TO_READ;
    waitpid $pid, 0;

    return $ret;
}    # }}}

1
