comments
[ikiwiki.git] / doc / todo / allow_plugins_to_add_sorting_methods.mdwn
index 1533b6c44c6a9110b172dfd90c4a5041138571fd..67d85f6f84a7722a52975f63596cf2e33f08f7ba 100644 (file)
@@ -20,14 +20,61 @@ 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>
 
-## Documentation extracted from the branch
+(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>
+
+>>>> I agree it seems more elegant, so I have focused on it.
+>>>>
+>>>> I don't know about reusing `IkiWiki::PageSpec` for this.
+>>>>
+>>>> I would be inclined to drop the `check_` stuff.
+>>>>
+>>>> Wouldn't it make sense to have `meta(title)` instead
+>>>> of `meta_title`?
+>>>>
+>>>> As I read the regexp in `cmpspec_translate`, the "command"
+>>>> is required to have params. They should be optional, 
+>>>> to match the documentation and because most sort methods
+>>>> do not need parameters.
+>>>> --[[Joey]]
+
+## 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 as arguments, and
+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.
 
@@ -37,12 +84,35 @@ For instance, the built-in `title` sort order could be reimplemented as
                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.
 
+  > I feel it sould be clearer to call that "sortas", since "sort=" is used
+  > to specify a sort method in other directives. --[[Joey]]
+
+### 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
@@ -51,3 +121,31 @@ An optional `sort` parameter will be used preferentially when
        \[[!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.