X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/5e236f5d25b68f5fb4a421b24470419c6042cb1c..73f4a8835876c8cb07808367cd72d9ae972893e8:/IkiWiki.pm
diff --git a/IkiWiki.pm b/IkiWiki.pm
index c787612e1..5d5c7f0d0 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
@@ -17,7 +17,7 @@ use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase
%forcerebuild %loaded_plugins};
use Exporter q{import};
-our @EXPORT = qw(hook debug error template htmlpage deptype use_pagespec
+our @EXPORT = qw(hook debug error template htmlpage deptype
add_depends pagespec_match pagespec_match_list bestlink
htmllink readfile writefile pagetype srcfile pagename
displaytime will_render gettext urlto targetpage
@@ -38,7 +38,6 @@ our $DEPEND_LINKS=4;
use Memoize;
memoize("abs2rel");
memoize("pagespec_translate");
-memoize("file_pruned");
memoize("template_file");
sub getsetup () {
@@ -882,7 +881,7 @@ sub bestlink ($$) {
$l.="/" if length $l;
$l.=$link;
- if (exists $links{$l}) {
+ if (exists $pagesources{$l}) {
return $l;
}
elsif (exists $pagecase{lc $l}) {
@@ -892,7 +891,7 @@ sub bestlink ($$) {
if (length $config{userdir}) {
my $l = "$config{userdir}/".lc($link);
- if (exists $links{$l}) {
+ if (exists $pagesources{$l}) {
return $l;
}
elsif (exists $pagecase{lc $l}) {
@@ -1027,6 +1026,13 @@ sub urlto ($$;$) {
return beautify_urlpath($link);
}
+sub isselflink ($$) {
+ my $page=shift;
+ my $link=shift;
+
+ return $page eq $link;
+}
+
sub htmllink ($$$;@) {
my $lpage=shift; # the page doing the linking
my $page=shift; # the page that will contain the link (different for inline)
@@ -1052,7 +1058,7 @@ sub htmllink ($$$;@) {
}
return "$linktext"
- if length $bestlink && $page eq $bestlink &&
+ if length $bestlink && isselflink($page, $bestlink) &&
! defined $opts{anchor};
if (! $destsources{$bestlink}) {
@@ -1082,11 +1088,10 @@ sub htmllink ($$$;@) {
}
my @attrs;
- if (defined $opts{rel}) {
- push @attrs, ' rel="'.$opts{rel}.'"';
- }
- if (defined $opts{class}) {
- push @attrs, ' class="'.$opts{class}.'"';
+ foreach my $attr (qw{rel class title}) {
+ if (defined $opts{$attr}) {
+ push @attrs, " $attr=\"$opts{$attr}\"";
+ }
}
return "$linktext";
@@ -1409,7 +1414,7 @@ sub check_content (@) {
my %old=map { $_ => 1 }
split("\n", readfile(srcfile($pagesources{$params{page}})));
foreach my $line (split("\n", $params{content})) {
- push @diff, $line if ! exists $old{$_};
+ push @diff, $line if ! exists $old{$line};
}
$params{diff}=join("\n", @diff);
}
@@ -1781,105 +1786,20 @@ sub add_depends ($$;$) {
return 1;
}
- # Analyse the pagespec, and match it against all pages
- # to get a list of influences, and add explicit dependencies
- # for those.
- #my $sub=pagespec_translate($pagespec);
- #return if $@;
- #foreach my $p (keys %pagesources) {
- # my $r=$sub->($p, location => $page );
- # my %i=$r->influences;
- # foreach my $i (keys %i) {
- # $depends_simple{$page}{lc $i} |= $i{$i};
- # }
- #}
- print STDERR "warning: use of add_depends; influences not tracked\n";
-
- $depends{$page}{$pagespec} |= $deptype;
- return 1;
-}
-
-sub use_pagespec ($$;@) {
- my $page=shift;
- my $pagespec=shift;
- my %params=@_;
-
+ # Add explicit dependencies for influences.
my $sub=pagespec_translate($pagespec);
- error "syntax error in pagespec \"$pagespec\""
- if $@ || ! defined $sub;
-
- my @candidates;
- if (exists $params{limit}) {
- @candidates=grep { $params{limit}->($_) } keys %pagesources;
- }
- else {
- @candidates=keys %pagesources;
- }
-
- if (defined $params{sort}) {
- my $f;
- if ($params{sort} eq 'title') {
- $f=sub { pagetitle(basename($a)) cmp pagetitle(basename($b)) };
- }
- elsif ($params{sort} eq 'title_natural') {
- eval q{use Sort::Naturally};
- if ($@) {
- error(gettext("Sort::Naturally needed for title_natural sort"));
- }
- $f=sub { Sort::Naturally::ncmp(pagetitle(basename($a)), pagetitle(basename($b))) };
- }
- elsif ($params{sort} eq 'mtime') {
- $f=sub { $pagemtime{$b} <=> $pagemtime{$a} };
- }
- elsif ($params{sort} eq 'age') {
- $f=sub { $pagectime{$b} <=> $pagectime{$a} };
- }
- else {
- error sprintf(gettext("unknown sort type %s"), $params{sort});
- }
- @candidates = sort { &$f } @candidates;
- }
-
- @candidates=reverse(@candidates) if $params{reverse};
-
- my @matches;
- my $firstfail;
- my $count=0;
- foreach my $p (@candidates) {
+ return if $@;
+ foreach my $p (keys %pagesources) {
my $r=$sub->($p, location => $page);
- if ($r) {
- push @matches, [$p, $r];
- last if defined $params{num} && ++$count == $params{num};
- }
- elsif (! defined $firstfail) {
- $firstfail=$r;
+ my $i=$r->influences;
+ foreach my $k (keys %$i) {
+ $depends_simple{$page}{lc $k} |= $i->{$k};
}
+ last if $r->influences_static;
}
-
- $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT);
- my @ret;
- if (@matches) {
- # Add all influences from successful matches.
- foreach my $m (@matches) {
- push @ret, $m->[0];
- my %i=$m->[1]->influences;
- foreach my $i (keys %i) {
- $depends_simple{$page}{lc $i} |= $i{$i};
- }
- }
- }
- elsif (defined $firstfail) {
- # Add influences from one failure. (Which one should not
- # matter; all should have the same influences.)
- my %i=$firstfail->influences;
- foreach my $i (keys %i) {
- $depends_simple{$page}{lc $i} |= $i{$i};
- }
- error(sprintf(gettext("cannot match pages: %s"), $firstfail));
- }
-
- return @ret;
+ $depends{$page}{$pagespec} |= $deptype;
+ return 1;
}
sub deptype (@) {
@@ -1898,14 +1818,18 @@ sub deptype (@) {
return $deptype;
}
-sub file_pruned ($$) {
- require File::Spec;
- my $file=File::Spec->canonpath(shift);
- my $base=File::Spec->canonpath(shift);
- $file =~ s#^\Q$base\E/+##;
+sub file_pruned ($;$) {
+ my $file=shift;
+ if (@_) {
+ require File::Spec;
+ $file=File::Spec->canonpath($file);
+ my $base=File::Spec->canonpath(shift);
+ return if $file eq $base;
+ $file =~ s#^\Q$base\E/+##;
+ }
my $regexp='('.join('|', @{$config{wiki_file_prune_regexps}}).')';
- return $file =~ m/$regexp/ && $file ne $base;
+ return $file =~ m/$regexp/;
}
sub define_gettext () {
@@ -2050,27 +1974,87 @@ sub pagespec_match ($$;@) {
}
sub pagespec_match_list ($$;@) {
- my $pages=shift;
- my $spec=shift;
- my @params=@_;
+ my $page=shift;
+ my $pagespec=shift;
+ my %params=@_;
- my $sub=pagespec_translate($spec);
- error "syntax error in pagespec \"$spec\""
- if $@ || ! defined $sub;
-
- my @ret;
- my $r;
- foreach my $page (@$pages) {
- $r=$sub->($page, @params);
- push @ret, $page if $r;
+ # Backwards compatability with old calling convention.
+ if (ref $page) {
+ print STDERR "warning: a plugin (".caller().") is using pagespec_match_list in an obsolete way, and needs to be updated\n";
+ $params{list}=$page;
+ $page=$params{location}; # ugh!
}
- if (! @ret && defined $r && $r->isa("IkiWiki::ErrorReason")) {
- error(sprintf(gettext("cannot match pages: %s"), $r));
+ my $sub=pagespec_translate($pagespec);
+ error "syntax error in pagespec \"$pagespec\""
+ if $@ || ! defined $sub;
+
+ my @candidates;
+ if (exists $params{list}) {
+ @candidates=exists $params{filter}
+ ? grep { ! $params{filter}->($_) } @{$params{list}}
+ : @{$params{list}};
}
else {
- return @ret;
+ @candidates=exists $params{filter}
+ ? grep { ! $params{filter}->($_) } keys %pagesources
+ : keys %pagesources;
}
+
+ if (defined $params{sort}) {
+ my $f;
+ if ($params{sort} eq 'title') {
+ $f=sub { pagetitle(basename($a)) cmp pagetitle(basename($b)) };
+ }
+ elsif ($params{sort} eq 'title_natural') {
+ eval q{use Sort::Naturally};
+ if ($@) {
+ error(gettext("Sort::Naturally needed for title_natural sort"));
+ }
+ $f=sub { Sort::Naturally::ncmp(pagetitle(basename($a)), pagetitle(basename($b))) };
+ }
+ elsif ($params{sort} eq 'mtime') {
+ $f=sub { $pagemtime{$b} <=> $pagemtime{$a} };
+ }
+ elsif ($params{sort} eq 'age') {
+ $f=sub { $pagectime{$b} <=> $pagectime{$a} };
+ }
+ else {
+ error sprintf(gettext("unknown sort type %s"), $params{sort});
+ }
+ @candidates = sort { &$f } @candidates;
+ }
+
+ @candidates=reverse(@candidates) if $params{reverse};
+
+ $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT);
+
+ # clear params, remainder is passed to pagespec
+ my $num=$params{num};
+ delete @params{qw{num deptype reverse sort filter list}};
+
+ my @matches;
+ my $firstfail;
+ my $count=0;
+ my $accum=IkiWiki::SuccessReason->new();
+ foreach my $p (@candidates) {
+ my $r=$sub->($p, %params, location => $page);
+ error(sprintf(gettext("cannot match pages: %s"), $r))
+ if $r->isa("IkiWiki::ErrorReason");
+ $accum |= $r;
+ if ($r) {
+ push @matches, $p;
+ last if defined $num && ++$count == $num;
+ }
+ }
+
+ # Add simple dependencies for accumulated influences.
+ my $i=$accum->influences;
+ foreach my $k (keys %$i) {
+ $depends_simple{$page}{lc $k} |= $i->{$k};
+ }
+
+ return @matches;
}
sub pagespec_valid ($) {
@@ -2093,7 +2077,7 @@ use overload (
'""' => sub { $_[0][0] },
'0+' => sub { 0 },
'!' => sub { bless $_[0], 'IkiWiki::SuccessReason'},
- '&' => sub { $_[0]->merge_influences($_[1]); $_[0] },
+ '&' => sub { $_[0]->merge_influences($_[1], 1); $_[0] },
'|' => sub { $_[1]->merge_influences($_[0]); $_[1] },
fallback => 1,
);
@@ -2106,7 +2090,7 @@ use overload (
'""' => sub { $_[0][0] },
'0+' => sub { 1 },
'!' => sub { bless $_[0], 'IkiWiki::FailReason'},
- '&' => sub { $_[1]->merge_influences($_[0]); $_[1] },
+ '&' => sub { $_[1]->merge_influences($_[0], 1); $_[1] },
'|' => sub { $_[0]->merge_influences($_[1]); $_[0] },
fallback => 1,
);
@@ -2119,19 +2103,30 @@ sub new {
sub influences {
my $this=shift;
- if (! @_) {
- return %{$this->[1]};
- }
- else {
- $this->[1]={@_};
- }
+ $this->[1]={@_} if @_;
+ my %i=%{$this->[1]};
+ delete $i{""};
+ return \%i;
+}
+
+sub influences_static {
+ return ! $_[0][1]->{""};
}
sub merge_influences {
my $this=shift;
my $other=shift;
- foreach my $influence (keys %{$other->[1]}) {
- $this->[1]{$influence} |= $other->[1]{$influence};
+ my $anded=shift;
+
+ if (! $anded || (($this || %{$this->[1]}) &&
+ ($other || %{$other->[1]}))) {
+ foreach my $influence (keys %{$other->[1]}) {
+ $this->[1]{$influence} |= $other->[1]{$influence};
+ }
+ }
+ else {
+ # influence blocker
+ $this->[1]={};
}
}
@@ -2188,24 +2183,24 @@ sub match_link ($$;@) {
my $from=exists $params{location} ? $params{location} : '';
my $links = $IkiWiki::links{$page};
- return IkiWiki::FailReason->new("$page has no links")
+ return IkiWiki::FailReason->new("$page has no 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)
+ return IkiWiki::SuccessReason->new("$page links to $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1)
if $bestlink eq IkiWiki::bestlink($page, $p);
}
else {
- return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page => $IkiWiki::DEPEND_LINKS)
+ return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1)
if match_glob($p, $link, %params);
my ($p_rel)=$p=~/^\/?(.*)/;
$link=~s/^\///;
- return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page => $IkiWiki::DEPEND_LINKS)
+ return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1)
if match_glob($p_rel, $link, %params);
}
}
- return IkiWiki::FailReason->new("$page does not link to $link");
+ return IkiWiki::FailReason->new("$page does not link to $link", "" => 1);
}
sub match_backlink ($$;@) {