From cad753baf9b25ddd8e4cb5454766fce1cdc4217a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 13 Sep 2013 09:14:24 +0100 Subject: [PATCH 1/6] IkiWiki::Render: make 'scan' idempotent If it does nothing when a page has already been scanned, we can use it at any time to force a page to be scanned. In particular, the templatebody plugin is going to need this. --- IkiWiki/Render.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index fa2940b01..9e93534c6 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -6,7 +6,7 @@ use warnings; use strict; use IkiWiki; -my (%backlinks, %rendered); +my (%backlinks, %rendered, %scanned); our %brokenlinks; my $links_calculated=0; @@ -154,6 +154,8 @@ sub genpage ($$) { sub scan ($) { my $file=shift; + return if $scanned{$file}; + $scanned{$file}=1; debug(sprintf(gettext("scanning %s"), $file)); From cbb3218db762341a1eafbf2892cb100755772f78 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 21 Feb 2014 21:10:43 +0000 Subject: [PATCH 2/6] add readtemplate hook --- IkiWiki.pm | 10 +++++++++- doc/plugins/write.mdwn | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index e5da04a3b..5e17c4a73 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2021,11 +2021,19 @@ sub template_depends ($$;@) { if (defined $page && defined $tpage) { add_depends($page, $tpage); } - + my @opts=( filter => sub { my $text_ref = shift; ${$text_ref} = decode_utf8(${$text_ref}); + run_hooks(readtemplate => sub { + ${$text_ref} = shift->( + id => $name, + page => $tpage, + content => ${$text_ref}, + untrusted => $untrusted, + ); + }); }, loop_context_vars => 1, die_on_bad_params => 0, diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index d2d1a6329..f4620b623 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -211,6 +211,26 @@ them to `%links`. Present in IkiWiki 2.40 and later. The function is passed named parameters "page" and "content". Its return value is ignored. +### readtemplate + + hook(type => "readtemplate", id => "foo", call => \&readtemplate); + +Runs on the raw source of a page or `*.tmpl` file that is being +used as a template, before it is parsed by [[!cpan HTML::Template]]. + +The function is passed named parameters: + +* `id`: the name under which the template was looked up, + such as `page.tmpl` or `note` +* `page`: the name of the template as a page or attachment in the wiki, + such as `templates/note`, or `undef` if it's outside the wiki (e.g. in + `/usr/share/ikiwiki/templates`) +* `content`: the content of the corresponding file +* `untrusted`: true if the template was loaded from the wiki or an underlay, + false if it was loaded from a trusted location + +It should return the replacement content. + ### filter hook(type => "filter", id => "foo", call => \&filter); From 7672014582a994624503399a1f50e855c4fc9ca7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 21 Feb 2014 22:45:29 +0000 Subject: [PATCH 3/6] Add templatebody plugin and directive, and enable it by default Also add a regression test for templatebody. --- IkiWiki.pm | 3 +- IkiWiki/Plugin/templatebody.pm | 81 ++++++++++++++++ doc/ikiwiki/directive/edittemplate.mdwn | 12 ++- doc/ikiwiki/directive/template.mdwn | 20 +++- doc/ikiwiki/directive/templatebody.mdwn | 28 ++++++ doc/plugins/templatebody.mdwn | 7 ++ doc/plugins/write.mdwn | 3 + doc/templates.mdwn | 9 +- t/templatebody.t | 123 ++++++++++++++++++++++++ 9 files changed, 278 insertions(+), 8 deletions(-) create mode 100644 IkiWiki/Plugin/templatebody.pm create mode 100644 doc/ikiwiki/directive/templatebody.mdwn create mode 100644 doc/plugins/templatebody.mdwn create mode 100755 t/templatebody.t diff --git a/IkiWiki.pm b/IkiWiki.pm index 5e17c4a73..d8cfc31cc 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -152,7 +152,8 @@ sub getsetup () { type => "internal", default => [qw{mdwn link inline meta htmlscrubber passwordauth openid signinedit lockedit conditional - recentchanges parentlinks editpage}], + recentchanges parentlinks editpage + templatebody}], description => "plugins to enable by default", safe => 0, rebuild => 1, diff --git a/IkiWiki/Plugin/templatebody.pm b/IkiWiki/Plugin/templatebody.pm new file mode 100644 index 000000000..3848b75c7 --- /dev/null +++ b/IkiWiki/Plugin/templatebody.pm @@ -0,0 +1,81 @@ +#!/usr/bin/perl +# Define self-documenting templates as wiki pages without HTML::Template +# markup leaking into IkiWiki's output. +# Copyright © 2013-2014 Simon McVittie. GPL-2+, see debian/copyright +package IkiWiki::Plugin::templatebody; + +use warnings; +use strict; +use IkiWiki 3.00; +use Encode; + +sub import { + hook(type => "getsetup", id => "templatebody", call => \&getsetup); + hook(type => "preprocess", id => "templatebody", call => \&preprocess, + scan => 1); + hook(type => "readtemplate", id => "templatebody", + call => \&readtemplate); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "core", + }, +} + +# This doesn't persist between runs: we're going to read and scan the +# template file regardless, so there's no point in saving it to the index. +# Example contents: +# ("templates/note" => "
\n\n
") +my %templates; + +sub preprocess (@) { + my %params=@_; + + # [[!templatebody "
hello
"]] results in + # preprocess("
hello
" => undef, page => ...) + my $content = $_[0]; + if (length $_[1]) { + error(gettext("first parameter must be the content")); + } + + $templates{$params{page}} = $content; + + return ""; +} + +sub readtemplate { + my %params = @_; + my $tpage = $params{page}; + my $content = $params{content}; + my $filename = $params{filename}; + + # pass-through if it's a .tmpl attachment or otherwise unsuitable + return $content unless defined $tpage; + return $content if $tpage =~ /\.tmpl$/; + my $src = $pagesources{$tpage}; + return $content unless defined $src; + return $content unless defined pagetype($src); + + # We might be using the template for [[!template]], which has to run + # during the scan stage so that templates can include scannable + # directives which are expanded in the resulting page. Calls to + # IkiWiki::scan are in arbitrary order, so the template might + # not have been scanned yet. Make sure. + require IkiWiki::Render; + IkiWiki::scan($src); + + # Having scanned it, we know whether it had a [[!templatebody]]. + if (exists $templates{$tpage}) { + return $templates{$tpage}; + } + + # If not, return the whole thing. (Eventually, after implementing + # a transition, this can become an error.) + return $content; +} + +1 diff --git a/doc/ikiwiki/directive/edittemplate.mdwn b/doc/ikiwiki/directive/edittemplate.mdwn index a6f301dd3..b3177daa8 100644 --- a/doc/ikiwiki/directive/edittemplate.mdwn +++ b/doc/ikiwiki/directive/edittemplate.mdwn @@ -18,17 +18,25 @@ the directive displaying a note about the template being registered, add "silent=yes". Often the template page contains a simple skeleton for a particular type of -page. For the bug report pages in the above example, it might look -something like: +page, wrapped in a [[templatebody]] directive. For the bug report pages in +the above example, it might look something like: + \[[!templatebody <` is replaced with the name of the page being created. +Text outside the [[templatebody]] directive is not part of the template, +and can be used to document it. + +If the template does not contain a [[templatebody]] directive, the entire +source of the page is used for the template. This is deprecated. + [[!meta robots="noindex, follow"]] diff --git a/doc/ikiwiki/directive/template.mdwn b/doc/ikiwiki/directive/template.mdwn index 9e3ae54df..dd1ca3d52 100644 --- a/doc/ikiwiki/directive/template.mdwn +++ b/doc/ikiwiki/directive/template.mdwn @@ -31,16 +31,25 @@ large chunks of marked up text to be embedded into a template: ## Creating a template -The template is a regular wiki page, located in the `templates/` +The template is in a regular wiki page, located in the `templates/` subdirectory inside the source directory of the wiki. +The contents of the [[templatebody]] directive are used as the +template. Anything outside that directive is not included in the template, +and is usually used as documentation describing the template. + +If the template does not contain a [[templatebody]] directive, the entire +source of the page is used for the template. This is deprecated, because +it leads to the template markup being interpreted as ordinary +page source when the page is built, as well as being used as the template. Alternatively, templates can be stored in a directory outside the wiki, as files with the extension ".tmpl". By default, these are searched for in `/usr/share/ikiwiki/templates`, the `templatedir` setting can be used to make another directory be searched first. When referring to templates outside the wiki source directory, the "id" -parameter is not interpreted as a pagespec, and you must include the full filename -of the template page, including the ".tmpl" extension. E.g.: +parameter is not interpreted as a pagespec, you must include the full filename +of the template page including the ".tmpl" extension, +and the templatebody directive is not used. E.g.: \[[!template id=blogpost.tmpl]] @@ -63,6 +72,7 @@ few things: Here's a sample template: + \[[!templatebody < Name: \[[]]
Age:
@@ -76,6 +86,10 @@ Here's a sample template: + ENDBODY]] + + This template describes a person. Parameters: name, age, + color (favorite color, optional), notes (optional). The filled out template will be formatted the same as the rest of the page that contains it, so you can include WikiLinks and all other forms of wiki diff --git a/doc/ikiwiki/directive/templatebody.mdwn b/doc/ikiwiki/directive/templatebody.mdwn new file mode 100644 index 000000000..dfadb2c2d --- /dev/null +++ b/doc/ikiwiki/directive/templatebody.mdwn @@ -0,0 +1,28 @@ +The `templatebody` directive is supplied by the +[[!iki plugins/templatebody desc=templatebody]] plugin. + +This directive allows wiki pages to be used as templates +for the [[template]] or [[edittemplate]] directive, without having +[[!cpan HTML::Template]] markup interpreted as wiki markup when that +page is built. + +This directive does not produce any output in the wiki page that +defines the template; the rest of that page can be used to to document +how to use the template. + +The first, un-named parameter is the content of the template. +Because templates often contain [[directives|ikiwiki/directive]], it's +convenient to use the "here-document" syntax for it: + + \[[!templatebody < +
Name:
+
Age:
+ + + + ENDBODY]] + +[[!meta robots="noindex, follow"]] diff --git a/doc/plugins/templatebody.mdwn b/doc/plugins/templatebody.mdwn new file mode 100644 index 000000000..eee5cde1a --- /dev/null +++ b/doc/plugins/templatebody.mdwn @@ -0,0 +1,7 @@ +[[!template id=plugin name=templatebody author="[[smcv]]" core=1]] +[[!tag type/special-purpose]] + +This plugin provides the [[ikiwiki/directive/templatebody]] +[[ikiwiki/directive]]. With this plugin, you can set up templates +stored in the wiki for [[template]] or [[edittemplate]] without the +[[!cpan HTML::Template]] markup being interpreted as wiki markup. diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index f4620b623..15f054c09 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -217,6 +217,9 @@ value is ignored. Runs on the raw source of a page or `*.tmpl` file that is being used as a template, before it is parsed by [[!cpan HTML::Template]]. +For instance, the [[plugins/templatebody]] plugin uses this to return +the content of the [[ikiwiki/directive/templatebody]] directive (if there +is one) instead of the page's full content. The function is passed named parameters: diff --git a/doc/templates.mdwn b/doc/templates.mdwn index d0f891c21..80372fcb7 100644 --- a/doc/templates.mdwn +++ b/doc/templates.mdwn @@ -14,8 +14,10 @@ easy to learn. All you really need to know to modify templates is this: [[!if test="enabled(template) or enabled(edittemplate)" then=""" ## template pages -Template pages are regular wiki pages that are used as templates for other -pages. +Template pages are regular wiki pages containing a +[[!iki ikiwiki/directive/templatebody desc="templatebody directive"]], +used as templates for other pages. The parts of the template +page outside the directive can be used to document it. """]] [[!if test="enabled(template)" then=""" @@ -38,6 +40,9 @@ feeds=no archive=yes sort=title template=titlepage rootpage=templates postformtext="Add a new template page named:"]] """]] +If the template does not contain a `templatebody` directive, the entire +source of the page is used for the template. This is deprecated. + ## template files Template files are unlike template pages in that they have the extension diff --git a/t/templatebody.t b/t/templatebody.t new file mode 100755 index 000000000..b0bc82ce5 --- /dev/null +++ b/t/templatebody.t @@ -0,0 +1,123 @@ +#!/usr/bin/perl +package IkiWiki; + +use warnings; +use strict; +use Test::More tests => 18; + +BEGIN { use_ok("IkiWiki"); } +BEGIN { use_ok("IkiWiki::Render"); } +BEGIN { use_ok("IkiWiki::Plugin::templatebody"); } +BEGIN { use_ok("IkiWiki::Plugin::mdwn"); } +BEGIN { use_ok("IkiWiki::Plugin::tag"); } +BEGIN { use_ok("IkiWiki::Plugin::template"); } + +sub assert_pagespec_matches { + my $page = shift; + my $spec = shift; + my @params = @_; + @params = (location => 'index') unless @params; + + my $res = pagespec_match($page, $spec, @params); + + if ($res) { + pass($res); + } + else { + fail($res); + } +} + +sub assert_pagespec_doesnt_match { + my $page = shift; + my $spec = shift; + my @params = @_; + @params = (location => 'index') unless @params; + + my $res = pagespec_match($page, $spec, @params); + + if (ref $res && $res->isa("IkiWiki::ErrorReason")) { + fail($res); + } + elsif ($res) { + fail($res); + } + else { + pass($res); + } +} + +ok(! system("rm -rf t/tmp; mkdir t/tmp t/tmp/src t/tmp/dst")); + +$config{verbose} = 1; +$config{srcdir} = 't/tmp/src'; +$config{underlaydir} = 't/tmp/src'; +$config{destdir} = 't/tmp/dst'; +$config{underlaydirbase} = '.'; +$config{templatedir} = 'templates'; +$config{usedirs} = 1; +$config{htmlext} = 'html'; +$config{wiki_file_chars} = "-[:alnum:]+/.:_"; +$config{default_pageext} = "mdwn"; +$config{wiki_file_prune_regexps} = [qr/^\./]; + +is(checkconfig(), 1); + +%oldrenderedfiles=%pagectime=(); +%pagesources=%pagemtime=%oldlinks=%links=%depends=%typedlinks=%oldtypedlinks= +%destsources=%renderedfiles=%pagecase=%pagestate=(); + +$pagesources{index} = "index.mdwn"; +$pagemtime{index} = $pagectime{index} = 1000000; +writefile("index.mdwn", "t/tmp/src", <,

+[[!tag greeting]] +ENDBODY]] + +This template says hello to someone. +[[!tag documentation]] +EOF +); + +$pagesources{"templates/oldtmpl"} = "templates/oldtmpl.mdwn"; +$pagemtime{index} = $pagectime{index} = 1000000; +writefile("templates/oldtmpl.mdwn", "t/tmp/src", <,

+EOF +); + +my %content; + +foreach my $page (keys %pagesources) { + my $content = readfile("t/tmp/src/$pagesources{$page}"); + $content = IkiWiki::filter($page, $page, $content); + $content = IkiWiki::preprocess($page, $page, $content); + $content{$page} = $content; +} + +# Templates are expanded +like($content{index}, qr{

hello, world

}); +like($content{index}, qr{

greetings, earthlings

}); +assert_pagespec_matches('index', 'tagged(greeting)'); +# The documentation from the templatebody-using page is not expanded +unlike($content{index}, qr{This template says hello to someone}); +assert_pagespec_doesnt_match('index', 'tagged(documentation)'); + +# In the templatebody-using page, the documentation is expanded +like($content{'templates/deftmpl'}, qr{This template says hello to someone}); +assert_pagespec_matches('templates/deftmpl', 'tagged(documentation)'); +# In the templatebody-using page, the template is *not* expanded +unlike($content{'templates/deftmpl'}, qr{

hello, world

}); +unlike($content{'templates/deftmpl'}, qr{

greetings, earthlings

}); +assert_pagespec_doesnt_match('templates/deftmpl', 'tagged(greeting)'); + +1; From 236c46a3f7e5e62296484dc47b4882f7f4327a06 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 13 Sep 2013 10:30:24 +0100 Subject: [PATCH 4/6] Use templatebody for the templates in the basewiki and docwiki --- doc/templates/gitbranch.mdwn | 5 +++-- doc/templates/links.mdwn | 4 ++++ doc/templates/note.mdwn | 5 +++-- doc/templates/plugin.mdwn | 5 +++-- doc/templates/popup.mdwn | 5 +++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/doc/templates/gitbranch.mdwn b/doc/templates/gitbranch.mdwn index 853da9280..4ea73c91b 100644 --- a/doc/templates/gitbranch.mdwn +++ b/doc/templates/gitbranch.mdwn @@ -1,9 +1,11 @@ +[[!templatebody < Available in a [[!taglink /git]] repository [[!taglink branch|/branches]].
Branch:
Author:
- +ENDBODY]] + This template is used to create an infobox for a git branch. It uses these parameters: @@ -13,4 +15,3 @@ these parameters: (e.g. github/master)
  • author - the author of the branch
  • -
    diff --git a/doc/templates/links.mdwn b/doc/templates/links.mdwn index 4bd1a85bf..3239a59c2 100644 --- a/doc/templates/links.mdwn +++ b/doc/templates/links.mdwn @@ -1,3 +1,4 @@ +[[!templatebody < [[ikiwiki_logo|logo/ikiwiki.png]]
      @@ -14,3 +15,6 @@ Flattr this +ENDBODY]] + +This template contains the navigation links used on the front page. diff --git a/doc/templates/note.mdwn b/doc/templates/note.mdwn index 9ef5ad942..8de7374bc 100644 --- a/doc/templates/note.mdwn +++ b/doc/templates/note.mdwn @@ -1,11 +1,12 @@ +[[!templatebody < - +ENDBODY]] + Use this template to insert a note into a page. The note will be styled to float to the right of other text on the page. This template has one parameter:
      • `text` - the text to display in the note
      -
      diff --git a/doc/templates/plugin.mdwn b/doc/templates/plugin.mdwn index 322c49445..d36dd5f85 100644 --- a/doc/templates/plugin.mdwn +++ b/doc/templates/plugin.mdwn @@ -1,3 +1,4 @@ +[[!templatebody < Plugin:
      Author:
      @@ -8,7 +9,8 @@ Currently enabled: [[!if test="enabled()" then="yes" else="no"]]< [[!if test="sourcepage(plugins/contrib/*)" then="""[[!meta title=" (third party plugin)"]]"""]] [[!tag plugins/type/core]] - +ENDBODY]] + This template is used to create an infobox for an ikiwiki plugin. It uses these parameters:
        @@ -16,4 +18,3 @@ these parameters:
      • author - the author of the plugin
      • core - set to a true value if the plugin is enabled by default
      -
      diff --git a/doc/templates/popup.mdwn b/doc/templates/popup.mdwn index 92455eb21..b721a95f9 100644 --- a/doc/templates/popup.mdwn +++ b/doc/templates/popup.mdwn @@ -1,4 +1,3 @@ - Use this template to create a popup window that is displayed when the mouse is over part of the page. This template has two parameters:
        @@ -10,7 +9,9 @@ large for good usability.
      Note that browsers that do not support the CSS will display the popup inline in the page, inside square brackets. -
      + +[[templatebody < [] +ENDBODY]] From a9fc30b19cfb68c1bd326e0088a677fc87c7dca5 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Mar 2014 10:11:04 +0000 Subject: [PATCH 5/6] Track whether we're in the scan or render phase In the scan phase, it's too early to match pagespecs or sort pages; in the render phase, both of those are OK. It would be possible to add phases later, renumbering them if necessary to maintain numerical order. --- IkiWiki.pm | 7 ++++++- IkiWiki/Render.pm | 11 ++++++++++- po/po2wiki | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index d8cfc31cc..9511c8303 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -14,7 +14,7 @@ use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase %pagestate %wikistate %renderedfiles %oldrenderedfiles %pagesources %delpagesources %destsources %depends %depends_simple @mass_depends %hooks %forcerebuild %loaded_plugins %typedlinks - %oldtypedlinks %autofiles @underlayfiles $lastrev}; + %oldtypedlinks %autofiles @underlayfiles $lastrev $phase}; use Exporter q{import}; our @EXPORT = qw(hook debug error htmlpage template template_depends @@ -34,6 +34,11 @@ our $DEPEND_CONTENT=1; our $DEPEND_PRESENCE=2; our $DEPEND_LINKS=4; +# Phases of processing. +sub PHASE_SCAN () { 0 } +sub PHASE_RENDER () { 1 } +$phase = PHASE_SCAN; + # Optimisation. use Memoize; memoize("abs2rel"); diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 9e93534c6..c88de1e8e 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -827,6 +827,8 @@ sub gen_autofile ($$$) { } sub refresh () { + $phase = PHASE_SCAN; + srcdir_check(); run_hooks(refresh => sub { shift->() }); my ($files, $pages, $new, $internal_new, $del, $internal_del, $changed, $internal_changed); @@ -878,7 +880,10 @@ sub refresh () { } calculate_links(); - + + # At this point it becomes OK to start matching pagespecs. + $phase = PHASE_RENDER; + remove_del(@$del, @$internal_del); foreach my $file (@$changed) { @@ -942,6 +947,10 @@ sub commandline_render () { loadindex(); unlockwiki(); + # This function behaves as though it's in the render phase; + # all other files are assumed to have been scanned last time. + $phase = PHASE_RENDER; + my $srcfile=possibly_foolish_untaint($config{render}); my $file=$srcfile; $file=~s/\Q$config{srcdir}\E\/?//; diff --git a/po/po2wiki b/po/po2wiki index 126aa8e17..862aa9d97 100755 --- a/po/po2wiki +++ b/po/po2wiki @@ -22,6 +22,8 @@ foreach my $file (@$files) { $pagesources{$page}=$file; # used by po plugin functions } +$IkiWiki::phase = IkiWiki::PHASE_RENDER; + foreach my $lang (@{$config{po_slave_languages}}) { my ($ll, $name)=IkiWiki::Plugin::po::splitlangpair($lang); $config{destdir}="../underlays/locale/$ll"; From c04a26f3e70d654ccec5542daf8425e44cb5bac8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Mar 2014 10:42:00 +0000 Subject: [PATCH 6/6] Assume that every page has been scanned by the time the scan phase ends This doesn't prevent memory from being used to track what we have and haven't scanned, but it does make it temporary. The existing %rendered hash, which is filled afterwards, will be larger than %scanned in practice anyway: %scanned will contain an entry for each page that changed, plus an entry for each template used by templatebody, whereas %rendered will contain an entry for each page that changed plus an entry for each page rendered due to links or dependencies. --- IkiWiki/Render.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index c88de1e8e..825c077da 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -154,7 +154,7 @@ sub genpage ($$) { sub scan ($) { my $file=shift; - return if $scanned{$file}; + return if $phase > PHASE_SCAN || $scanned{$file}; $scanned{$file}=1; debug(sprintf(gettext("scanning %s"), $file)); @@ -883,6 +883,9 @@ sub refresh () { # At this point it becomes OK to start matching pagespecs. $phase = PHASE_RENDER; + # Save some memory: we no longer need to keep track of which pages + # we've scanned + %scanned = (); remove_del(@$del, @$internal_del);