134 lines
6.1 KiB
Markdown
134 lines
6.1 KiB
Markdown
[[!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-package 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.
|