Weave: Write documentation pages
[ Previous: Tangle: write code output ]
[ Top: xmlp alpha ]
[ Next: Write index page ]
The weave step is the other main function of traditional literate programming: it takes the
items as defined and creates the documentation file. Since the documentation in this case is
a set of pages, the philosophy is a little different. For each main item, we write a separate
documentation page (subitems are left on the same page as their respective parents, with
headings.)
The file <project>_format.html is used to generate each of these pages; a more elaborate
formatting control mechanism would be nice later, but this will do the trick for now. Code
pieces are written enclosed in <code>
tags, and <insert>
tags are replaced with the label, not the name, of the respective items.
The overall code for weave looks a lot like the scan code, because it's doing very similar
things. It scans lines of input, using global variables to mark its current state.
Setup is straightforward: we rewind the INPUT
filehandle, load the template
into a list (because we'll be scanning it once for each item page) and set some globals to
blank values.
|
seek INPUT, 0, 0;
open TEM, $format_html;
@template = <TEM>;
close TEM;
$name = '';
$item = 0;
$piece = 0;
while (<INPUT>) {
|
So let's get down to business scanning. The thing weave is interested in is items, so
let's look for <item>
tags first. For each item we encounter, we'll set
up replacement tags as follows:
[##next##]
and [##prev##]
These contain the URLs of the next and previous items in the list, respectively. The first
item has a [##prev##]
pointing to the index, and the last has a
[##next##]
pointing to the index.
[##nextlabel##]
and [##prevlabel##]
The labels of the next and previous items, for nice link formatting.
[##body##]
The body of the item is its documentation and properly formatted code. In other words, most
of the work of weave is to build up the [##body##]
tag.
[##name##]
, [##url##]
and [##label##]
The name, URL and label of the current item.
Eventually we'll want change dates as well, but we're not tracking it yet, so there's not much
point. All in good time.
|
if (/(<item .*>)/i)
{
$tag = $1;
$tag =~ s/^<item\s+//i;
$attr = "";
%thisitem = (name => '', label => '', pattern => '', language => '');
foreach $part (split /"/, $tag) {
if ($attr eq '') {
$attr = $part;
$attr =~ s/^\s*//;
$attr =~ s/\s*=\s*$//;
} else {
$thisitem{$attr} = $part;
$attr = '';
}
}
$name = $thisitem{name};
if ($parent{$name} eq '') {
$tags{name} = $name;
$tags{url} = $url{$name};
$tags{label} = $label{$name};
if ($item == 0) {
$tags{prev} = "index.html";
$tags{prevlabel} = "index";
} else {
$i = $items[$item-1];
if ($parent{$i} ne '') { $i = $parent{$i}; }
$tags{prev} = $url{$i};
$tags{prevlabel} = $label{$i};
}
$tags{body} = '';
} else {
$n = $name;
$n =~ s/^.*?\.//;
$tags{body} .= "<br><br>\n";
$tags{body} .= "<a name=\"$n\">\n";
$tags{body} .= "<i>$label{$name}</i><br>\n";
}
if ($item == $#items) {
$tags{next} = "index.html";
$tags{nextlabel} = "index";
} else {
$tags{next} = $url{$items[$item+1]};
$tags{nextlabel} = $label{$items[$item+1]};
}
next;
}
next if $name eq '';
|
And of course we terminate the item similarly to the scanner. The difference is that we also
write out the current item's page using the various tags we've accumulated during scanning.
|
if (/(<\/item\s*>)/i) {
if (($parent{$name} eq '' && $children{$name} == 0) || $lastchild{$parent{$name}} eq $name)
{
if ($parent{$name} eq '') {
open OUT, ">$url{$name}";
} else {
open OUT, ">$url{$parent{$name}}";
}
foreach $line (@template) {
$_ = $line;
while (/\[##(.*?)##\]/) {
$tag=$1;
s/\[##$tag##\]/$tags{$tag}/e;
}
print OUT;
}
close OUT;
}
$name = '';
$item++;
next;
}
|
While in an <item>
, we scan for pieces, just like scan. Text inside pieces
is formatted differently (with spacing and linebreaks intact.)
|
if (/(<piece.*>)/i)
{
$tag = $1;
$tag =~ s/^<piece\s*//i;
$attr = "";
%thispiece = (add-to => '', language => '');
foreach $part (split /"/, $tag) {
if ($attr eq '') {
$attr = $part;
$attr =~ s/^\s*//;
$attr =~ s/\s*=\s*$//;
} else {
$thispiece{$attr} = $part;
$attr = '';
}
}
$tags{body} .= "<table width=100%>\n";
$tags{body} .= "<tr><td width=30 bgcolor=eeeeee> </td><td width=100%>\n";
if ($thispiece{'add-to'} ne '') {
$tags{body} .= "<i>Add the following to \"$label{$thispiece{'add-to'}}\"</i><br>\n";
}
$tags{body} .= "<pre>";
$piece = 1;
next;
}
if (/<\/piece\s*>/i) {
$tags{body} .= "</pre>";
$tags{body} .= "</td></tr></table>\n";
$piece = 0;
next;
}
|
Almost done. The only remaining thing is to format <insert>
tags.
|
if (/(<insert\s.*>)/i)
{
$tag = $1;
$before = $`;
$after = $';
$tag =~ s/^<insert\s+//i;
$attr = "";
%thisinsert = (name => '');
foreach $part (split /"/, $tag) {
if ($attr eq '') {
$attr = $part;
$attr =~ s/^\s*//;
$attr =~ s/\s*=\s*$//;
} else {
$thisinsert{$attr} = $part;
$attr = '';
}
}
if ($thisinsert{name} =~ /^\./) {
$thisinsert{name} = $name . $thisinsert{name};
}
$tags{body} .= $before . "<i>See <a href=\"$url{$thisinsert{name}}\">";
$tags{body} .= "$label{$thisinsert{name}}</a></i>$after";
next;
}
|
And finally, any line which doesn't contain an <insert>
and which is actually
within an <item>
simply gets tacked onto the current item's body after we
make sure all the characters are going to display correctly. Note especially the attention
to detail with the [## delimiter -- if we didn't replace that with a version containing an
HTML entity instead (#) then we'd have a problem with recursion once we get into the
template application code. Which, of course, I realized only after having a problem with
recursion once I got into the template application code.
|
s/&/&/g if $piece;
s/\[\[/</g if $piece;
s/\[\#\#/[##/g;
$tags{body} .= $_ if $name ne '';
}
|
[ Previous: Tangle: write code output ]
[ Top: xmlp alpha ]
[ Next: Write index page ]
This code and documentation are released under the terms of the GNU license. They are
additionally copyright (c) 2000, Vivtek. All rights reserved except those explicitly
granted under the terms of the GNU license.
|