]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blobdiff - IkiWiki.pm
web commit by PaulWise: remove bogus comment
[git.ikiwiki.info.git] / IkiWiki.pm
index 1cfa419b6f614762a580f1e5aa702b4f4ae0d08f..0af4a4fe9303f292977294a8de5ec88d5ddf7d24 100644 (file)
@@ -33,13 +33,28 @@ sub defaultconfig () { #{{{
                qr/\.x?html?$/, qr/\.ikiwiki-new$/,
                qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//,
                qr/\.dpkg-tmp$/],
-       wiki_link_regexp => qr/\[\[(?:([^\]\|]+)\|)?([^\s\]#]+)(?:#([^\s\]]+))?\]\]/,
+       wiki_link_regexp => qr{
+               \[\[                    # beginning of link
+               (?:
+                       ([^\]\|]+)      # 1: link text
+                       \|              # followed by '|'
+               )?                      # optional
+
+               ([^\s\]#]+)             # 2: page to link to
+               (?:
+                       \#              # '#', beginning of anchor
+                       ([^\s\]]+)      # 3: anchor text
+               )?                      # optional
+
+               \]\]                    # end of link
+       }x,
        wiki_file_regexp => qr/(^[-[:alnum:]_.:\/+]+$)/,
        web_commit_regexp => qr/^web commit (by (.*?(?=: |$))|from (\d+\.\d+\.\d+\.\d+)):?(.*)/,
        verbose => 0,
        syslog => 0,
        wikiname => "wiki",
        default_pageext => "mdwn",
+       htmlext => "html",
        cgi => 0,
        post_commit => 0,
        rcs => '',
@@ -71,6 +86,7 @@ sub defaultconfig () { #{{{
        adminemail => undef,
        plugin => [qw{mdwn inline htmlscrubber passwordauth openid signinedit
                      lockedit conditional}],
+       libdir => undef,
        timeformat => '%c',
        locale => undef,
        sslcookie => 0,
@@ -112,7 +128,7 @@ sub checkconfig () { #{{{
                unless exists $config{wikistatedir};
        
        if ($config{rcs}) {
-               eval qq{require IkiWiki::Rcs::$config{rcs}};
+               eval qq{use IkiWiki::Rcs::$config{rcs}};
                if ($@) {
                        error("Failed to load RCS module IkiWiki::Rcs::$config{rcs}: $@");
                }
@@ -125,8 +141,12 @@ sub checkconfig () { #{{{
 } #}}}
 
 sub loadplugins () { #{{{
+       if (defined $config{libdir}) {
+               unshift @INC, $config{libdir};
+       }
+
        loadplugin($_) foreach @{$config{plugin}};
-       
+
        run_hooks(getopt => sub { shift->() });
        if (grep /^-/, @ARGV) {
                print STDERR "Unknown option: $_\n"
@@ -192,7 +212,7 @@ sub log_message ($$) { #{{{
 
 sub possibly_foolish_untaint ($) { #{{{
        my $tainted=shift;
-       my ($untainted)=$tainted=~/(.*)/;
+       my ($untainted)=$tainted=~/(.*)/s;
        return $untainted;
 } #}}}
 
@@ -242,7 +262,7 @@ sub targetpage ($$) { #{{{
 sub htmlpage ($) { #{{{
        my $page=shift;
        
-       return targetpage($page, "html");
+       return targetpage($page, $config{htmlext});
 } #}}}
 
 sub srcfile ($) { #{{{
@@ -452,7 +472,7 @@ sub displaytime ($) { #{{{
 sub beautify_url ($) { #{{{
        my $url=shift;
 
-       $url =~ s!/index.html$!/!;
+       $url =~ s!/index.$config{htmlext}$!/!;
        $url =~ s!^$!./!; # Browsers don't like empty links...
 
        return $url;
@@ -526,7 +546,12 @@ sub htmllink ($$$;@) { #{{{
                $bestlink.="#".$opts{anchor};
        }
 
-       return "<a href=\"$bestlink\">$linktext</a>";
+       my @attrs;
+       if (defined $opts{rel}) {
+               push @attrs, ' rel="'.$opts{rel}.'"';
+       }
+
+       return "<a href=\"$bestlink\"@attrs>$linktext</a>";
 } #}}}
 
 sub htmlize ($$$) { #{{{
@@ -592,14 +617,24 @@ sub preprocess ($$$;$$) { #{{{
                my $command=shift;
                my $params=shift;
                if (length $escape) {
-                       return "[[$command $params]]";
+                       return "\\[[$command $params]]";
                }
                elsif (exists $hooks{preprocess}{$command}) {
                        return "" if $scan && ! $hooks{preprocess}{$command}{scan};
                        # Note: preserve order of params, some plugins may
                        # consider it significant.
                        my @params;
-                       while ($params =~ /(?:(\w+)=)?(?:"""(.*?)"""|"([^"]+)"|(\S+))(?:\s+|$)/sg) {
+                       while ($params =~ m{
+                               (?:(\w+)=)?             # 1: named parameter key?
+                               (?:
+                                       """(.*?)"""     # 2: triple-quoted value
+                               |
+                                       "([^"]+)"       # 3: single-quoted value
+                               |
+                                       (\S+)           # 4: unquoted value
+                               )
+                               (?:\s+|$)               # delimiter to next param
+                       }sgx) {
                                my $key=$1;
                                my $val;
                                if (defined $2) {
@@ -643,11 +678,31 @@ sub preprocess ($$$;$$) { #{{{
                        return $ret;
                }
                else {
-                       return "[[$command $params]]";
+                       return "\\[[$command $params]]";
                }
        };
        
-       $content =~ s{(\\?)\[\[(\w+)\s+((?:(?:\w+=)?(?:""".*?"""|"[^"]+"|[^\s\]]+)\s*)*)\]\]}{$handle->($1, $2, $3)}seg;
+       $content =~ s{
+               (\\?)           # 1: escape?
+               \[\[            # directive open
+               (\w+)           # 2: command
+               \s+
+               (               # 3: the parameters..
+                       (?:
+                               (?:\w+=)?               # named parameter key?
+                               (?:
+                                       """.*?"""       # triple-quoted value
+                                       |
+                                       "[^"]+"         # single-quoted value
+                                       |
+                                       [^\s\]]+        # unquoted value
+                               )
+                               \s*                     # whitespace or end
+                                                       # of directive
+                       )
+               *)              # 0 or more parameters
+               \]\]            # directive closed
+       }{$handle->($1, $2, $3)}sexg;
        return $content;
 } #}}}
 
@@ -746,9 +801,9 @@ sub loadindex () { #{{{
                        $depends{$page}=$items{depends}[0] if exists $items{depends};
                        $destsources{$_}=$page foreach @{$items{dest}};
                        $renderedfiles{$page}=[@{$items{dest}}];
-                       $oldrenderedfiles{$page}=[@{$items{dest}}];
                        $pagecase{lc $page}=$page;
                }
+               $oldrenderedfiles{$page}=[@{$items{dest}}];
                $pagectime{$page}=$items{ctime}[0];
        }
        close IN;
@@ -798,7 +853,6 @@ sub template_params (@) { #{{{
                return "";
        }
 
-       require HTML::Template;
        my @ret=(
                filter => sub {
                        my $text_ref = shift;
@@ -813,6 +867,7 @@ sub template_params (@) { #{{{
 } #}}}
 
 sub template ($;@) { #{{{
+       require HTML::Template;
        HTML::Template->new(template_params(@_));
 } #}}}
 
@@ -977,7 +1032,21 @@ sub pagespec_translate ($) { #{{{
 
        # Convert spec to perl code.
        my $code="";
-       while ($spec=~m/\s*(\!|\(|\)|\w+\([^\)]+\)|[^\s()]+)\s*/ig) {
+       while ($spec=~m{
+               \s*             # ignore whitespace
+               (               # 1: match a single word
+                       \!              # !
+               |
+                       \(              # (
+               |
+                       \)              # )
+               |
+                       \w+\([^\)]+\)   # command(params)
+               |
+                       [^\s()]+        # any other text
+               )
+               \s*             # ignore whitespace
+       }igx) {
                my $word=$1;
                if (lc $word eq "and") {
                        $code.=" &&";
@@ -1056,8 +1125,8 @@ sub match_glob ($$;@) { #{{{
        
        # relative matching
        if ($glob =~ m!^\./!) {
-               $from=~s!/?[^/]+$!!;
-               $glob=~s!^\./!!;
+               $from=~s#/?[^/]+$##;
+               $glob=~s#^\./##;
                $glob="$from/$glob" if length $from;
        }
 
@@ -1083,18 +1152,23 @@ sub match_link ($$;@) { #{{{
 
        # relative matching
        if ($link =~ m!^\.! && defined $from) {
-               $from=~s!/?[^/]+$!!;
-               $link=~s!^\./!!;
+               $from=~s#/?[^/]+$##;
+               $link=~s#^\./##;
                $link="$from/$link" if length $from;
        }
 
        my $links = $IkiWiki::links{$page} or return undef;
        return IkiWiki::FailReason->new("$page has no links") unless @$links;
        my $bestlink = IkiWiki::bestlink($from, $link);
-       return IkiWiki::FailReason->new("no such link") unless length $bestlink;
        foreach my $p (@$links) {
-               return IkiWiki::SuccessReason->new("$page links to $link")
-                       if $bestlink eq IkiWiki::bestlink($page, $p);
+               if (length $bestlink) {
+                       return IkiWiki::SuccessReason->new("$page links to $link")
+                               if $bestlink eq IkiWiki::bestlink($page, $p);
+               }
+               else {
+                       return IkiWiki::SuccessReason->new("$page links to page matching $link")
+                               if match_glob($p, $link, %params);
+               }
        }
        return IkiWiki::FailReason->new("$page does not link to $link");
 } #}}}