1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
# Script to be run whenever a section or an op is added or removed
# from ops.markdown. Or just before every commit. It makes sure
# that all sections and all entries are alphabetically sorted for
# easier lookup, while the Miscellaneous section is always last.
my @in = "ops.markdown".IO.slurp.lines(:!chomp);
my $line;
my @out;
my %sections;
class Section {
has $.name;
has $.label;
has %.ops;
method toc() {
my $ops := %!ops.keys.sort.map( {
my $name := .words.head;
my $label := .subst(/ \s* '`' (\w+) '`' /, { "-$0" }, :g );
"[$name](#$label)"
} ).join(" |\n");
"## [$!name](#$!label)\n\n$ops\n\n"
}
method doc() {
my $doc := %!ops.sort(*.key).map( -> (:key($name), :value($text)) {
"## $name\n$text"
} ).join;
"# <a id=\"$!label\"></a> $!name\n\n$doc"
}
}
# until we get to the table of contents
@out.push($line)
until ($line := @in.shift).starts-with('## [');
# skip the table of contents
Nil until ($line := @in.shift).starts-with('# <a id="');
# until the end of the file
while @in {
my $label := ~$line.match(/ '"' <( .* )> '"' /);
my $name := $line.match(/ 'a>' \s* <( .*/).chomp;
my $section := %sections{$label} //= Section.new(:$label,:$name);
# skip empty lines until first op
Nil until ($line := @in.shift).starts-with('## ');
# handle ops until end of file or next section
repeat {
my $op := $line.substr(3).chomp;
my @lines;
@lines.push($line)
until !@in
|| ($line := @in.shift).starts-with('## ')
|| $line.starts-with('# <a id="');
$section.ops{$op} = @lines.join;
} until !@in || $line.starts-with('# <a id="');
}
# Make sure <misc> comes last
my @labels = %sections.keys.sort: { $_ eq 'misc' ?? 'zzz' !! $_ };
# push labels and then sections
@out.push(%sections{$_}.toc) for @labels;
@out.push(%sections{$_}.doc) for @labels;
"ops.markdown".IO.spurt(@out.join);
|