[pmwiki-users] When to generate final tags?

Joachim Durchholz jo at durchholz.org
Wed Jun 29 10:24:07 CDT 2005


Patrick R. Michaud wrote:

> On Tue, Jun 28, 2005 at 09:33:57AM +0200, Joachim Durchholz wrote:
> 
>>Similarly, if somebody starts a (:table:) within an (:input start:) - 
>>(:input end:) pair, the table must be finished off before (:input end:), 
>>whether the wiki author has specified a (:tableend:) or not.
>>
>>What's the proper way to do this?
> 
> At the moment there isn't one -- nested blocks are a bit of a pain.
> I've been thinking of generalizing the Block() call to be able to
> handle arbitrary nested block structures, but doing so would
> change a number of exposed PmWiki internals and could break a
> number of recipes.  So I've been thinking that would need to wait
> for 2.1. 

I understand.

I've given nested blocks a bit of thought, and have come with a general 
strategy. I don't know what your thoughs have been, so I don't know 
whether it's any improvement, but here goes anyway:


Parsing nested stuff via regular expressions directly is impossible. But 
you can use a repetitive process that matches non-greedily, replaces the 
so-found innermost block (we already have Keep() in place which can do 
that), and repeats the process until done.

Add a new variant of Markup, NestableMarkup. Instead of a pattern for 
the entire markup, it gives two: one for markup start and one for markup 
end. (It would probably also need two $rep parameters.)

NestableMarkup does just the standard thing, but it also extends the 
$BeginNest and $EndNest arrays.

After all of the recipes have installed their markup, PmWiki installs 
this one:
   Markup(
     'nesting',
     '<split',
     '/(' . implode ('|', $BeginNest) . ')(.?*)'
       . '(' . implode ('|', $EndNest) . ')/em',
     'Keep(\'$0\', \'nest\')');

This markup must be repeatedly applied until it doesn't find anything 
anymore.

Then another markup that re-expands all strings saved with a 'nest' tag, 
and wraps them like this:
   (:nest N:)$kept_string(:unnest N:)
where N is a serial number that identifies each nest-unnest pair (might 
be useful for scripts that try to find the (:unnest:) for a (:nest:), or 
vice versa).

What I currently don't know how to handle well are nestable structures 
like (:if:) (:else:) (:ifend:) - the (:else:) doesn't have a good place 
in this scheme: it would be desirable to annotate it with, say, (:innest 
N:), but that would require some inventive parameter passing for 
NestableMarkup and some regex hackery in the Markup() call above (all 
probably doable but nontrivial).

(:nest N:) would do $NestingId = N (note that N need not be numeric). It 
would also set $NestedRule['N'] to the $name of the nestable markup 
(some markup might want to scan the $NestedRule for some given markups).

(:unnest N:) would call the functions installed in 
$UnnestFunctions['N']. It would also drop the last element in the 
$NestedRule and $UnnestFunctiosn arrays (this makes them into stacks 
that get pushed and popped according to the nesting we're in).

Markups can then install "unnest handlers" in 
$UnnestFunctions[$NestingId] - which is the whole point of the exercise.


Regards,
Jo



More information about the pmwiki-users mailing list