devel:syntax_plugins
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
devel:syntax_plugins [2009-12-21 10:36] – 130.158.152.134 | devel:syntax_plugins [2023-03-04 15:31] (current) – Aleksandr | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Syntax Plugins ====== | + | ====== Syntax Plugins ====== |
- | FIXME(this needs to be refactored) | + | [[plugintype> |
- | + | ||
- | Syntax Plugins are [[: | + | |
===== Synopsis ===== | ===== Synopsis ===== | ||
- | A Syntax Plugin //example// needs to define a class named '' | + | A Syntax Plugin //Example// needs: |
+ | * class name | ||
+ | * which extends | ||
+ | * to be stored in a file '' | ||
+ | Moreover, a [[plugin_info|plugin.info.txt]] file is needed. For full details of plugins and their files and how to create more syntax components | ||
The class needs to implement at least the following functions: | The class needs to implement at least the following functions: | ||
- | * **'' | ||
* **'' | * **'' | ||
* **'' | * **'' | ||
- | * **'' | + | * **'' |
- | * **'' | + | * **'' |
- | * **'' | + | * **'' |
\\ | \\ | ||
Line 22: | Line 23: | ||
* **'' | * **'' | ||
- | * '' | + | * '' |
- | * '' | + | * '' |
- | * '' | + | * '' |
* **'' | * **'' | ||
- | * **'' | + | * **'' |
- | Additional functions can be defined as needed. It is recommended to prepend an underscore to self defined functions to avoid possible nameclashes with future plugin specification enhancements. | + | Additional functions can be defined as needed. |
\\ | \\ | ||
Inherited Properties | Inherited Properties | ||
- | * **'' | + | * **'' |
+ | |||
+ | Inherited Functions | ||
+ | |||
+ | * See [[common plugin functions]] for inherited functions available to all plugins. e.g. localisation, | ||
===== Syntax Types ===== | ===== Syntax Types ===== | ||
Line 39: | Line 44: | ||
DokuWiki uses different syntax types to determine which syntax may be nested. Eg. you can have text formatting inside of tables. To integrate your plugin into this system it needs to specify which type it is and which types can be nested within it. The following types are currently available: | DokuWiki uses different syntax types to determine which syntax may be nested. Eg. you can have text formatting inside of tables. To integrate your plugin into this system it needs to specify which type it is and which types can be nested within it. The following types are currently available: | ||
- | ^ Type | + | ^ Modetype |
- | | container | listblock, table, quote, hr | containers are complex modes that can contain many other modes -- hr breaks the principle but they shouldn' | + | | container |
- | | baseonly | header | some modes are allowed inside the base mode only | | + | | baseonly |
- | | formatting | strong, emphasis, underline, monospace, subscript, superscript, | + | | formatting |
- | | substition((Yes this is spelled wrong, but we won't change it to avoid breaking existing plugins. Sometimes a typo becomes a standard - see the HTTP " | + | | substition((Yes this is spelled wrong, but we won't change it to avoid breaking existing plugins. Sometimes a typo becomes a standard - see the HTTP " |
- | | protected |' | + | | protected |
- | | disabled | unformatted | inside this mode no wiki markup should be applied but lineendings and whitespace isn't preserved | | + | | disabled |
- | | paragraphs | eol | used to mark paragraph boundaries | | + | | paragraphs |
- | For a description what each type means and which other formatting classes are registered in them read the comments in '' | + | For a description what each type means and which other formatting classes are registered in them read the comments in '' |
====== Tutorial: Syntax Plugins Explained ====== | ====== Tutorial: Syntax Plugins Explained ====== | ||
- | The goal of this tutorial is to explain the concepts involved in a [[:DokuWiki]] [[devel: | + | The goal of this tutorial is to explain the concepts involved in a DokuWiki [[devel: |
For those who are really impatient to get started, grab a copy of the [[devel: | For those who are really impatient to get started, grab a copy of the [[devel: | ||
Line 73: | Line 78: | ||
* The '' | * The '' | ||
* add content to the output document with '' | * add content to the output document with '' | ||
+ | * access the return value of handle() using the //$data// parameter of render($mode, | ||
* ensure any content output by the plugin is **safe** - run raw wiki data through an entity conversion function. | * ensure any content output by the plugin is **safe** - run raw wiki data through an entity conversion function. | ||
* do the minimum possible processing and decision making here, it should all have been done in the '' | * do the minimum possible processing and decision making here, it should all have been done in the '' | ||
Line 105: | Line 111: | ||
These are the other modes that can occur nested within the current mode's own markup. | These are the other modes that can occur nested within the current mode's own markup. | ||
- | Each syntax mode has its own array of allowed modes which tells the parser what other syntax modes will be recognised whilst | + | Each syntax mode has its own array of allowed modes which tells the parser what other syntax modes will be recognised whilst |
:!: Your plugin gets in the allowedModes array of other syntax modes through the mode type it reports using the '' | :!: Your plugin gets in the allowedModes array of other syntax modes through the mode type it reports using the '' | ||
- | :!: Your plugin tells the parser which other syntax modes it permits by reporting the mode types it allows via the '' | + | :!: Your plugin tells the parser which other syntax modes it permits by reporting the mode types it allows via the '' |
==== PType ==== | ==== PType ==== | ||
PType governs how the parser handles html %%< | PType governs how the parser handles html %%< | ||
- | Generally, when the parser encounters some markup, there will be a currently open HTML paragraph tag. The parser needs to know if it should close that tag before entering your syntax mode and then open another paragraph when exiting, that is '' | + | Generally, when the parser encounters some markup, there will be a currently open HTML paragraph tag. The parser needs to know if it should close that tag before entering your syntax mode and then open another paragraph when exiting, that is '' |
- | For those that know CSS, returning | + | The PType also decides how and if paragraphs are created **inside** the syntax mode. With '' |
- | < | + | For those that know CSS, returning |
+ | |||
+ | === Example === | ||
+ | |||
+ | Suppose we have a fairly standard syntax plugin with the ENTRY => UNMATCHED => EXIT pattern. Depending on the PType setting, | ||
+ | |||
+ | ^wikisyntax ^PType=normal ^PType=block ^PType=stack ^ | ||
+ | |< | ||
+ | foo | ||
+ | < | ||
+ | |||
+ | bar</ | ||
+ | <p>foo | ||
+ | ENTRY("< | ||
+ | UNMATCHED(" | ||
+ | EXIT("</ | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | ENTRY("< | ||
+ | UNMATCHED(" | ||
+ | EXIT("</ | ||
+ | < | ||
+ | < | ||
+ | ENTRY("< | ||
+ | <p> | ||
+ | UNMATCHED(" | ||
+ | </ | ||
+ | EXIT("</ | ||
+ | < | ||
+ | </ | ||
==== Sort Number ==== | ==== Sort Number ==== | ||
- | This number is used by the lexer((the part of the parser which analyses the raw wiki page)) to control the order it tests the syntax mode patterns against raw wiki data. It is only important if the patterns belonging two or more modes match the same raw data - where the pattern belonging to the mode with the lowest sort number will win out. | + | This number is used by the lexer((the part of the parser which analyses the raw wiki page)) to control the order it tests the syntax mode patterns against raw wiki data. It is only important if the patterns belonging |
You can make use of this behaviour to write a plugin which will replace or extend a native DokuWiki handler for the same syntax. | You can make use of this behaviour to write a plugin which will replace or extend a native DokuWiki handler for the same syntax. | ||
Line 139: | Line 175: | ||
* be very wary of look behind assertions. The parser only attempts to match patterns on the next piece of "not yet matched" | * be very wary of look behind assertions. The parser only attempts to match patterns on the next piece of "not yet matched" | ||
* option flags can only be included as inline options, e.g. '' | * option flags can only be included as inline options, e.g. '' | ||
+ | * back references do not work, e.g. "'' | ||
+ | |||
\\ | \\ | ||
Line 155: | Line 193: | ||
* use non-greedy quantifiers, | * use non-greedy quantifiers, | ||
* be wary of using multiple exit patterns. The first exit pattern encountered will most likely trigger the parser to exit your syntax mode - even if that wasn't the pattern the entry pattern looked ahead for. Needing multiple exit patterns probably indicates a need for multiple plugins. | * be wary of using multiple exit patterns. The first exit pattern encountered will most likely trigger the parser to exit your syntax mode - even if that wasn't the pattern the entry pattern looked ahead for. Needing multiple exit patterns probably indicates a need for multiple plugins. | ||
+ | * In the [[devel: | ||
* early versions of the DokuWiki lexer had a bug which prevented use of "<" | * early versions of the DokuWiki lexer had a bug which prevented use of "<" | ||
+ | * Use this for a example of correct regular expression: [[devel: | ||
==== handle() method ==== | ==== handle() method ==== | ||
This is the part of your plugin which should do all the work. Before DokuWiki renders the wiki page it creates a list of instructions for the renderer. | This is the part of your plugin which should do all the work. Before DokuWiki renders the wiki page it creates a list of instructions for the renderer. | ||
+ | |||
+ | The complete signature is: '' | ||
**$match** parameter --- The text matched by the patterns, or in the case of **'' | **$match** parameter --- The text matched by the patterns, or in the case of **'' | ||
Line 171: | Line 213: | ||
**$pos** parameter --- The character position of the matched text. | **$pos** parameter --- The character position of the matched text. | ||
- | **&$handler** parameter --- Object Reference to the [[devel: | + | **$handler** parameter --- Object Reference to the [[devel: |
+ | |||
+ | **return** --- The instructions for the '' | ||
==== render() method ==== | ==== render() method ==== | ||
- | The part of the plugin that provides the output for the final web page - or whatever other output format is supported. It is here that the plugin adds its output to that already generated by other parts of the renderer - by concatenating its output to the renderer' | + | The part of the plugin that provides the output for the final web page - or whatever other output format is supported. It is here that the plugin adds its output to that already generated by other parts of the renderer - e.g. by concatenating its output to the renderer' |
- | < | + | < |
$renderer-> | $renderer-> | ||
</ | </ | ||
- | :!: Any raw wiki data that passes through '' | + | :!: Any raw wiki data that passes through '' |
- | **$mode** parameter --- Name for the format mode of the final output produced by the renderer. | + | The complete signature is: '' |
- | < | + | |
+ | **$mode** parameter --- Name for the format mode of the final output produced by the renderer. | ||
+ | < | ||
if ($mode == ' | if ($mode == ' | ||
// code to generate XHTML output from instruction $data | // code to generate XHTML output from instruction $data | ||
Line 190: | Line 236: | ||
</ | </ | ||
- | **$data** parameter --- An array containing | + | **$renderer** parameter --- Give access to the object [[xref> |
- | ==== Safety & Security ==== | + | **$data** parameter --- An array containing the instructions previously prepared and returned by the plugin' |
- | Raw wiki page data which reaches | + | ===XHTML renderer === |
+ | When your plugin | ||
+ | <code php> | ||
+ | if ($mode == ' | ||
+ | /** @var Doku_Renderer_xhtml $renderer */ | ||
+ | // code to generate XHTML output from instruction $data | ||
+ | $renderer-> | ||
+ | } | ||
+ | </ | ||
+ | Detail: the variable '' | ||
- | ==== Localization ==== | + | === Metadata renderer |
+ | A special render mode '' | ||
- | FIXME | + | In the metadata rendering mode you extracts metadata from the page. This is particularly important if you manually handle certain kinds of links. If you don't register these, they will not show up as backlinks on the pages that they refer to. Here is an example of how to register these backlinks: |
- | For now refer to [[devel: | + | <code php> |
+ | public function render($mode, | ||
+ | if($mode == ' | ||
+ | /** @var Doku_Renderer_xhtml $renderer */ | ||
+ | // this is where you put all the rendering that will be displayed in the | ||
+ | // web browser | ||
+ | return true; | ||
+ | } | ||
+ | if($mode == ' | ||
+ | /** @var Doku_Renderer_metadata $renderer */ | ||
+ | $renderer-> | ||
+ | // I am assuming that when processing in handle(), you have stored | ||
+ | // the link destination in $data[0] | ||
+ | return true; | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | </ | ||
+ | This example uses the [[xref> | ||
+ | <code php> | ||
+ | public function render($mode, | ||
+ | if ($data === false) return false; | ||
- | ==== Configuration ==== | + | // XHTML output |
- | Please refer to [[configuration]]. | + | if ($mode |
+ | /** @var Doku_Renderer_xhtml $renderer */ | ||
+ | ... | ||
+ | |||
+ | // for metadata renderer | ||
+ | } elseif ($mode | ||
+ | /** @var Doku_Renderer_metadata $renderer */ | ||
+ | // erase tags on persistent metadata no more used | ||
+ | if (isset($renderer-> | ||
+ | unset($renderer-> | ||
+ | $renderer-> | ||
+ | } | ||
+ | |||
+ | // merge with previous tags and make the values unique | ||
+ | if (!isset($renderer-> | ||
+ | $renderer-> | ||
+ | |||
+ | // create raw text summary for the page abstract | ||
+ | if ($renderer-> | ||
+ | ... | ||
+ | return true; | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | </ | ||
+ | First it handles old persistent metadata no longer used by this plugin. This persistent metadata is always kept, thus when you change your mind and use current metadata instead, you need to remove it explicitly. | ||
- | ==== Using Styles and JavaScript ==== | + | When handling persistent data in the metadata renderer, take care you update also the current metadata, when you update persistent metadata. |
- | FIXME | + | The tag plugin stores here ' |
- | For now refer to [[devel: | + | When some raw text from your syntax should be included in the abstract you can append it to '' |
+ | |||
+ | The xhtml mode is called when DokuWiki is in need of a new xhtml version of the wikipage. The metadata is a bit different. In general, the metadata of the page is rendered on demand when '' | ||
+ | |||
+ | When someone edit a page and use the preview function, the metadata renderer is not called. So the metadata is not yet updated! This is done when the page is saved. | ||
+ | |||
+ | ===== Safety & Security ===== | ||
+ | |||
+ | Raw wiki page data which reaches your plugin has not been processed at all. No further processing is done on the output after it leaves your plugin. At an absolute minimum the plugin should ensure any raw data output has all HTML special characters converted to HTML entities. Also any wiki data extracted and used internally should be treated with suspicion. See also [[devel:security]]. | ||
+ | |||
+ | ===== Common | ||
+ | Some function are shared between the plugins, refer to next sections for info: | ||
+ | * [[devel: | ||
+ | * [[devel: | ||
+ | * [[devel: | ||
Line 217: | Line 333: | ||
To make it easy on the users of wikis which install your plugin, you should add a button for its syntax to the editor toolbar. | To make it easy on the users of wikis which install your plugin, you should add a button for its syntax to the editor toolbar. | ||
- | See the Action plugin page, [[devel:action_plugins#sample_action_plugin_2]]. Also refer to [[devel:toolbar]]. | + | * The [[devel:toolbar#extending_the_toolbar|toolbar]] page explains how you can extend by PHP or javascript. |
+ | * Another | ||
===== Writing Your Own Plugin ===== | ===== Writing Your Own Plugin ===== | ||
Line 228: | Line 345: | ||
- Edit that file to make it yours. | - Edit that file to make it yours. | ||
* change the class name to be '' | * change the class name to be '' | ||
- | * change the '' | ||
* change the '' | * change the '' | ||
* add a '' | * add a '' | ||
* change the '' | * change the '' | ||
- | * change the '' | + | * change the '' |
* alter the '' | * alter the '' | ||
* add a '' | * add a '' | ||
Line 239: | Line 355: | ||
* if you have entry and exit patterns remember to handle the unmatched data. | * if you have entry and exit patterns remember to handle the unmatched data. | ||
* treat raw wiki data with suspicion and remember to ensure all special characters go to an entity converter. | * treat raw wiki data with suspicion and remember to ensure all special characters go to an entity converter. | ||
+ | - Add a [[plugin_info|plugin.info.txt]] file in your plugin directory (see for example, the sample plugin below) | ||
- Test and post your completed plugin on the DokuWiki [[: | - Test and post your completed plugin on the DokuWiki [[: | ||
+ | |||
+ | ===== Read also===== | ||
+ | |||
+ | * The [[http:// | ||
+ | * [[Plugin file structure]] | ||
+ | * [[Common plugin functions]] | ||
+ | * [[Plugin programming tips]] | ||
+ | * [[plugins|Plugin Development]] | ||
===== Sample Plugin 1 - Now ===== | ===== Sample Plugin 1 - Now ===== | ||
Line 265: | Line 390: | ||
// must be run within DokuWiki | // must be run within DokuWiki | ||
if(!defined(' | if(!defined(' | ||
- | |||
- | if(!defined(' | ||
- | require_once DOKU_PLUGIN.' | ||
/** | /** | ||
Line 275: | Line 397: | ||
class syntax_plugin_now extends DokuWiki_Syntax_Plugin { | class syntax_plugin_now extends DokuWiki_Syntax_Plugin { | ||
- | function | + | |
- | | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | | + | |
- | | + | |
- | function getSort() { return 32; } | + | |
- | + | ||
- | | + | |
$this-> | $this-> | ||
} | } | ||
- | function handle($match, | + | |
return array($match, | return array($match, | ||
} | } | ||
- | function render($mode, | + | |
+ | // $data is what the function handle return' | ||
if($mode == ' | if($mode == ' | ||
+ | /** @var Doku_Renderer_xhtml $renderer */ | ||
$renderer-> | $renderer-> | ||
return true; | return true; | ||
Line 302: | Line 417: | ||
return false; | return false; | ||
} | } | ||
- | }</ | + | } |
+ | </ | ||
+ | |||
+ | You also need the plugin.info.txt file: | ||
+ | <code txt plugin.info.txt> | ||
+ | base now | ||
+ | author me | ||
+ | email me@someplace.com | ||
+ | date 2005-07-28 | ||
+ | name Now Plugin | ||
+ | desc Include the current date and time | ||
+ | url https:// | ||
+ | </ | ||
Note: due to the way DokuWiki caches pages this plugin will report the date/time at which the cached version was created. | Note: due to the way DokuWiki caches pages this plugin will report the date/time at which the cached version was created. | ||
Line 323: | Line 450: | ||
* '' | * '' | ||
- | Again, all fairly straightforward - and here it is. | + | Put the file syntax.php from below into a folder named " |
<code php syntax.php> | <code php syntax.php> | ||
<?php | <?php | ||
Line 336: | Line 462: | ||
// must be run within Dokuwiki | // must be run within Dokuwiki | ||
if(!defined(' | if(!defined(' | ||
- | |||
- | if(!defined(' | ||
- | require_once(DOKU_PLUGIN.' | ||
/** | /** | ||
Line 346: | Line 469: | ||
class syntax_plugin_color extends DokuWiki_Syntax_Plugin { | class syntax_plugin_color extends DokuWiki_Syntax_Plugin { | ||
- | | + | |
- | * return some info | + | |
- | */ | + | |
- | function getInfo(){ | + | |
- | return array( | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ); | + | |
- | } | + | |
- | + | ||
- | | + | |
- | function getAllowedTypes() { return array(' | + | |
- | function getSort(){ return 158; } | + | |
- | function connectTo($mode) { $this-> | + | |
- | function postConnect() { $this-> | + | |
Line 370: | Line 479: | ||
* Handle the match | * Handle the match | ||
*/ | */ | ||
- | function handle($match, | + | |
switch ($state) { | switch ($state) { | ||
case DOKU_LEXER_ENTER : | case DOKU_LEXER_ENTER : | ||
Line 387: | Line 496: | ||
* Create output | * Create output | ||
*/ | */ | ||
- | function render($mode, | + | |
+ | // $data is what the function handle() return' | ||
if($mode == ' | if($mode == ' | ||
+ | /** @var Doku_Renderer_xhtml $renderer */ | ||
list($state, | list($state, | ||
switch ($state) { | switch ($state) { | ||
- | | + | |
- | list($color, | + | list($color, |
- | $renderer-> | + | $renderer-> |
- | break; | + | break; |
| | ||
- | | + | |
- | case DOKU_LEXER_EXIT : | + | |
+ | | ||
+ | case DOKU_LEXER_EXIT : | ||
+ | | ||
+ | | ||
} | } | ||
return true; | return true; | ||
Line 404: | Line 519: | ||
} | } | ||
| | ||
- | // validate | + | /** |
- | // | + | * Validate |
- | // | + | * this is cut price validation - only to ensure the basic format is correct and there is nothing harmful |
- | function _isValid($c) { | + | * three basic formats |
+ | */ | ||
+ | | ||
$c = trim($c); | $c = trim($c); | ||
| | ||
Line 421: | Line 538: | ||
} | } | ||
} | } | ||
- | ?> | ||
</ | </ | ||
Note: No checking is done to ensure colour names are valid or RGB values are within correct ranges. | Note: No checking is done to ensure colour names are valid or RGB values are within correct ranges. | ||
+ | |||
+ | ===== Unit Testing Syntax Plugins ===== | ||
+ | |||
+ | For a general introduction about Unit Testing in DokuWiki please see [[devel: | ||
+ | |||
+ | The following example function shows a simple way to do this: | ||
+ | |||
+ | <code php> | ||
+ | public function test_superscript() { | ||
+ | $info = array(); | ||
+ | $expected = " | ||
+ | |||
+ | $instructions = p_get_instructions(' | ||
+ | $xhtml = p_render(' | ||
+ | |||
+ | $this-> | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Here we strongly benefit from DokuWiki' | ||
+ |
devel/syntax_plugins.1261388167.txt.gz · Last modified: 2009-12-21 10:36 by 130.158.152.134