Major patch rewrite
[ikiwiki.git] / doc / todo / Add_a_plugin_to_list_available_pre-processor_commands.mdwn
1 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]]
2
3 > Good idea, I do see a few problems:
4
5 > - preprocessor directives do not necessarily have the same name as the
6 >   plugin that contains them (for example, the graphviz plugin adds a graph
7 >   directive). Won't keys `%{IkiWiki::hooks{preprocess}}` work?
8
9 >>> Er, yeah - that's a much better solution. :) -- and done
10
11 > - "listplugins" is a bit misnamed since it only does preprocessor directives.
12
13 >>> Yes.  Initially this was going to list all enabled plugins.  Then when searching
14 >>> for enabled plugins I changed my mind and decided that a list of pre-processor
15 >>> directives was more useful.  I'll fix that too. -- changed to `listpreprocessors`
16
17 > - comment was copied from version plugin and still mentions version :-)
18
19 >>> :-) -- fixed
20
21 > - Seems like [[ikiwiki/formatting]] could benefit from including the
22 >   list.. however, just a list of preprocessor directive names is not
23 >   the most user-friendly thing that could be put on that page. It would
24 >   be nice if there were also a short description and maybe an example of
25 >   use. Seems like the place to include that info would be in the call
26 >   to `hook()`.
27 >   (Maybe adding that is more involved than you want to go though..)
28
29 > --[[Joey]]
30
31 >> Adding a whole new hook for a usage example is more effort than I
32 >> wanted to go to.  I was thinking of either:
33 >>
34 >>    - Adding a configuration for a wiki directory.  If a matching page is in the
35 >>      specified wiki directory then the plugin name gets turned into a link to that
36 >>      page
37 >>    - Adding configuration for an external URL.  Each plugin name is added as
38 >>       a link to the plugin name appended to the URL.
39
40 >>The first option is easier to navigate and wouldn't produce broken links,
41 >>but requires all the plugin documentation to be local.  The second option
42 >>can link back to the main IkiWiki site, but if you have any non-standard
43 >>plugins then you'll get broken links.
44 >>
45 >>Hrm.  After listing all of that, maybe your idea with the hooks is the better
46 >>solution.  I'll think about it some more. -- [[Will]]
47
48 >>> I started implementing the hook based solution, and decided I didn't like
49 >>> it because there was no nice way to rebuild pages when the preprocessor
50 >>> descriptions changed.  So instead I assumed that the the [[plugins]] pages
51 >>> would be moved into the underlay directory.  This plugin then uses an
52 >>> `inline` directive to include those pages.  You can use the `inline`
53 >>> parameter to decide if you want to include all the descriptions or
54 >>> just the titles.  There is also an option to auto-create default/blank
55 >>> description pages if they are missing (from a template).  As preprocessor
56 >>> commands don't list unless they have a description page, auto-creation
57 >>> is enabled by default.
58 >>>
59 >>>  There are three new templates that are needed.  These are for:
60 >>>
61 >>>  - The auto-created description pages are generated from `preprocessor-description.tmpl`.
62 >>>  - When only pre-processor names are listed, the `listpreprocessors-listonly.tmpl` template is used.
63 >>>  - When pre-processor descriptions are included inline, the `listpreprocessors-inline.tmpl` template is used.
64 >>>
65 >>> -- [[Will]]
66
67 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:
68
69     #!/usr/bin/perl
70     # Ikiwiki listpreprocessors plugin.
71     package IkiWiki::Plugin::listpreprocessors;
72     
73     use warnings;
74     use strict;
75     use IkiWiki 2.00;
76     
77     sub import { #{{{
78         hook(type => "getsetup", id => "listpreprocessors", call => \&getsetup);
79         hook(type => "preprocess", id => "listpreprocessors", call => \&preprocess);
80         hook(type => "refresh", id => "listpreprocessors", call => \&refresh);
81     } # }}}
82     
83     sub getsetup () { #{{{
84         return
85                 plugin => {
86                         safe => 1,
87                         rebuild => undef,
88                 },
89                 preprocessor_description_dir => {
90                         type => "string",
91                         description => "The ikiwiki directory that contains plugin descriptions.",
92                         safe => 1,
93                         rebuild => 1,
94                 },
95                 preprocessor_description_autocreate => {
96                         type => "boolean",
97                         description => "Should pre-processor command descriptions be automatically created from a template.",
98                         safe => 1,
99                         rebuild => 1,
100                 },
101     } #}}}
102     
103     sub gendescription ($$) { #{{{
104         my $plugin=shift;
105         my $page=shift;
106         my $file=$page.".".$config{default_pageext};
107         my $template=template("preprocessor-description.tmpl");
108         $template->param(page => $page, plugin => $plugin);
109         writefile($file, $config{srcdir}, $template->output);
110         if ($config{rcs}) {
111                 IkiWiki::rcs_add($file);
112         }
113     } #}}}
114     
115     sub refresh () { #{{{
116     
117         if (defined $config{preprocessor_description_autocreate} && ! $config{preprocessor_description_autocreate}) {
118                 return; # create pages unless they explicitly ask us not to
119         }
120     
121         if (!defined $config{preprocessor_description_dir}) {
122                 $config{preprocessor_description_dir} = "ikiwiki/plugin/";
123         }
124         
125         my @pluginlist = sort( keys %{ $IkiWiki::hooks{preprocess} } );
126         my %pluginpages;
127     
128         if (@pluginlist) {
129                 my ($plugin,$page);
130                 
131                 foreach $plugin (@pluginlist) {
132                         $pluginpages{$plugin} = $config{preprocessor_description_dir} . $plugin;
133                 }
134     
135                 if ($config{rcs}) {
136                         IkiWiki::disable_commit_hook();
137                 }
138                 
139                 while (($plugin,$page) = each %pluginpages) {
140                         gendescription($plugin,$page);
141                 }
142                 
143                 if ($config{rcs}) {
144                         IkiWiki::rcs_commit_staged(
145                                 gettext("automatic pre-processor description generation"),
146                                 undef, undef);
147                         IkiWiki::enable_commit_hook();
148                 }
149         }
150     } #}}}
151     
152     sub preprocess (@) { #{{{
153         my %params=@_;
154         
155         if (!defined $config{plugin_description_dir}) {
156                 $config{plugin_description_dir} = "ikiwiki/plugin/";
157         }
158         
159         my @pluginlist = sort( keys %{ $IkiWiki::hooks{preprocess} } );
160         foreach my $plugin (@pluginlist) {
161                 $plugin = $config{plugin_description_dir} . $plugin;
162         }
163         my $pluginString = join (' or ', @pluginlist);
164         
165         my $result = "[[!inline pages=\"$pluginString\" feeds=\"no\" show=0 sort=\"title\"";
166         
167         if (defined $params{inline}) {
168                 $result .= ' template=\"listpreprocessors-listonly\" archive="yes"';
169         } else {
170                 $result .= ' template=\"listpreprocessors-inline\" archive="no"';
171         }
172         
173         $result .= "]]";
174         
175         return IkiWiki::preprocess($params{page}, $params{destpage}, 
176                 IkiWiki::filter($params{page}, $params{destpage}, $result));
177     } # }}}
178     
179     1
180
181 --------
182
183 This is what I was using for `listpreprocessors-inline.tmpl`:
184
185     <div class="listpreprocessorsinline">
186     
187     <div class="inlineheader">
188     
189     <span class="header">
190     <a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a>
191     </span>
192     
193     </div><!--.inlineheader-->
194     
195     <div class="inlinecontent">
196     <TMPL_VAR CONTENT>
197     </div><!--.inlinecontent-->
198     
199     </div><!--.listpreprocessorsinline-->
200
201 --------
202
203 This is what I was using for `listpreprocessors-listonly.tmpl`:
204
205     <p class="listpreprocessors"><a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a></p>
206
207 --------
208
209 This is what I was using for `preprocessor-description.tmpl`:
210
211     The <TMPL_VAR plugin> preprocessor command currently has no description.
212     
213     Maybe you should edit this page to add one.