# Copyright (C) 2005 Alex Schroeder # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . use strict; use v5.10; AddModuleDescription('moin.pl', 'Moin Markup Extension'); our ($q, $bol, @HtmlStack, %RuleOrder, @MyRules); push(@MyRules, \&MoinRule); $RuleOrder{\&MoinRule} = -10; # run before default rules because of [[BR]] my %moin_level; # mapping length of whitespace to indentation level my $moin_current; # the current length of whitespace (not indentation level!) sub MoinLength { my $str = shift; my $oldpos = pos; $str =~ s/\t/ /g; die if pos != $oldpos; return length($str); # the length of whitespace } sub MoinListLevel { my $oldpos = pos; my $length = MoinLength(shift); if (not InElement('li') and not InElement('dd')) { # problematic mixing! %moin_level = ($length => 1); $moin_current = $length; } elsif ($moin_level{$length}) { # return from a sublist or continuing the current list foreach my $ln (keys %moin_level) { delete $moin_level{$ln} if $moin_level{$ln} > $moin_level{$length}; } $moin_current = $length; } elsif ($length > $moin_current) { # or entering a new sublist $moin_level{$length} = $moin_level{$moin_current} + 1; $moin_current = $length; } else { # else we've returned to an invalid level - but we know that there is a higher level! $length++ until $moin_level{$length}; $moin_current = $length; } pos = $oldpos; return $moin_level{$moin_current} } sub MoinRule { # ["free link"] if (m/\G(\["(.*?)"\])/cgs) { Dirty($1); print GetPageOrEditLink($2); return ''; } # [[BR]] elsif (m/\G\[\[BR\]\]/cg) { return $q->br(); } # {{{ # block # }}} elsif ($bol && m/\G\{\{\{\n?(.*?\n)\}\}\}[ \t]*\n?/cgs) { return CloseHtmlEnvironments() . $q->pre({-class=>'real'}, $1) . AddHtmlEnvironment('p'); } # * list item # * nested item elsif ($bol && m/\G(\s*\n)*([ \t]+)\*[ \t]*/cg or InElement('li') && (m/\G(\s*\n)+([ \t]+)\*[ \t]*/cg)) { return CloseHtmlEnvironmentUntil('li') . OpenHtmlEnvironment('ul', MoinListLevel($2)) . AddHtmlEnvironment('li'); } # 1. list item # 1. nested item elsif ($bol && m/\G(\s*\n)*([ \t]+)1\.[ \t]*/cg or InElement('li') && m/\G(\s*\n)+([ \t]+)1\.[ \t]*/cg) { return CloseHtmlEnvironmentUntil('li') . OpenHtmlEnvironment('ol', MoinListLevel($2)) . AddHtmlEnvironment('li'); } # indented text using whitespace elsif ($bol && m/\G(\s*\n)*([ \t]+)/cg) { my $str = $2; if (MoinLength($str) == $moin_current and (InElement('li') or InElement('dd'))) { return ' '; } else { return CloseHtmlEnvironmentUntil('dd') . OpenHtmlEnvironment('dl', MoinListLevel($str), 'quote') . $q->dt() . AddHtmlEnvironment('dd'); } } # emphasis and strong emphasis using '' and ''' elsif (defined $HtmlStack[0] && $HtmlStack[1] && $HtmlStack[0] eq 'em' && $HtmlStack[1] eq 'strong' and m/\G'''''/cg) { # close either of the two return CloseHtmlEnvironment() . CloseHtmlEnvironment(); } # traditional wiki syntax for '''strong''' elsif (m/\G'''/cg) { return (defined $HtmlStack[0] && $HtmlStack[0] eq 'strong') ? CloseHtmlEnvironment() : AddHtmlEnvironment('strong'); } # traditional wiki syntax for ''emph'' elsif (m/\G''/cg) { return (defined $HtmlStack[0] && $HtmlStack[0] eq 'em') ? CloseHtmlEnvironment() : AddHtmlEnvironment('em'); } # moin syntax for __underline__ elsif (m/\G__/cg) { return (defined $HtmlStack[0] && $HtmlStack[0] eq 'em') ? CloseHtmlEnvironment() : AddHtmlEnvironment('em', 'style="text-decoration: underline; font-style: normal;"'); } # don't automatically fuse lines elsif (m/\G([ \t]+|[ \t]*\n)/cg) { return ' '; } return; }