[[!template id=gitbranch branch=smcv/sort-hooks author="[[Simon_McVittie|smcv]]"]]
[[!tag patch]]
The available [[ikiwiki/pagespec/sorting]] methods are currently hard-coded in
IkiWiki.pm, making it difficult to add any extra sorting mechanisms. I've
prepared a branch which adds 'sort' as a hook type and uses it to implement a
new meta_title
sort type.
Someone could use this hook to make \[[!inline sort=title]]
prefer the meta
title over the page name, but for compatibility, I'm not going to (I do wonder
whether it would be worth making sort=name an alias for the current sort=title,
and changing the meaning of sort=title in 4.0, though).
Gitweb:
http://git.pseudorandom.co.uk/smcv/ikiwiki.git?a=shortlog;h=refs/heads/sort-hooks
I briefly tried to turn all the current sort types into hook functions, and
have some of them pre-registered, but decided that probably wasn't a good idea.
That earlier version of the branch is also available for comparison:
http://git.pseudorandom.co.uk/smcv/ikiwiki.git?a=shortlog;h=refs/heads/sort-hooks-excessive
(The older version is untested, and probably doesn't really work as-is - I
misunderstood the details of how the built-in function sort
works when using
$a
and $b
. The newer version has been tested, and has a regression test for
its core functionality.)
This hook isn't (yet) sufficient to implement [[plugins/contrib/report]]'s
NIH'd sorting mechanisms:
-
report
can sort by any [[plugins/contrib/field]], whereas this one has a
finite number of hooks: if the field
plugin's functionality is desirable,
perhaps parameterized sort mechanisms similar to pagespec match functions
would be useful? Then the field
plugin could register
hook(type => "sort", id => "field")
and you could have
\[[!inline ... sort="field(Mood)"]]
or something?
-
report
can sort by multiple criteria, with independent direction-changing:
if this is desirable, perhaps pagespec_match_list
could be enhanced to
interpret sort="x -y z(w)"
as sorting by (pseudocode)
{ $cmp_x->($a, $b) || (-$cmp_y->($a, $b)) || $cmp_z->($a, $b, "w") }
?
I've now added both of these features to the sort-hooks branch. --[[smcv]]
I wonder if IkiWiki would benefit from the concept of a "sortspec", like a [[ikiwiki/PageSpec]] but dedicated to sorting lists of pages rather than defining lists of pages? Rather than defining a sort-hook, define a SortSpec class, and enable people to add their own sort methods as functions defined inside that class, similarly to the way they can add their own pagespec definitions. --[[KathrynAndersen]]
[[!template id=gitbranch branch=smcv/sort-package author="[[Simon_McVittie|smcv]]"]]
I'd be inclined to think that's overkill, but it wasn't very hard to
implement, and in a way is more elegant. I set it up so sort mechanisms
share the IkiWiki::PageSpec
package, but with a cmp_
prefix. Gitweb:
http://git.pseudorandom.co.uk/smcv/ikiwiki.git?a=shortlog;h=refs/heads/sort-package
Documentation from sort-hooks branch
sort hook (added to [[plugins/write]])
hook(type => "sort", id => "foo", call => \&sort_by_foo);
This hook adds an additional [[ikiwiki/pagespec/sorting]] order or overrides
an existing one.
The callback is given two page names followed by the parameter as arguments, and
returns negative, zero or positive if the first page should come before,
close to (i.e. undefined order), or after the second page.
For instance, the built-in title
sort order could be reimplemented as
sub sort_by_title {
pagetitle(basename($_[0])) cmp pagetitle(basename($_[1]));
}
and to sort by an arbitrary meta
value, you could use:
# usage: sort="meta(description)"
sub sort_by_meta {
my $param = $_[2];
error "sort=meta requires a parameter" unless defined $param;
my $left = $pagestate{$_[0]}{meta}{$param};
$left = "" unless defined $left;
my $right = $pagestate{$_[1]}{meta}{$param};
$right = "" unless defined $right;
return $left cmp $right;
}
meta_title sort order (conditionally added to [[ikiwiki/pagespec/sorting]])
meta_title
- Order according to the \[[!meta title="foo" sort="bar"]]
or \[[!meta title="foo"]]
[[ikiwiki/directive]], or the page name if no
full title was set.
Multiple sort orders (added to [[ikiwiki/pagespec/sorting]])
In addition, you can combine several sort orders and/or reverse the order of
sorting, with a string like age -title
(which would sort by age, then by
title in reverse order if two pages have the same age).
meta title sort parameter (added to [[ikiwiki/directive/meta]])
An optional sort
parameter will be used preferentially when
[[ikiwiki/pagespec/sorting]] by meta_title
:
\[[!meta title="The Beatles" sort="Beatles, The"]]
\[[!meta title="David Bowie" sort="Bowie, David"]]
Documentation from sort-hooks branch
The changes to [[ikiwiki/pagespec/sorting]] are the same.
The changes to [[plugins/write]] are replaced by:
Sorting plugins
Similarly, it's possible to write plugins that add new functions as
[[ikiwiki/pagespec/sorting]] methods. To achieve this, add a function to
the IkiWiki::PageSpec package named cmp_foo
, which will be used when sorting
by foo
or foo(...)
is requested.
The function will be passed three or more parameters. The first two are
page names, and the third is undef
if invoked as foo
, or the parameter
"bar"
if invoked as foo(bar)
. It may also be passed additional, named
parameters.
It should return the same thing as Perl's cmp
and <=>
operators: negative
if the first argument is less than the second, positive if the first argument
is greater, or zero if they are considered equal. It may also raise an
error using error
, for instance if it needs a parameter but one isn't
provided.
You can also define a function called check_cmp_foo
in the same package.
If you do, it will be called while preparing to sort by foo
or foo(bar)
,
with argument undef
or "bar"
respectively; it may raise an error using
error
, if sorting like that isn't going to work.