believed to be fixed already
[ikiwiki] / doc / bugs / conditional_preprocess_during_scan.mdwn
1 [[!template id=gitbranch branch=GiuseppeBilotta/scanif author="[[GiuseppeBilotta]]"]]
2
3 When a directive that should be run during scan preprocessing is inside
4 an if directive, it doesn't get called because the if preprocessing does
5 not run during scan.
6
7 I've written a simple [[patch]] to fix the issue, currently hosted on the
8 scanif branch of my repository. The patch also passes the preview option
9 back to the Ikiwiki::preprocess call, making sure that whatever is being
10 reprocessed is done so in the same conditions as the original call.
11
12 > One problem with this is that it has the same dependency-ordering problems
13 > as inline-based or pagespec-based trails with my [[plugins/contrib/trail]]
14 > plugin: `if` takes a pagespec, but pagespecs aren't guaranteed to match
15 > correctly until everything has been scanned (for instance, `link()` might
16 > give the wrong results because a page that added or deleted a link hasn't
17 > been scanned yet). If you have a clever idea for how to fix this, I'd love
18 > to hear it - being able to specify a [[plugins/contrib/trail]] in terms
19 > of a sorted pagespec would be useful. --[[smcv]]
20
21 >> I have a solution to the dependency-ordering problem in a different
22 >> branch of my repository, with a post_scan hook mechanism which I use to
23 >> be able to sort outer inline pages according to the last modification
24 >> date of their nested inline pages. The way I implemented it currently,
25 >> though, doesn't use the existing hooks mechanism of ikiwiki (because
26 >> it's something which I believe to be more efficiently done the way I
27 >> implemented it) so I don't know how likely it is to be included
28 >> upstream.
29
30 >> For what it's worth, I think that my post_scan hook mechanism would work
31 >> rather fine with your trail plugin.
32
33 >>> We discussed this on IRC, and I think it's actually more complicated
34 >>> than that: the branch to sort by newest inlined entry wants a
35 >>> "pagespecs now work" hook, whereas for trail I want a "sorting now
36 >>> works" hook:
37 >>>
38 >>> * scan
39 >>> * pagespecs now work (post-scan)
40 >>>   * Giuseppe's version of inline can decide what each inline
41 >>>     contains, and thus decide where they go in `inline(mtime)`
42 >>>     order
43 >>> * pagespecs and sorting now work (pre-render)
44 >>>   * my trail plugin can decide what each trail contains, and
45 >>>     also sort them in the right order (which might be
46 >>>     `inline(mtime)`, so might be undefined until pagespecs work)
47 >>> * render
48 >>>
49 >>> --[[smcv]]
50
51 >> However, the case of the if
52 >> directive is considerably more complicated, because the conditional
53 >> can introduce a much stronger feedback effect in the pre/post scanning
54 >> dependency. In fact, it's probably possible to build a couple of pages
55 >> with vicious conditional dependency circles that would break/unbreak
56 >> depending on which pass we are in. And I believe this is an intrinsic
57 >> limitation of the system, which cannot be solved at all.
58
59 >>> One way forward that I can think of for this issue is to
60 >>> have a way to tell `\[[!if]]` which answer it should assume for
61 >>> scanning purposes, so it would assume that answer when running
62 >>> in the scan phase, and really evaluate the pagespec when running
63 >>> in the render phase. For instance:
64 >>>
65 >>>     \[[!if test="enabled(foo)" scan_assume=yes then="""
66 >>>     \[[!foo]]
67 >>>     """]]
68 >>>
69 >>> could maybe scan \[[!foo]] unconditionally.
70 >>>
71 >>> This makes me wonder whether `\[[!if]]` was too general: by having
72 >>> the full generality of pagespecs, it reduces its possible uses to
73 >>> "those contexts where pagespecs work".
74 >>>
75 >>> Another possibility might be to have "complex" pagespecs and sort
76 >>> orders (those whose correct answer requires scanning to have completed,
77 >>> like `link()` and sorting by `meta(title)`) throw an error when used in
78 >>> the scan phase, but simple pagespecs like `enabled()` and `glob()`, and
79 >>> simple sort orders like `title` and `path`, could continue to work?
80 >>> My `wip-too-soon` work-in-progress branch is heading in this direction,
81 >>> although it currently makes `pagespec_match` fail completely and does
82 >>> not even allow "simple" pagespecs and sort orders.
83 >>>
84 >>> At the moment, if a pagespec cannot be evaluated, `\[[!if]]` will
85 >>> produce neither the `then` clause nor the `else` clause. This could
86 >>> get pretty confusing if it is run during the scan phase and produces
87 >>> an error, then run during the render phase and succeeds: if you had,
88 >>> say,
89 >>>
90 >>>     \[[!if run_during_scan=1 test="link(foo)" then="""
91 >>>     there is a link to foo
92 >>>     \[[!tag there_is_a_link_to_foo]]
93 >>>     """ else="""
94 >>>     there is no link to foo
95 >>>     \[[!tag there_is_no_link_to_foo]]
96 >>>     """]]
97 >>>
98 >>> then the resulting page would contain one of the snippets of text,
99 >>> but its metadata would contain neither of the tags. Perhaps the plugin
100 >>> would have to remember that it failed during the scan phase, so that
101 >>> it could warn about the failure during the render phase instead of,
102 >>> or in addition to, producing its normal output?
103 >>>
104 >>> Of the conditional-specific tests, `included()` and `destpage(glob)`
105 >>> can never match during scan.
106 >>>
107 >>> Does anyone actually use `\[[!if]]` in ways that they would want to
108 >>> be active during scan, other than an `enabled(foo)` test?
109 >>> I'm increasingly tempted to add `\[[!ifenabled foo]]` to solve
110 >>> that single case, and call that a solution to this bug...
111 >>>
112 >>> --[[smcv]]