I've found myself wanting to know which [[plugins]] are switched on so I know which pre-processor commands I can use. The attached [[patch]] adds a new plugin that generates the list of available plugins. -- [[Will]]
Good idea, I do see a few problems:
- preprocessor directives do not necessarily have the same name as the
plugin that contains them (for example, the graphviz plugin adds a graph
directive). Won't keys
%{IkiWiki::hooks{preprocess}} work?
Er, yeah - that's a much better solution. :) -- and done
- "listplugins" is a bit misnamed since it only does preprocessor directives.
Yes. Initially this was going to list all enabled plugins. Then when searching
for enabled plugins I changed my mind and decided that a list of pre-processor
directives was more useful. I'll fix that too. -- changed to listpreprocessors
- comment was copied from version plugin and still mentions version :-)
:-) -- fixed
- Seems like [[ikiwiki/formatting]] could benefit from including the
list.. however, just a list of preprocessor directive names is not
the most user-friendly thing that could be put on that page. It would
be nice if there were also a short description and maybe an example of
use. Seems like the place to include that info would be in the call
to
hook() .
(Maybe adding that is more involved than you want to go though..)
--[[Joey]]
Adding a whole new hook for a usage example is more effort than I
wanted to go to. I was thinking of either:
- Adding a configuration for a wiki directory. If a matching page is in the
specified wiki directory then the plugin name gets turned into a link to that
page
- Adding configuration for an external URL. Each plugin name is added as
a link to the plugin name appended to the URL.
The first option is easier to navigate and wouldn't produce broken links,
but requires all the plugin documentation to be local. The second option
can link back to the main IkiWiki site, but if you have any non-standard
plugins then you'll get broken links.
Hrm. After listing all of that, maybe your idea with the hooks is the better
solution. I'll think about it some more. -- [[Will]]
I started implementing the hook based solution, and decided I didn't like
it because there was no nice way to rebuild pages when the preprocessor
descriptions changed. So instead I assumed that the the [[plugins]] pages
would be moved into the underlay directory. This plugin then uses an
inline directive to include those pages. You can use the inline
parameter to decide if you want to include all the descriptions or
just the titles. There is also an option to auto-create default/blank
description pages if they are missing (from a template). As preprocessor
commands don't list unless they have a description page, auto-creation
is enabled by default.
There are three new templates that are needed. These are for:
- The auto-created description pages are generated from
preprocessor-description.tmpl .
- When only pre-processor names are listed, the
listpreprocessors-listonly.tmpl template is used.
- When pre-processor descriptions are included inline, the
listpreprocessors-inline.tmpl template is used.
-- [[Will]]
Just a quick note: pages are only created for pre-processor commands
that exist when the refresh hook is called. This is before the [[shortcuts]] are
processed. However, the list of available pre-processor commands will include
shortcuts if they have description pages (the list is generated later, after the
shortcuts have been added). While this was unplanned, it seems a reasonable
tradeoff between including all the large number of shortcuts and including none. -- [[Will]]
Here is the main listpreprocessors plugin. (Note, because this has double square brackets in the source, it isn't quite displaying correctly - look at the page source for details.) New template files follow:
#!/usr/bin/perl
# Ikiwiki listpreprocessors plugin.
package IkiWiki::Plugin::listpreprocessors;
use warnings;
use strict;
use Encode;
use IkiWiki 2.00;
sub import { #{{{
hook(type => "getsetup", id => "listpreprocessors", call => \&getsetup);
hook(type => "preprocess", id => "listpreprocessors", call => \&preprocess);
hook(type => "refresh", id => "listpreprocessors", call => \&refresh);
} # }}}
sub getsetup () { #{{{
return
plugin => {
safe => 1,
rebuild => undef,
},
preprocessor_description_dir => {
type => "string",
description => "The ikiwiki directory that contains plugin descriptions.",
safe => 1,
rebuild => 1,
},
preprocessor_description_autocreate => {
type => "boolean",
description => "Should pre-processor command descriptions be automatically created from a template.",
safe => 1,
rebuild => 1,
},
} #}}}
sub gendescription ($$) { #{{{
my $plugin=shift;
my $page=shift;
my $file=$page.".".$config{default_pageext};
my $template=template("preprocessor-description.tmpl");
$template->param(page => $page, plugin => $plugin);
writefile($file, $config{srcdir}, $template->output);
if ($config{rcs}) {
IkiWiki::rcs_add($file);
}
} #}}}
sub refresh () { #{{{
eval q{use File::Find};
error($@) if $@;
if (defined $config{preprocessor_description_autocreate} && ! $config{preprocessor_description_autocreate}) {
return; # create pages unless they explicitly ask us not to
}
if (!defined $config{preprocessor_description_dir}) {
$config{preprocessor_description_dir} = "ikiwiki/plugin/";
}
my @pluginlist = sort( keys %{ $IkiWiki::hooks{preprocess} } );
my %pluginpages;
if (@pluginlist) {
my ($plugin,$page);
foreach $plugin (@pluginlist) {
$pluginpages{$plugin} = $config{preprocessor_description_dir} . $plugin;
}
my %pages;
foreach my $dir ($config{srcdir}, @{$config{underlaydirs}}, $config{underlaydir}) {
find({
no_chdir => 1,
wanted => sub {
$_=decode_utf8($_);
if (IkiWiki::file_pruned($_, $dir)) {
$File::Find::prune=1;
}
elsif (! -l $_) {
my ($f)=/$config{wiki_file_regexp}/; # untaint
return unless defined $f;
$f=~s/^\Q$dir\E\/?//;
return unless length $f;
return if $f =~ /\._([^.]+)$/; # skip internal page
if (! -d _) {
$pages{pagename($f)}=$f;
}
}
}
}, $dir);
}
if ($config{rcs}) {
IkiWiki::disable_commit_hook();
}
my $needcommit = 0;
while (($plugin,$page) = each %pluginpages) {
if (! exists $pages{$page}) {
$needcommit = 1;
gendescription($plugin,$page);
}
}
if ($config{rcs}) {
if ($needcommit) {
IkiWiki::rcs_commit_staged(
gettext("automatic pre-processor description generation"),
undef, undef);
}
IkiWiki::enable_commit_hook();
}
}
} #}}}
sub preprocess (@) { #{{{
my %params=@_;
if (!defined $config{plugin_description_dir}) {
$config{plugin_description_dir} = "ikiwiki/plugin/";
}
my @pluginlist = sort( keys %{ $IkiWiki::hooks{preprocess} } );
foreach my $plugin (@pluginlist) {
$plugin = $config{plugin_description_dir} . $plugin;
}
my $pluginString = join (' or ', @pluginlist);
my $result = "[[!inline pages=\"$pluginString\" feeds=\"no\" show=0 sort=\"title\"";
if (defined $params{inline}) {
$result .= ' template=\"listpreprocessors-listonly\" archive="yes"';
} else {
$result .= ' template=\"listpreprocessors-inline\" archive="no"';
}
$result .= "]]";
return IkiWiki::preprocess($params{page}, $params{destpage},
IkiWiki::filter($params{page}, $params{destpage}, $result));
} # }}}
1
This is what I was using for listpreprocessors-inline.tmpl :
<div class="listpreprocessorsinline">
<div class="inlineheader">
<span class="header">
<a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a>
</span>
</div><!--.inlineheader-->
<div class="inlinecontent">
<TMPL_VAR CONTENT>
</div><!--.inlinecontent-->
</div><!--.listpreprocessorsinline-->
This is what I was using for listpreprocessors-listonly.tmpl :
<p class="listpreprocessors"><a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a></p>
This is what I was using for preprocessor-description.tmpl :
The <TMPL_VAR plugin> preprocessor command currently has no description.
Maybe you should edit this page to add one.
|