X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/cb8b2f80b2f8c91eba3f3a6a5b9913ab80326df8..d50bd08439d5df17855b62f7c4d658027f93792d:/IkiWiki.pm diff --git a/IkiWiki.pm b/IkiWiki.pm index da36494fb..1730e476a 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -14,7 +14,7 @@ use open qw{:utf8 :std}; use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase %pagestate %wikistate %renderedfiles %oldrenderedfiles %pagesources %destsources %depends %depends_simple %hooks - %forcerebuild %loaded_plugins}; + %forcerebuild %loaded_plugins %typedlinks %oldtypedlinks}; use Exporter q{import}; our @EXPORT = qw(hook debug error template htmlpage deptype @@ -24,7 +24,7 @@ our @EXPORT = qw(hook debug error template htmlpage deptype add_underlay pagetitle titlepage linkpage newpagefile inject add_link %config %links %pagestate %wikistate %renderedfiles - %pagesources %destsources); + %pagesources %destsources %typedlinks); our $VERSION = 3.00; # plugin interface version, next is ikiwiki version our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE @@ -1165,7 +1165,7 @@ sub htmlize ($$$$) { my $content=shift; my $oneline = $content !~ /\n/; - + if (exists $hooks{htmlize}{$type}) { $content=$hooks{htmlize}{$type}{call}->( page => $page, @@ -1186,10 +1186,9 @@ sub htmlize ($$$$) { if ($oneline) { # hack to get rid of enclosing junk added by markdown - # and other htmlizers + # and other htmlizers/sanitizers $content=~s/^
//i; - $content=~s/<\/p>$//i; - chomp $content; + $content=~s/<\/p>\n*$//i; } return $content; @@ -1504,7 +1503,7 @@ sub loadindex () { if (! $config{rebuild}) { %pagesources=%pagemtime=%oldlinks=%links=%depends= %destsources=%renderedfiles=%pagecase=%pagestate= - %depends_simple=(); + %depends_simple=%typedlinks=%oldtypedlinks=(); } my $in; if (! open ($in, "<", "$config{wikistatedir}/indexdb")) { @@ -1570,6 +1569,14 @@ sub loadindex () { if (exists $d->{state}) { $pagestate{$page}=$d->{state}; } + if (exists $d->{typedlinks}) { + $typedlinks{$page}=$d->{typedlinks}; + + while (my ($type, $links) = each %{$typedlinks{$page}}) { + next unless %$links; + $oldtypedlinks{$page}{$type} = {%$links}; + } + } } $oldrenderedfiles{$page}=[@{$d->{dest}}]; } @@ -1618,6 +1625,10 @@ sub saveindex () { $index{page}{$src}{depends_simple} = $depends_simple{$page}; } + if (exists $typedlinks{$page} && %{$typedlinks{$page}}) { + $index{page}{$src}{typedlinks} = $typedlinks{$page}; + } + if (exists $pagestate{$page}) { foreach my $id (@hookids) { foreach my $key (keys %{$pagestate{$page}{$id}}) { @@ -1797,7 +1808,7 @@ sub add_depends ($$;$) { # Add explicit dependencies for influences. my $sub=pagespec_translate($pagespec); - return if $@; + return unless defined $sub; foreach my $p (keys %pagesources) { my $r=$sub->($p, location => $page); my $i=$r->influences; @@ -1927,16 +1938,22 @@ sub inject { use warnings; } -sub add_link ($$) { +sub add_link ($$;$) { my $page=shift; my $link=shift; + my $type=shift; push @{$links{$page}}, $link unless grep { $_ eq $link } @{$links{$page}}; + + if (defined $type) { + $typedlinks{$page}{$type}{$link} = 1; + } } -sub sortspec_translate ($) { +sub sortspec_translate ($$) { my $spec = shift; + my $reverse = shift; my $code = ""; my @data; @@ -1991,6 +2008,10 @@ sub sortspec_translate ($) { return sub { 0 }; } + if ($reverse) { + $code="-($code)"; + } + no warnings; return eval 'sub { '.$code.' }'; } @@ -2062,7 +2083,7 @@ sub pagespec_match ($$;@) { my $sub=pagespec_translate($spec); return IkiWiki::ErrorReason->new("syntax error in pagespec \"$spec\"") - if $@ || ! defined $sub; + if ! defined $sub; return $sub->($page, @params); } @@ -2080,7 +2101,9 @@ sub pagespec_match_list ($$;@) { my $sub=pagespec_translate($pagespec); error "syntax error in pagespec \"$pagespec\"" - if $@ || ! defined $sub; + if ! defined $sub; + my $sort=sortspec_translate($params{sort}, $params{reverse}) + if defined $params{sort}; my @candidates; if (exists $params{list}) { @@ -2093,20 +2116,19 @@ sub pagespec_match_list ($$;@) { ? grep { ! $params{filter}->($_) } keys %pagesources : keys %pagesources; } - - if (defined $params{sort}) { - @candidates = IkiWiki::SortSpec::sort_pages($params{sort}, - @candidates); - } - - @candidates=reverse(@candidates) if $params{reverse}; - - $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT); # clear params, remainder is passed to pagespec + $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT); my $num=$params{num}; delete @params{qw{num deptype reverse sort filter list}}; + # when only the top matches will be returned, it's efficient to + # sort before matching to pagespec, + if (defined $num && defined $sort) { + @candidates=IkiWiki::SortSpec::sort_pages( + $sort, @candidates); + } + my @matches; my $firstfail; my $count=0; @@ -2128,14 +2150,21 @@ sub pagespec_match_list ($$;@) { $depends_simple{$page}{lc $k} |= $i->{$k}; } - return @matches; + # when all matches will be returned, it's efficient to + # sort after matching + if (! defined $num && defined $sort) { + return IkiWiki::SortSpec::sort_pages( + $sort, @matches); + } + else { + return @matches; + } } sub pagespec_valid ($) { my $spec=shift; - my $sub=pagespec_translate($spec); - return ! $@; + return defined pagespec_translate($spec); } sub glob2re ($) { @@ -2255,26 +2284,34 @@ sub match_link ($$;@) { $link=derel($link, $params{location}); my $from=exists $params{location} ? $params{location} : ''; + my $linktype=$params{linktype}; + my $qualifier=''; + if (defined $linktype) { + $qualifier=" with type $linktype"; + } my $links = $IkiWiki::links{$page}; - return IkiWiki::FailReason->new("$page has no links", "" => 1) + return IkiWiki::FailReason->new("$page has no links", $page => $IkiWiki::DEPEND_LINKS, "" => 1) unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { if (length $bestlink) { - return IkiWiki::SuccessReason->new("$page links to $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) - if $bestlink eq IkiWiki::bestlink($page, $p); + if ((!defined $linktype || exists $IkiWiki::typedlinks{$page}{$linktype}{$p}) && $bestlink eq IkiWiki::bestlink($page, $p)) { + return IkiWiki::SuccessReason->new("$page links to $link$qualifier", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + } } else { - return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) - if match_glob($p, $link, %params); + if ((!defined $linktype || exists $IkiWiki::typedlinks{$page}{$linktype}{$p}) && match_glob($p, $link, %params)) { + return IkiWiki::SuccessReason->new("$page links to page $p$qualifier, matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + } my ($p_rel)=$p=~/^\/?(.*)/; $link=~s/^\///; - return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) - if match_glob($p_rel, $link, %params); + if ((!defined $linktype || exists $IkiWiki::typedlinks{$page}{$linktype}{$p_rel}) && match_glob($p_rel, $link, %params)) { + return IkiWiki::SuccessReason->new("$page links to page $p_rel$qualifier, matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + } } } - return IkiWiki::FailReason->new("$page does not link to $link", "" => 1); + return IkiWiki::FailReason->new("$page does not link to $link$qualifier", $page => $IkiWiki::DEPEND_LINKS, "" => 1); } sub match_backlink ($$;@) { @@ -2412,13 +2449,10 @@ sub match_ip ($$;@) { package IkiWiki::SortSpec; # This is in the SortSpec namespace so that the $a and $b that sort() uses -# $IkiWiki::SortSpec::a and $IkiWiki::SortSpec::b, so that plugins' cmp -# functions can access them easily. -sub sort_pages -{ - my $f = IkiWiki::sortspec_translate(shift); - - return sort $f @_; +# are easily available in this namespace, for cmp functions to use them. +sub sort_pages { + my $f=shift; + sort $f @_ } sub cmp_title {