Dokuwiki - Syntax Plugin

1 - About

The syntax plugin captures a content between two nodes.

This start and end nodes are defined with the help of a regular expression. See:

The content between this two nodes will be processed by other plugin if :

3 - State

State are just steps in the parsing process that returns information according to regular expressions.

To define the plugin content (ie the node in the parse tree), you define a pattern expression within this tow state:

  • DOKU_LEXER_ENTER (The opening node)
  • DOKU_LEXER_EXIT (The closing node)

Then you can retrieve text below this two nodes with the state: DOKU_LEXER_MATCHED

For every text that was not match by any other plugin, you retrieve the text in the DOKU_LEXER_UNMATCHED state.

The plugin type configures if any other plugin must be applied on the content.

3.1 - DOKU_LEXER_ENTER

You enter in this state when the entry pattern matches the document.

The entry pattern is set by addEntryPattern() in the function connectTo.

The patterns defines the first tag node of the tree and the beginning of the content

3.2 - DOKU_LEXER_EXIT

A pattern set by addExitPattern() in the postConnect function that defines the end of content

3.3 - DOKU_LEXER_UNMATCHED

A state that returns all text that was not matched by other plugins between the enter tag and the end tag. You generally output it with this code

$renderer->doc .= $renderer->_xmlEntities($match);

You can have several call to the unmatched text because the parser engine create block of text separated by end of line.

3.4 - DOKU_LEXER_MATCHED

It's used when you want to extract information between the enter and the end tag.

This is used to format complex structure such as table, list,…

The matched content will then not be parsed by an other plugin.

4 - Example

4.1 - Wiki Page

The raw data of the dokuwiki page:

<tag>
**will be bold and then processed** 
This text will appear in the 'not matched' state.
<subtag>This text will be in the </subtag>
<subsubtag>A subsub
tag</subsubtag>
</tag>
 
The below links call the page itself with the purge option in order to suppress any cache effect.
[[test?purge=true|Test with purge]]

4.2 - Output

DOKU_LEXER_ENTER: <tag>

will be bold and then processed


DOKU_LEXER_UNMATCHED: This text will appear in the 'not matched' state.
DOKU_LEXER_MATCHED: <subtag>This text must be in the matched tag</subtag>
DOKU_LEXER_UNMATCHED: <subsubtag>A subsub
DOKU_LEXER_UNMATCHED: tag</subsubtag>
DOKU_LEXER_EXIT: </tag> 

4.3 - Code

This is a syntax php file. It must be in the syntax directory located in DOKU_PLUGIN/tag/syntax/example.php

Example is the name of the component and is at the end of the class name

<?php
/**
 * Plugin Tag: Show how a syntax plugin workd
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Nicolas GERARD
 */
 
// must be run within Dokuwiki
if (!defined('DOKU_INC')) die();
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 *
 * class name = syntax_plugin_pluginDir_pluginComponent
 */
class syntax_plugin_tag_example extends DokuWiki_Syntax_Plugin
{
 
    protected $plugin_name = 'tag';
 
    /*
     * What is the type of this plugin ?
     * This a plugin categorization
     * This is only important for other plugin
     * See @getAllowedTypes
     */
    public function getType()
    {
        return 'container';
    }
 
    // This function tells the parser to apply or not
    // the content between the start and end tag
    // to the below type plugin
    public function getAllowedTypes()
    {
        return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
    }
 
    // Sort order in which the plugin are applied
    public function getSort()
    {
        return 158;
    }
 
    // This where the addEntryPattern must bed defined
    public function connectTo($mode)
    {
        // The third parameter is a call back
        // It must correspond to the class name without syntax_
        // Ie plugin_tag_example
        $this->Lexer->addEntryPattern('<tag.*?>(?=.*?</tag>)', $mode, 'plugin_'.$plugin_name.'_'.$this->getPluginComponent());
    }
 
    // This where the addPattern and addExitPattern are defined
    public function postConnect()
    {
        $this->Lexer->addPattern('<subtag.*>.*</subtag>','plugin_'.$plugin_name.'_'.$this->getPluginComponent());
        $this->Lexer->addExitPattern('</tag>', 'plugin_'.$plugin_name.'_'.$this->getPluginComponent());
    }
 
 
    /**
     * Handle the match
     * You get the match for each pattern in the $match variable
     * $state says if it's an entry, exit or match pattern
     *
     * This is an instruction block and is cached apart from the rendering output
     * There is two caches levels
     * https://www.dokuwiki.org/devel:caching
     * This cache may be suppressed with the url parameters ?purge=true
     */
    public function handle($match, $state, $pos, Doku_Handler $handler)
    {
        // We return the $match data for the $state pattern
        // You can do whatever you want here on the data
        // It's an other level cache that creates instructions.
        return array($state, $match);
    }
 
    /**
     * Create output
     * The rendering process
     */
    public function render($mode, Doku_Renderer $renderer, $data)
    {
        // The $data variable comes from the handle() function
        //
        // $mode = 'xhtml' means that we output html
        // There is other mode such as metadata where you can output data for the headers (Not 100% sure)
        if ($mode == 'xhtml') {
 
            list($state, $match) = $data;
 
            switch ($state) {
 
                case DOKU_LEXER_ENTER :
                    $stateDesc = 'DOKU_LEXER_ENTER';
                    break;
                case DOKU_LEXER_MATCHED :
                    $stateDesc = 'DOKU_LEXER_MATCHED';
                    break;
                case DOKU_LEXER_UNMATCHED :
                    $stateDesc = 'DOKU_LEXER_UNMATCHED';
                    break;
                case DOKU_LEXER_EXIT :
                    $stateDesc = 'DOKU_LEXER_EXIT';
                    break;
                case DOKU_LEXER_SPECIAL :
                    $stateDesc = 'DOKU_LEXER_SPECIAL';
                    break;
            }
            // render->_xmlEntities because we want to see the character <> of the tag <tag>
            $renderer->doc .= "<BR>".$stateDesc.": ".$renderer->_xmlEntities($match);
            return true;
        }
        return false;
    }
 
}
dokuwiki/syntax.txt · Last modified: 2015/09/20 17:56 by gerardnico