xref: /dokuwiki/inc/parser/parser.php (revision 0b7c14c22e9810803e87a882cd9b3597b27fe74f)
1<?php
2
3if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
4
5require_once DOKU_INC . 'inc/parser/lexer.php';
6require_once DOKU_INC . 'inc/parser/handler.php';
7
8//-------------------------------------------------------------------
9
10/**
11* Sets up the Lexer with modes and points it to the Handler
12* For an intro to the Lexer see: wiki:parser
13*/
14class Doku_Parser {
15
16    var $Handler;
17
18    var $Lexer;
19
20    var $modes = array();
21
22    var $connected = FALSE;
23
24    function addBaseMode(& $BaseMode) {
25        $this->modes['base'] = & $BaseMode;
26        if ( !$this->Lexer ) {
27            $this->Lexer = & new Doku_Lexer($this->Handler,'base', TRUE);
28        }
29        $this->modes['base']->Lexer = & $this->Lexer;
30    }
31
32    /**
33    * PHP preserves order of associative elements
34    * Mode sequence is important
35    */
36    function addMode($name, & $Mode) {
37        if ( !isset($this->modes['base']) ) {
38            $this->addBaseMode(new Doku_Parser_Mode_Base());
39        }
40        $Mode->Lexer = & $this->Lexer;
41        $this->modes[$name] = & $Mode;
42    }
43
44    function connectModes() {
45
46        if ( $this->connected ) {
47            return;
48        }
49
50        foreach ( array_keys($this->modes) as $mode ) {
51
52            // Base isn't connected to anything
53            if ( $mode == 'base' ) {
54                continue;
55            }
56
57            $this->modes[$mode]->preConnect();
58
59            foreach ( array_keys($this->modes) as $cm ) {
60
61                if ( $this->modes[$cm]->accepts($mode) ) {
62                    $this->modes[$mode]->connectTo($cm);
63                }
64
65            }
66
67            $this->modes[$mode]->postConnect();
68        }
69
70        $this->connected = TRUE;
71    }
72
73    function parse($doc) {
74        if ( $this->Lexer ) {
75            $this->connectModes();
76            // Normalize CRs and pad doc
77            $doc = "\n".str_replace("\r\n","\n",$doc)."\n";
78            $this->Lexer->parse($doc);
79            $this->Handler->_finalize();
80            return $this->Handler->calls;
81        } else {
82            return FALSE;
83        }
84    }
85
86}
87
88//-------------------------------------------------------------------
89/**
90 * This class and all the subclasses below are
91 * used to reduce the effort required to register
92 * modes with the Lexer. For performance these
93 * could all be eliminated later perhaps, or
94 * the Parser could be serialized to a file once
95 * all modes are registered
96 *
97 * @author Harry Fuecks <hfuecks@gmail.com>
98*/
99class Doku_Parser_Mode {
100
101    var $Lexer;
102
103    var $allowedModes = array();
104
105    // Called before any calls to connectTo
106    function preConnect() {}
107
108    function connectTo($mode) {}
109
110    // Called after all calls to connectTo
111    function postConnect() {}
112
113    function accepts($mode) {
114        return in_array($mode, $this->allowedModes );
115    }
116
117}
118
119//-------------------------------------------------------------------
120class Doku_Parser_Mode_Base extends Doku_Parser_Mode {
121
122    function Doku_Parser_Mode_Base() {
123
124        $this->allowedModes = array_merge (
125                Doku_Parser_BlockContainers(),
126                Doku_Parser_BaseOnly(),
127                Doku_Parser_Paragraphs(),
128                Doku_Parser_Formatting(),
129                Doku_Parser_Substition(),
130                Doku_Parser_Protected(),
131                Doku_Parser_Disabled()
132            );
133    }
134}
135
136//-------------------------------------------------------------------
137class Doku_Parser_Mode_Footnote extends Doku_Parser_Mode {
138
139    function Doku_Parser_Mode_Footnote() {
140
141        $this->allowedModes = array_merge (
142                Doku_Parser_BlockContainers(),
143                Doku_Parser_Formatting(),
144                Doku_Parser_Substition(),
145                Doku_Parser_Protected(),
146                Doku_Parser_Disabled()
147            );
148
149    }
150
151    function connectTo($mode) {
152        $this->Lexer->addEntryPattern(
153            '\x28\x28(?=.*\x29\x29)',$mode,'footnote'
154            );
155    }
156
157    function postConnect() {
158        $this->Lexer->addExitPattern(
159            '\x29\x29','footnote'
160            );
161
162    }
163
164}
165
166//-------------------------------------------------------------------
167class Doku_Parser_Mode_Header extends Doku_Parser_Mode {
168
169    function preConnect() {
170        //we're not picky about the closing ones, two are enough
171
172        // Header 1 is special case - match 6 or more
173        $this->Lexer->addSpecialPattern(
174                            '[ \t]*={6,}[^\n]+={2,}[ \t]*(?=\n)',
175                            'base',
176                            'header'
177                        );
178
179        // For the rest, match exactly
180        for ( $i = 5; $i > 1; $i--) {
181            $this->Lexer->addSpecialPattern(
182                                '[ \t]*={'.$i.'}[^\n]+={2,}[ \t]*(?=\n)',
183                                'base',
184                                'header'
185                            );
186        }
187    }
188
189}
190
191//-------------------------------------------------------------------
192class Doku_Parser_Mode_NoToc extends Doku_Parser_Mode {
193
194    function connectTo($mode) {
195        $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc');
196    }
197
198}
199
200//-------------------------------------------------------------------
201class Doku_Parser_Mode_NoCache extends Doku_Parser_Mode {
202
203    function connectTo($mode) {
204        $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache');
205    }
206
207}
208
209//-------------------------------------------------------------------
210class Doku_Parser_Mode_Linebreak extends Doku_Parser_Mode {
211
212    function connectTo($mode) {
213        $this->Lexer->addSpecialPattern('\x5C{2}(?=\s)',$mode,'linebreak');
214    }
215}
216
217//-------------------------------------------------------------------
218class Doku_Parser_Mode_Eol extends Doku_Parser_Mode {
219
220    function connectTo($mode) {
221        $badModes = array('listblock','table');
222        if ( in_array($mode, $badModes) ) {
223            return;
224        }
225        $this->Lexer->addSpecialPattern('\n',$mode,'eol');
226    }
227}
228
229//-------------------------------------------------------------------
230class Doku_Parser_Mode_HR extends Doku_Parser_Mode {
231
232    function connectTo($mode) {
233        $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr');
234    }
235
236}
237
238//-------------------------------------------------------------------
239class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
240
241    var $type;
242
243    var $formatting = array (
244        'strong' => array (
245            'entry'=>'\*\*(?=.*\*\*)',
246            'exit'=>'\*\*',
247            ),
248
249        'emphasis'=> array (
250            'entry'=>'//(?=.*//)',
251            'exit'=>'//',
252            ),
253
254        'underline'=> array (
255            'entry'=>'__(?=.*__)',
256            'exit'=>'__',
257            ),
258
259        'monospace'=> array (
260            'entry'=>'\x27\x27(?=.*\x27\x27)',
261            'exit'=>'\x27\x27',
262            ),
263
264        'subscript'=> array (
265            'entry'=>'<sub>(?=.*\x3C/sub\x3E)',
266            'exit'=>'</sub>',
267            ),
268
269        'superscript'=> array (
270            'entry'=>'<sup>(?=.*\x3C/sup\x3E)',
271            'exit'=>'</sup>',
272            ),
273
274        'deleted'=> array (
275            'entry'=>'<del>(?=.*\x3C/del\x3E)',
276            'exit'=>'</del>',
277            ),
278        );
279
280    function Doku_Parser_Mode_Formatting($type) {
281
282        if ( !array_key_exists($type, $this->formatting) ) {
283            trigger_error('Invalid formatting type '.$type, E_USER_WARNING);
284        }
285
286        $this->type = $type;
287
288        $this->allowedModes = array_merge (
289                Doku_Parser_Formatting($type),
290                Doku_Parser_Substition(),
291                Doku_Parser_Disabled()
292            );
293
294    }
295
296    function connectTo($mode) {
297
298        // Can't nest formatting in itself
299        if ( $mode == $this->type ) {
300            return;
301        }
302
303        $this->Lexer->addEntryPattern(
304                $this->formatting[$this->type]['entry'],
305                $mode,
306                $this->type
307            );
308    }
309
310    function postConnect() {
311
312        $this->Lexer->addExitPattern(
313            $this->formatting[$this->type]['exit'],
314            $this->type
315            );
316
317    }
318}
319
320//-------------------------------------------------------------------
321class Doku_Parser_Mode_ListBlock extends Doku_Parser_Mode {
322
323    function Doku_Parser_Mode_ListBlock() {
324
325        $this->allowedModes = array_merge (
326                Doku_Parser_Formatting(),
327                Doku_Parser_Substition(),
328                Doku_Parser_Disabled()
329            );
330
331        $this->allowedModes[] = 'footnote';
332        $this->allowedModes[] = 'preformatted';
333        $this->allowedModes[] = 'unformatted';
334        $this->allowedModes[] = 'html';
335        $this->allowedModes[] = 'php';
336        $this->allowedModes[] = 'code';
337        $this->allowedModes[] = 'file';
338    }
339
340    function connectTo($mode) {
341        $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock');
342        $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock');
343
344        $this->Lexer->addPattern('\n {2,}[\-\*]','listblock');
345        $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock');
346
347    }
348
349    function postConnect() {
350        $this->Lexer->addExitPattern('\n','listblock');
351    }
352}
353
354//-------------------------------------------------------------------
355class Doku_Parser_Mode_Table extends Doku_Parser_Mode {
356
357    function Doku_Parser_Mode_Table() {
358
359        $this->allowedModes = array_merge (
360                Doku_Parser_Formatting(),
361                Doku_Parser_Substition(),
362                Doku_Parser_Disabled()
363            );
364        $this->allowedModes[] = 'footnote';
365        $this->allowedModes[] = 'preformatted';
366        $this->allowedModes[] = 'unformatted';
367    }
368
369    function connectTo($mode) {
370        $this->Lexer->addEntryPattern('\n\^',$mode,'table');
371        $this->Lexer->addEntryPattern('\n\|',$mode,'table');
372    }
373
374    function postConnect() {
375        $this->Lexer->addPattern('\n\^','table');
376        $this->Lexer->addPattern('\n\|','table');
377        $this->Lexer->addPattern(' {2,}','table');
378        $this->Lexer->addPattern('\^','table');
379        $this->Lexer->addPattern('\|','table');
380        $this->Lexer->addExitPattern('\n','table');
381    }
382}
383
384//-------------------------------------------------------------------
385class Doku_Parser_Mode_Unformatted extends Doku_Parser_Mode {
386
387    function connectTo($mode) {
388        $this->Lexer->addEntryPattern('<nowiki>(?=.*\x3C/nowiki\x3E)',$mode,'unformatted');
389        $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt');
390    }
391
392    function postConnect() {
393        $this->Lexer->addExitPattern('</nowiki>','unformatted');
394        $this->Lexer->addExitPattern('%%','unformattedalt');
395        $this->Lexer->mapHandler('unformattedalt','unformatted');
396    }
397
398}
399
400//-------------------------------------------------------------------
401class Doku_Parser_Mode_PHP extends Doku_Parser_Mode {
402
403    function connectTo($mode) {
404        $this->Lexer->addEntryPattern('<php>(?=.*\x3C/php\x3E)',$mode,'php');
405    }
406
407    function postConnect() {
408        $this->Lexer->addExitPattern('</php>','php');
409    }
410
411}
412
413//-------------------------------------------------------------------
414class Doku_Parser_Mode_HTML extends Doku_Parser_Mode {
415
416    function connectTo($mode) {
417        $this->Lexer->addEntryPattern('<html>(?=.*\x3C/html\x3E)',$mode,'html');
418    }
419
420    function postConnect() {
421        $this->Lexer->addExitPattern('</html>','html');
422    }
423
424}
425
426//-------------------------------------------------------------------
427class Doku_Parser_Mode_Preformatted extends Doku_Parser_Mode {
428
429    function connectTo($mode) {
430        // Has hard coded awareness of lists...
431        $this->Lexer->addEntryPattern('\n  (?![\*\-])',$mode,'preformatted');
432        $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted');
433
434        // How to effect a sub pattern with the Lexer!
435        $this->Lexer->addPattern('\n  ','preformatted');
436        $this->Lexer->addPattern('\n\t','preformatted');
437
438    }
439
440    function postConnect() {
441        $this->Lexer->addExitPattern('\n','preformatted');
442    }
443
444}
445
446//-------------------------------------------------------------------
447class Doku_Parser_Mode_Code extends Doku_Parser_Mode {
448
449    function connectTo($mode) {
450        $this->Lexer->addEntryPattern('<code(?=.*\x3C/code\x3E)',$mode,'code');
451    }
452
453    function postConnect() {
454        $this->Lexer->addExitPattern('</code>','code');
455    }
456
457}
458
459//-------------------------------------------------------------------
460class Doku_Parser_Mode_File extends Doku_Parser_Mode {
461
462    function connectTo($mode) {
463        $this->Lexer->addEntryPattern('<file>(?=.*\x3C/file\x3E)',$mode,'file');
464    }
465
466    function postConnect() {
467        $this->Lexer->addExitPattern('</file>','file');
468    }
469
470}
471
472//-------------------------------------------------------------------
473class Doku_Parser_Mode_Quote extends Doku_Parser_Mode {
474
475    function Doku_Parser_Mode_Quote() {
476
477        $this->allowedModes = array_merge (
478                Doku_Parser_Formatting(),
479                Doku_Parser_Substition(),
480                Doku_Parser_Disabled()
481            );
482            $this->allowedModes[] = 'footnote';
483            $this->allowedModes[] = 'preformatted';
484            $this->allowedModes[] = 'unformatted';
485    }
486
487    function connectTo($mode) {
488        $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote');
489    }
490
491    function postConnect() {
492        $this->Lexer->addPattern('\n>{1,}','quote');
493        $this->Lexer->addExitPattern('\n','quote');
494    }
495
496}
497
498//-------------------------------------------------------------------
499class Doku_Parser_Mode_Acronym extends Doku_Parser_Mode {
500    // A list
501    var $acronyms = array();
502    var $pattern = '';
503
504    function Doku_Parser_Mode_Acronym($acronyms) {
505        $this->acronyms = $acronyms;
506    }
507
508    function preConnect() {
509        $sep = '';
510        foreach ( $this->acronyms as $acronym ) {
511            $this->pattern .= $sep.'(?<=\b)'.Doku_Lexer_Escape($acronym).'(?=\b)';
512            $sep = '|';
513        }
514    }
515
516    function connectTo($mode) {
517        if ( strlen($this->pattern) > 0 ) {
518            $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym');
519        }
520    }
521
522}
523
524//-------------------------------------------------------------------
525class Doku_Parser_Mode_Smiley extends Doku_Parser_Mode {
526    // A list
527    var $smileys = array();
528    var $pattern = '';
529
530    function Doku_Parser_Mode_Smiley($smileys) {
531        $this->smileys = $smileys;
532    }
533
534    function preConnect() {
535        $sep = '';
536        foreach ( $this->smileys as $smiley ) {
537            $this->pattern .= $sep.Doku_Lexer_Escape($smiley);
538            $sep = '|';
539        }
540    }
541
542    function connectTo($mode) {
543        if ( strlen($this->pattern) > 0 ) {
544            $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley');
545        }
546    }
547
548}
549
550//-------------------------------------------------------------------
551class Doku_Parser_Mode_Wordblock extends Doku_Parser_Mode {
552    // A list
553    var $badwords = array();
554    var $pattern = '';
555
556    function Doku_Parser_Mode_Wordblock($badwords) {
557        $this->badwords = $badwords;
558    }
559
560    function preConnect() {
561
562        if ( count($this->badwords) == 0 ) {
563            return;
564        }
565
566        $sep = '';
567        foreach ( $this->badwords as $badword ) {
568            $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)';
569            $sep = '|';
570        }
571
572    }
573
574    function connectTo($mode) {
575        if ( strlen($this->pattern) > 0 ) {
576            $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock');
577        }
578    }
579
580}
581
582//-------------------------------------------------------------------
583/**
584* @TODO Quotes and 640x480 are not supported - just straight replacements here
585*/
586class Doku_Parser_Mode_Entity extends Doku_Parser_Mode {
587    // A list
588    var $entities = array();
589    var $pattern = '';
590
591    function Doku_Parser_Mode_Entity($entities) {
592        $this->entities = $entities;
593    }
594
595    function preConnect() {
596        $sep = '';
597        foreach ( $this->entities as $entity ) {
598            $this->pattern .= $sep.Doku_Lexer_Escape($entity);
599            $sep = '|';
600        }
601    }
602
603    function connectTo($mode) {
604        if ( strlen($this->pattern) > 0 ) {
605            $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity');
606        }
607    }
608
609}
610
611//-------------------------------------------------------------------
612// Implements the 640x480 replacement
613class Doku_Parser_Mode_MultiplyEntity extends Doku_Parser_Mode {
614
615    function connectTo($mode) {
616
617        $this->Lexer->addSpecialPattern(
618                    '(?<=\b)\d+[x|X]\d+(?=\b)',$mode,'multiplyentity'
619                );
620
621    }
622
623}
624
625//-------------------------------------------------------------------
626class Doku_Parser_Mode_Quotes extends Doku_Parser_Mode {
627
628    function connectTo($mode) {
629
630        $this->Lexer->addSpecialPattern(
631                    '(?<=\s)\'(?=\S)',$mode,'singlequoteopening'
632                );
633        $this->Lexer->addSpecialPattern(
634                    '(?<=^|\S)\'',$mode,'singlequoteclosing'
635                );
636        $this->Lexer->addSpecialPattern(
637                    '(?<=^|\s)"(?=\S)',$mode,'doublequoteopening'
638                );
639        $this->Lexer->addSpecialPattern(
640                    '(?<=\S)"',$mode,'doublequoteclosing'
641                );
642
643    }
644
645}
646
647//-------------------------------------------------------------------
648class Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode {
649
650    function connectTo($mode) {
651        $this->Lexer->addSpecialPattern(
652                '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink'
653            );
654    }
655
656}
657
658//-------------------------------------------------------------------
659class Doku_Parser_Mode_InternalLink extends Doku_Parser_Mode {
660
661    function connectTo($mode) {
662        // Word boundaries?
663        $this->Lexer->addSpecialPattern("\[\[[^\]]+?\]\]",$mode,'internallink');
664    }
665
666}
667
668//-------------------------------------------------------------------
669class Doku_Parser_Mode_Media extends Doku_Parser_Mode {
670
671    function connectTo($mode) {
672        // Word boundaries?
673        $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media');
674    }
675
676}
677
678//-------------------------------------------------------------------
679class Doku_Parser_Mode_RSS extends Doku_Parser_Mode {
680
681    function connectTo($mode) {
682        $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss');
683    }
684
685}
686
687//-------------------------------------------------------------------
688class Doku_Parser_Mode_ExternalLink extends Doku_Parser_Mode {
689    var $schemes = array('http','https','telnet','gopher','wais','ftp','ed2k','irc');
690    var $patterns = array();
691
692    function preConnect() {
693
694        $ltrs = '\w';
695        $gunk = '/\#~:.?+=&%@!\-';
696        $punc = '.:?\-;,';
697        $host = $ltrs.$punc;
698        $any  = $ltrs.$gunk.$punc;
699
700        foreach ( $this->schemes as $scheme ) {
701            $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
702        }
703
704        $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
705        $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
706
707    }
708
709    function connectTo($mode) {
710        foreach ( $this->patterns as $pattern ) {
711            $this->Lexer->addSpecialPattern($pattern,$mode,'externallink');
712        }
713    }
714
715}
716
717//-------------------------------------------------------------------
718class Doku_Parser_Mode_FileLink extends Doku_Parser_Mode {
719
720    var $pattern;
721
722    function preConnect() {
723
724        $ltrs = '\w';
725        $gunk = '/\#~:.?+=&%@!\-';
726        $punc = '.:?\-;,';
727        $host = $ltrs.$punc;
728        $any  = $ltrs.$gunk.$punc;
729
730        $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['.
731            $punc.']*[^'.$any.']';
732    }
733
734    function connectTo($mode) {
735        $this->Lexer->addSpecialPattern(
736            $this->pattern,$mode,'filelink');
737    }
738
739
740}
741
742//-------------------------------------------------------------------
743class Doku_Parser_Mode_WindowsShareLink extends Doku_Parser_Mode {
744
745    var $pattern;
746
747    function preConnect() {
748
749        $ltrs = '\w';
750        $gunk = '/\#~:.?+=&%@!\-';
751        $punc = '.:?\-;,';
752        $host = $ltrs.$punc;
753        $any  = $ltrs.$gunk.$punc;
754
755        $this->pattern = "[$gunk$punc\s]\\\\\\\\[$host]+?\\\\[$any]+?[$punc]*[^$any]";
756    }
757
758    function connectTo($mode) {
759        $this->Lexer->addSpecialPattern(
760            $this->pattern,$mode,'windowssharelink');
761    }
762
763
764}
765
766//-------------------------------------------------------------------
767class Doku_Parser_Mode_EmailLink extends Doku_Parser_Mode {
768
769    function connectTo($mode) {
770    //<([\w0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)>
771        $this->Lexer->addSpecialPattern("<[\w0-9\-_.]+?@[\w\-]+\.[\w\-\.]+\.*[\w]+>",$mode,'emaillink');
772    }
773
774}
775
776//-------------------------------------------------------------------
777// Help fns to keep mode lists - used to make it easier to populate
778// the list of modes another mode accepts
779
780// Can contain many other modes
781// E.g. a footnote can containing formatting etc.
782function Doku_Parser_BlockContainers() {
783    $modes = array(
784        'footnote', 'listblock', 'table','quote',
785        // hr breaks the principle but HRs should not be used in tables / lists
786        // so put it here
787        'hr',
788    );
789    return $modes;
790}
791
792// Used to mark paragraph boundaries
793function Doku_Parser_Paragraphs() {
794    $modes = array(
795        'eol'
796    );
797    return $modes;
798}
799
800// Can only be used by the base mode
801function Doku_Parser_BaseOnly() {
802    $modes = array(
803        'header'
804    );
805    return $modes;
806}
807
808// "Styling" modes that format text.
809function Doku_Parser_Formatting($remove = '') {
810    $modes = array(
811        'strong', 'emphasis', 'underline', 'monospace',
812        'subscript', 'superscript', 'deleted',
813        );
814    $key = array_search($remove, $modes);
815    if ( is_int($key) ) {
816        unset($modes[$key]);
817    }
818
819    return $modes;
820}
821
822// Modes where the token is simply replaced - contain no
823// other modes
824function Doku_Parser_Substition() {
825    $modes = array(
826        'acronym','smiley','wordblock','entity','camelcaselink',
827        'internallink','media','externallink','linebreak','emaillink',
828        'windowssharelink','filelink','notoc','nocache','multiplyentity',
829        'quotes','rss',
830    );
831    return $modes;
832}
833
834// Modes which have a start and end token but inside which
835// no other modes should be applied
836function Doku_Parser_Protected() {
837    $modes = array(
838        'preformatted','code','file',
839        'php','html','quote',
840    );
841    return $modes;
842}
843
844// Disable wiki markup inside this mode
845function Doku_Parser_Disabled() {
846    $modes = array(
847        'unformatted'
848    );
849    return $modes;
850}
851
852
853//Setup VIM: ex: et ts=4 enc=utf-8 :
854