aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchrysn <chrysn@fsfe.org>2013-08-09 01:14:44 +0200
committerchrysn <chrysn@fsfe.org>2013-08-09 01:18:38 +0200
commitbcfb05123c55f9859ea60b18657bdfdd89678e21 (patch)
treed4c74d1d07e301b961968a94fe9c1ff4554c6478
parent415fecfcb7e51ce316c803f97df5d2362b5e8954 (diff)
downloadikiwiki-bcfb05123c55f9859ea60b18657bdfdd89678e21.tar
ikiwiki-bcfb05123c55f9859ea60b18657bdfdd89678e21.tar.gz
suggested plugin: blocks (free relationships)
-rw-r--r--doc/todo/flexible_relationships_between_pages.mdwn84
-rw-r--r--doc/todo/flexible_relationships_between_pages/blocks.pm.mdwn129
-rw-r--r--doc/users/chrysn/interests.mdwn1
3 files changed, 214 insertions, 0 deletions
diff --git a/doc/todo/flexible_relationships_between_pages.mdwn b/doc/todo/flexible_relationships_between_pages.mdwn
new file mode 100644
index 000000000..ee3dd8d3a
--- /dev/null
+++ b/doc/todo/flexible_relationships_between_pages.mdwn
@@ -0,0 +1,84 @@
+it has been some years since the [[matching different kinds of links]] issue
+was tackled, but hardly a plugin is using it.
+
+in order to enhance on the [[todo/rel attribute for links]] and [[todo/better bug tracking support]]
+issues and to provide a more general infrastructure, i'd like to propose a
+generic plugin for typed links. following the use case i've developed it for,
+i'll call it `blocks` for the moment (but am open to better suggestions).
+
+outline
+=======
+
+the plugin has a **configuration option** called `blocks_names`, which consists
+of pairs of verbs; the typical example is `blocks/blockedby`, but other values
+could be `next/prev up/down` or `owner/owns`.
+
+for each verb in the options, there is a **directive** which is used to state
+the relationship; relationships can be declared on both ends, so a page `bugA`
+with the contents `\[[!blocks bugB]]` is semantically equivalent to a page
+`bugB` with the contents `\[[!blockedby bugA]]`.
+
+for each verb, there is also a **pagespec** which matches all pages that are
+the origin of a relationship to a given page. if `developerA` `\[[!owns
+bug1]]`, then if `bug1` contains `\[[!map pages="owns(.)"]]`, it will show the
+owning developer. these specs match both ways, ie. if `bug1` `\[[!owner
+developerA]]`, the said map directive will still produce the same result.
+
+details
+=======
+
+* single word relationships vs. symmetric relationships
+
+ with some verbs, it is possible that a relationship is only used in one
+ direction (eg `index`, even though one could declare it as
+ `index/isindexof`).
+
+ other verbs are symmetric, eg. `equivalent`, which need different treatment.
+
+* "taglink" style directives
+
+ the [[plugins/tag]] plugin would be a special case for this plugin (apart
+ from the autotag and tagdir features). as there is a `\[[!taglink ...]]`
+ directive, there could be an analogous directive for every single directive.
+
+* implementation notes
+
+ the way pagespec hooks are implemented required some nasty perl tricks, for
+ which the people who showed me felt very bad for having spoilt me. indeed,
+ `no strict refs;` and `*$forward_name = $forward_match;` are not exactly
+ ideal. a change in the pagespec declaration api (why not just `hook` like
+ everything else) would make the implementation cleaner.
+
+* configuration location
+
+ i aimed for static configuration of the `block_names` in the setup file. this
+ could be made more general like in the [[plugins/shortcut]] plugin, but that
+ would make things more complex.
+
+* no html links with `rel=` yet
+
+ as there are no taglink style links between the articles so far, no htmllink
+ gets rendered that could carry the relationship name in its rel field.
+
+ having the inverse relationship description in backlinks (as in the link
+ created by the map directive in the example above) would be hard to
+ implement. (actually, i think it'd be easier to determine the rel values from
+ the taggedlinks for *every* htmllink than to influence the backlinks in this
+ plugin).
+
+* one direction also creates a normal link
+
+ due to the way add\_link treats relationships, the forward relationship is
+ always going to be reflected in the links/backlinks. a section of
+ [[todo/matching different kinds of links]] was dismissed with "let's not
+ worry about it", this plugin might be reason to worry about it again. (i'd
+ consider what is in @links to be a representation of which hyperlinks are
+ there, and in this case, none are generated).
+
+implementation
+==============
+
+there is a working but slightly incomplete (basically where it comes to the
+details mentioned above) implementation in [[blocks.pm]].
+
+--chrysn
diff --git a/doc/todo/flexible_relationships_between_pages/blocks.pm.mdwn b/doc/todo/flexible_relationships_between_pages/blocks.pm.mdwn
new file mode 100644
index 000000000..0ef97b2c1
--- /dev/null
+++ b/doc/todo/flexible_relationships_between_pages/blocks.pm.mdwn
@@ -0,0 +1,129 @@
+#!/usr/bin/perl
+# Ikiwiki "blocks" relationship plugin.
+package IkiWiki::Plugin::blocks;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getsetup", id => "blocks", call => \&getsetup);
+ hook(type => "checkconfig", id => "skeleton", call => \&checkconfig);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ blocks_names => {
+ type => "string",
+ example => "blocks/blockedby",
+ description => "comma separated list of defined relationship pairs, the forward and backward name separated by a slash",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig () {
+ my $blocksnames;
+ if (defined $config{blocks_names}) {
+ $blocksnames = $config{blocks_names};
+ } else {
+ $blocksnames = "blocks/blockedby";
+ }
+
+ while ( $blocksnames =~ /([^ ]+)/g )
+ {
+ if ( $1 =~ m@([a-zA-Z0-9]+)(/([a-zA-Z0-9]+))?@ )
+ {
+ my $from = $1;
+ my $to = $3;
+ hook(
+ type => "preprocess",
+ shortcut => 1, # gets interpreted by listdirectives; see doc/bugs/cannot_preview_shortcuts.mdwn / ikiwiki commit 354d22e2
+ no_override => 1,
+ id => $from,
+ scan => 1,
+ call => sub { preprocess_blocks($from, 1, @_); }
+ );
+ if ($to)
+ {
+ hook(
+ type => "preprocess",
+ shortcut => 1,
+ no_override => 1,
+ id => $to,
+ scan => 1,
+ call => sub { preprocess_blocks($from, 0, @_); }
+ );
+ }
+
+ my $backward_match; my $backward_name;
+ my $forward_match; my $forward_name;
+
+ $backward_match = sub ($$;@) {
+ my $page=shift;
+ my $glob=shift;
+ return IkiWiki::PageSpec::match_backlink($page, $glob, linktype => $from, @_);
+ };
+
+ $backward_name = "IkiWiki::PageSpec::match_$from";
+
+ if ($to)
+ {
+ $forward_match = sub ($$;@) {
+ my $page=shift;
+ my $glob=shift;
+ return IkiWiki::PageSpec::match_link($page, $glob, linktype => $from, @_);
+ };
+
+ $forward_name = "IkiWiki::PageSpec::match_$to";
+ }
+
+ {
+ no strict 'refs';
+
+ if ($to)
+ {
+ *$forward_name = $forward_match;
+ }
+ *$backward_name = $backward_match;
+ }
+ } else {
+ error gettext("Malformed option in blocks_names");
+ }
+ }
+}
+
+sub preprocess_blocks ($$@) {
+ # with flip=0, the directive occurring on page A pointing at page B
+ # means that A $relation B, with flip=1, it means B $relation A
+ my $relation = shift;
+ my $flip = shift;
+
+ if (! @_) {
+ return "";
+ }
+ my %params=@_;
+ my $page = $params{page};
+ delete $params{page};
+ delete $params{destpage};
+ delete $params{preview};
+
+ foreach my $blocks (keys %params) {
+ $blocks=linkpage($blocks);
+
+ # hidden WikiLink
+ if ( $flip == 0 ) {
+ add_link($page, $blocks, $relation);
+ } else {
+ add_link($blocks, $page, $relation);
+ }
+ }
+
+ return "";
+}
+
+1
diff --git a/doc/users/chrysn/interests.mdwn b/doc/users/chrysn/interests.mdwn
index a70089a45..a5c8f33bf 100644
--- a/doc/users/chrysn/interests.mdwn
+++ b/doc/users/chrysn/interests.mdwn
@@ -14,6 +14,7 @@ these are the topics [[chrysn]] is or was interested in inside ikiwiki:
* [[todo/Better bug tracking support]]
* [[todo/calendar with "create" links]]
* [[todo/credentials page]]
+* [[todo/flexible relationships between pages]]
* [[todo/inline postform autotitles]]
* [[todo/internal definition list support]]
* [[todo/mirrorlist with per-mirror usedirs settings]]