1<?php 2/** 3 * Define various types of modes used by the parser - they are used to 4 * populate the list of modes another mode accepts 5 */ 6global $PARSER_MODES; 7$PARSER_MODES = array( 8 // containers are complex modes that can contain many other modes 9 // hr breaks the principle but they shouldn't be used in tables / lists 10 // so they are put here 11 'container' => array('listblock','table','quote','hr'), 12 13 // some mode are allowed inside the base mode only 14 'baseonly' => array('header'), 15 16 // modes for styling text -- footnote behaves similar to styling 17 'formatting' => array('strong', 'emphasis', 'underline', 'monospace', 18 'subscript', 'superscript', 'deleted', 'footnote'), 19 20 // modes where the token is simply replaced - they can not contain any 21 // other modes 22 'substition' => array('acronym','smiley','wordblock','entity', 23 'camelcaselink', 'internallink','media', 24 'externallink','linebreak','emaillink', 25 'windowssharelink','filelink','notoc', 26 'nocache','multiplyentity','quotes','rss'), 27 28 // modes which have a start and end token but inside which 29 // no other modes should be applied 30 'protected' => array('preformatted','code','file','php','html','htmlblock','phpblock'), 31 32 // inside this mode no wiki markup should be applied but lineendings 33 // and whitespace isn't preserved 34 'disabled' => array('unformatted'), 35 36 // used to mark paragraph boundaries 37 'paragraphs' => array('eol') 38); 39 40//------------------------------------------------------------------- 41 42/** 43 * Sets up the Lexer with modes and points it to the Handler 44 * For an intro to the Lexer see: wiki:parser 45 */ 46class Doku_Parser { 47 48 var $Handler; 49 50 /** 51 * @var Doku_Lexer $Lexer 52 */ 53 var $Lexer; 54 55 var $modes = array(); 56 57 var $connected = false; 58 59 /** 60 * @param Doku_Parser_Mode_base $BaseMode 61 */ 62 function addBaseMode($BaseMode) { 63 $this->modes['base'] = $BaseMode; 64 if ( !$this->Lexer ) { 65 $this->Lexer = new Doku_Lexer($this->Handler,'base', true); 66 } 67 $this->modes['base']->Lexer = $this->Lexer; 68 } 69 70 /** 71 * PHP preserves order of associative elements 72 * Mode sequence is important 73 * 74 * @param string $name 75 * @param Doku_Parser_Mode_Interface $Mode 76 */ 77 function addMode($name, Doku_Parser_Mode_Interface $Mode) { 78 if ( !isset($this->modes['base']) ) { 79 $this->addBaseMode(new Doku_Parser_Mode_base()); 80 } 81 $Mode->Lexer = $this->Lexer; 82 $this->modes[$name] = $Mode; 83 } 84 85 function connectModes() { 86 87 if ( $this->connected ) { 88 return; 89 } 90 91 foreach ( array_keys($this->modes) as $mode ) { 92 93 // Base isn't connected to anything 94 if ( $mode == 'base' ) { 95 continue; 96 } 97 $this->modes[$mode]->preConnect(); 98 99 foreach ( array_keys($this->modes) as $cm ) { 100 101 if ( $this->modes[$cm]->accepts($mode) ) { 102 $this->modes[$mode]->connectTo($cm); 103 } 104 105 } 106 107 $this->modes[$mode]->postConnect(); 108 } 109 110 $this->connected = true; 111 } 112 113 function parse($doc) { 114 if ( $this->Lexer ) { 115 $this->connectModes(); 116 // Normalize CRs and pad doc 117 $doc = "\n".str_replace("\r\n","\n",$doc)."\n"; 118 $this->Lexer->parse($doc); 119 $this->Handler->_finalize(); 120 return $this->Handler->calls; 121 } else { 122 return false; 123 } 124 } 125 126} 127 128//------------------------------------------------------------------- 129 130/** 131 * Class Doku_Parser_Mode_Interface 132 * 133 * Defines a mode (syntax component) in the Parser 134 */ 135interface Doku_Parser_Mode_Interface { 136 /** 137 * returns a number used to determine in which order modes are added 138 */ 139 public function getSort(); 140 141 /** 142 * Called before any calls to connectTo 143 * @return void 144 */ 145 function preConnect(); 146 147 /** 148 * Connects the mode 149 * 150 * @param string $mode 151 * @return void 152 */ 153 function connectTo($mode); 154 155 /** 156 * Called after all calls to connectTo 157 * @return void 158 */ 159 function postConnect(); 160 161 /** 162 * Check if given mode is accepted inside this mode 163 * 164 * @param string $mode 165 * @return bool 166 */ 167 function accepts($mode); 168} 169 170/** 171 * This class and all the subclasses below are used to reduce the effort required to register 172 * modes with the Lexer. 173 * 174 * @author Harry Fuecks <hfuecks@gmail.com> 175 */ 176class Doku_Parser_Mode implements Doku_Parser_Mode_Interface { 177 /** 178 * @var Doku_Lexer $Lexer 179 */ 180 var $Lexer; 181 var $allowedModes = array(); 182 183 function getSort() { 184 trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING); 185 } 186 187 function preConnect() {} 188 function connectTo($mode) {} 189 function postConnect() {} 190 function accepts($mode) { 191 return in_array($mode, (array) $this->allowedModes ); 192 } 193} 194 195/** 196 * Basically the same as Doku_Parser_Mode but extends from DokuWiki_Plugin 197 * 198 * Adds additional functions to syntax plugins 199 */ 200class Doku_Parser_Mode_Plugin extends DokuWiki_Plugin implements Doku_Parser_Mode_Interface { 201 /** 202 * @var Doku_Lexer $Lexer 203 */ 204 var $Lexer; 205 var $allowedModes = array(); 206 207 /** 208 * Sort for applying this mode 209 * 210 * @return int 211 */ 212 function getSort() { 213 trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING); 214 } 215 216 function preConnect() {} 217 function connectTo($mode) {} 218 function postConnect() {} 219 function accepts($mode) { 220 return in_array($mode, (array) $this->allowedModes ); 221 } 222} 223 224//------------------------------------------------------------------- 225class Doku_Parser_Mode_base extends Doku_Parser_Mode { 226 227 function __construct() { 228 global $PARSER_MODES; 229 230 $this->allowedModes = array_merge ( 231 $PARSER_MODES['container'], 232 $PARSER_MODES['baseonly'], 233 $PARSER_MODES['paragraphs'], 234 $PARSER_MODES['formatting'], 235 $PARSER_MODES['substition'], 236 $PARSER_MODES['protected'], 237 $PARSER_MODES['disabled'] 238 ); 239 } 240 241 function getSort() { 242 return 0; 243 } 244} 245 246//------------------------------------------------------------------- 247class Doku_Parser_Mode_footnote extends Doku_Parser_Mode { 248 249 function __construct() { 250 global $PARSER_MODES; 251 252 $this->allowedModes = array_merge ( 253 $PARSER_MODES['container'], 254 $PARSER_MODES['formatting'], 255 $PARSER_MODES['substition'], 256 $PARSER_MODES['protected'], 257 $PARSER_MODES['disabled'] 258 ); 259 260 unset($this->allowedModes[array_search('footnote', $this->allowedModes)]); 261 } 262 263 function connectTo($mode) { 264 $this->Lexer->addEntryPattern( 265 '\x28\x28(?=.*\x29\x29)',$mode,'footnote' 266 ); 267 } 268 269 function postConnect() { 270 $this->Lexer->addExitPattern( 271 '\x29\x29','footnote' 272 ); 273 } 274 275 function getSort() { 276 return 150; 277 } 278} 279 280//------------------------------------------------------------------- 281class Doku_Parser_Mode_header extends Doku_Parser_Mode { 282 283 function connectTo($mode) { 284 //we're not picky about the closing ones, two are enough 285 $this->Lexer->addSpecialPattern( 286 '[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)', 287 $mode, 288 'header' 289 ); 290 } 291 292 function getSort() { 293 return 50; 294 } 295} 296 297//------------------------------------------------------------------- 298class Doku_Parser_Mode_notoc extends Doku_Parser_Mode { 299 300 function connectTo($mode) { 301 $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc'); 302 } 303 304 function getSort() { 305 return 30; 306 } 307} 308 309//------------------------------------------------------------------- 310class Doku_Parser_Mode_nocache extends Doku_Parser_Mode { 311 312 function connectTo($mode) { 313 $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache'); 314 } 315 316 function getSort() { 317 return 40; 318 } 319} 320 321//------------------------------------------------------------------- 322class Doku_Parser_Mode_linebreak extends Doku_Parser_Mode { 323 324 function connectTo($mode) { 325 $this->Lexer->addSpecialPattern('\x5C{2}(?:[ \t]|(?=\n))',$mode,'linebreak'); 326 } 327 328 function getSort() { 329 return 140; 330 } 331} 332 333//------------------------------------------------------------------- 334class Doku_Parser_Mode_eol extends Doku_Parser_Mode { 335 336 function connectTo($mode) { 337 $badModes = array('listblock','table'); 338 if ( in_array($mode, $badModes) ) { 339 return; 340 } 341 // see FS#1652, pattern extended to swallow preceding whitespace to avoid issues with lines that only contain whitespace 342 $this->Lexer->addSpecialPattern('(?:^[ \t]*)?\n',$mode,'eol'); 343 } 344 345 function getSort() { 346 return 370; 347 } 348} 349 350//------------------------------------------------------------------- 351class Doku_Parser_Mode_hr extends Doku_Parser_Mode { 352 353 function connectTo($mode) { 354 $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr'); 355 } 356 357 function getSort() { 358 return 160; 359 } 360} 361 362//------------------------------------------------------------------- 363/** 364 * This class sets the markup for bold (=strong), 365 * italic (=emphasis), underline etc. 366 */ 367class Doku_Parser_Mode_formatting extends Doku_Parser_Mode { 368 var $type; 369 370 var $formatting = array ( 371 'strong' => array ( 372 'entry'=>'\*\*(?=.*\*\*)', 373 'exit'=>'\*\*', 374 'sort'=>70 375 ), 376 377 'emphasis'=> array ( 378 'entry'=>'//(?=[^\x00]*[^:])', //hack for bugs #384 #763 #1468 379 'exit'=>'//', 380 'sort'=>80 381 ), 382 383 'underline'=> array ( 384 'entry'=>'__(?=.*__)', 385 'exit'=>'__', 386 'sort'=>90 387 ), 388 389 'monospace'=> array ( 390 'entry'=>'\x27\x27(?=.*\x27\x27)', 391 'exit'=>'\x27\x27', 392 'sort'=>100 393 ), 394 395 'subscript'=> array ( 396 'entry'=>'<sub>(?=.*</sub>)', 397 'exit'=>'</sub>', 398 'sort'=>110 399 ), 400 401 'superscript'=> array ( 402 'entry'=>'<sup>(?=.*</sup>)', 403 'exit'=>'</sup>', 404 'sort'=>120 405 ), 406 407 'deleted'=> array ( 408 'entry'=>'<del>(?=.*</del>)', 409 'exit'=>'</del>', 410 'sort'=>130 411 ), 412 ); 413 414 /** 415 * @param string $type 416 */ 417 function __construct($type) { 418 global $PARSER_MODES; 419 420 if ( !array_key_exists($type, $this->formatting) ) { 421 trigger_error('Invalid formatting type '.$type, E_USER_WARNING); 422 } 423 424 $this->type = $type; 425 426 // formatting may contain other formatting but not it self 427 $modes = $PARSER_MODES['formatting']; 428 $key = array_search($type, $modes); 429 if ( is_int($key) ) { 430 unset($modes[$key]); 431 } 432 433 $this->allowedModes = array_merge ( 434 $modes, 435 $PARSER_MODES['substition'], 436 $PARSER_MODES['disabled'] 437 ); 438 } 439 440 function connectTo($mode) { 441 442 // Can't nest formatting in itself 443 if ( $mode == $this->type ) { 444 return; 445 } 446 447 $this->Lexer->addEntryPattern( 448 $this->formatting[$this->type]['entry'], 449 $mode, 450 $this->type 451 ); 452 } 453 454 function postConnect() { 455 456 $this->Lexer->addExitPattern( 457 $this->formatting[$this->type]['exit'], 458 $this->type 459 ); 460 461 } 462 463 function getSort() { 464 return $this->formatting[$this->type]['sort']; 465 } 466} 467 468//------------------------------------------------------------------- 469class Doku_Parser_Mode_listblock extends Doku_Parser_Mode { 470 471 function __construct() { 472 global $PARSER_MODES; 473 474 $this->allowedModes = array_merge ( 475 $PARSER_MODES['formatting'], 476 $PARSER_MODES['substition'], 477 $PARSER_MODES['disabled'], 478 $PARSER_MODES['protected'] #XXX new 479 ); 480 481 // $this->allowedModes[] = 'footnote'; 482 } 483 484 function connectTo($mode) { 485 $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]',$mode,'listblock'); 486 $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]',$mode,'listblock'); 487 488 $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); 489 $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); 490 491 } 492 493 function postConnect() { 494 $this->Lexer->addExitPattern('\n','listblock'); 495 } 496 497 function getSort() { 498 return 10; 499 } 500} 501 502//------------------------------------------------------------------- 503class Doku_Parser_Mode_table extends Doku_Parser_Mode { 504 505 function __construct() { 506 global $PARSER_MODES; 507 508 $this->allowedModes = array_merge ( 509 $PARSER_MODES['formatting'], 510 $PARSER_MODES['substition'], 511 $PARSER_MODES['disabled'], 512 $PARSER_MODES['protected'] 513 ); 514 } 515 516 function connectTo($mode) { 517 $this->Lexer->addEntryPattern('[\t ]*\n\^',$mode,'table'); 518 $this->Lexer->addEntryPattern('[\t ]*\n\|',$mode,'table'); 519 } 520 521 function postConnect() { 522 $this->Lexer->addPattern('\n\^','table'); 523 $this->Lexer->addPattern('\n\|','table'); 524 $this->Lexer->addPattern('[\t ]*:::[\t ]*(?=[\|\^])','table'); 525 $this->Lexer->addPattern('[\t ]+','table'); 526 $this->Lexer->addPattern('\^','table'); 527 $this->Lexer->addPattern('\|','table'); 528 $this->Lexer->addExitPattern('\n','table'); 529 } 530 531 function getSort() { 532 return 60; 533 } 534} 535 536//------------------------------------------------------------------- 537class Doku_Parser_Mode_unformatted extends Doku_Parser_Mode { 538 539 function connectTo($mode) { 540 $this->Lexer->addEntryPattern('<nowiki>(?=.*</nowiki>)',$mode,'unformatted'); 541 $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt'); 542 } 543 544 function postConnect() { 545 $this->Lexer->addExitPattern('</nowiki>','unformatted'); 546 $this->Lexer->addExitPattern('%%','unformattedalt'); 547 $this->Lexer->mapHandler('unformattedalt','unformatted'); 548 } 549 550 function getSort() { 551 return 170; 552 } 553} 554 555//------------------------------------------------------------------- 556class Doku_Parser_Mode_php extends Doku_Parser_Mode { 557 558 function connectTo($mode) { 559 $this->Lexer->addEntryPattern('<php>(?=.*</php>)',$mode,'php'); 560 $this->Lexer->addEntryPattern('<PHP>(?=.*</PHP>)',$mode,'phpblock'); 561 } 562 563 function postConnect() { 564 $this->Lexer->addExitPattern('</php>','php'); 565 $this->Lexer->addExitPattern('</PHP>','phpblock'); 566 } 567 568 function getSort() { 569 return 180; 570 } 571} 572 573//------------------------------------------------------------------- 574class Doku_Parser_Mode_html extends Doku_Parser_Mode { 575 576 function connectTo($mode) { 577 $this->Lexer->addEntryPattern('<html>(?=.*</html>)',$mode,'html'); 578 $this->Lexer->addEntryPattern('<HTML>(?=.*</HTML>)',$mode,'htmlblock'); 579 } 580 581 function postConnect() { 582 $this->Lexer->addExitPattern('</html>','html'); 583 $this->Lexer->addExitPattern('</HTML>','htmlblock'); 584 } 585 586 function getSort() { 587 return 190; 588 } 589} 590 591//------------------------------------------------------------------- 592class Doku_Parser_Mode_preformatted extends Doku_Parser_Mode { 593 594 function connectTo($mode) { 595 // Has hard coded awareness of lists... 596 $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted'); 597 $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted'); 598 599 // How to effect a sub pattern with the Lexer! 600 $this->Lexer->addPattern('\n ','preformatted'); 601 $this->Lexer->addPattern('\n\t','preformatted'); 602 603 } 604 605 function postConnect() { 606 $this->Lexer->addExitPattern('\n','preformatted'); 607 } 608 609 function getSort() { 610 return 20; 611 } 612} 613 614//------------------------------------------------------------------- 615class Doku_Parser_Mode_code extends Doku_Parser_Mode { 616 617 function connectTo($mode) { 618 $this->Lexer->addEntryPattern('<code\b(?=.*</code>)',$mode,'code'); 619 } 620 621 function postConnect() { 622 $this->Lexer->addExitPattern('</code>','code'); 623 } 624 625 function getSort() { 626 return 200; 627 } 628} 629 630//------------------------------------------------------------------- 631class Doku_Parser_Mode_file extends Doku_Parser_Mode { 632 633 function connectTo($mode) { 634 $this->Lexer->addEntryPattern('<file\b(?=.*</file>)',$mode,'file'); 635 } 636 637 function postConnect() { 638 $this->Lexer->addExitPattern('</file>','file'); 639 } 640 641 function getSort() { 642 return 210; 643 } 644} 645 646//------------------------------------------------------------------- 647class Doku_Parser_Mode_quote extends Doku_Parser_Mode { 648 649 function __construct() { 650 global $PARSER_MODES; 651 652 $this->allowedModes = array_merge ( 653 $PARSER_MODES['formatting'], 654 $PARSER_MODES['substition'], 655 $PARSER_MODES['disabled'], 656 $PARSER_MODES['protected'] #XXX new 657 ); 658 #$this->allowedModes[] = 'footnote'; 659 #$this->allowedModes[] = 'preformatted'; 660 #$this->allowedModes[] = 'unformatted'; 661 } 662 663 function connectTo($mode) { 664 $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote'); 665 } 666 667 function postConnect() { 668 $this->Lexer->addPattern('\n>{1,}','quote'); 669 $this->Lexer->addExitPattern('\n','quote'); 670 } 671 672 function getSort() { 673 return 220; 674 } 675} 676 677//------------------------------------------------------------------- 678class Doku_Parser_Mode_acronym extends Doku_Parser_Mode { 679 // A list 680 var $acronyms = array(); 681 var $pattern = ''; 682 683 function __construct($acronyms) { 684 usort($acronyms,array($this,'_compare')); 685 $this->acronyms = $acronyms; 686 } 687 688 function preConnect() { 689 if(!count($this->acronyms)) return; 690 691 $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]'; 692 $acronyms = array_map('Doku_Lexer_Escape',$this->acronyms); 693 $this->pattern = '(?<=^|'.$bound.')(?:'.join('|',$acronyms).')(?='.$bound.')'; 694 } 695 696 function connectTo($mode) { 697 if(!count($this->acronyms)) return; 698 699 if ( strlen($this->pattern) > 0 ) { 700 $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym'); 701 } 702 } 703 704 function getSort() { 705 return 240; 706 } 707 708 /** 709 * sort callback to order by string length descending 710 * 711 * @param string $a 712 * @param string $b 713 * 714 * @return int 715 */ 716 function _compare($a,$b) { 717 $a_len = strlen($a); 718 $b_len = strlen($b); 719 if ($a_len > $b_len) { 720 return -1; 721 } else if ($a_len < $b_len) { 722 return 1; 723 } 724 725 return 0; 726 } 727} 728 729//------------------------------------------------------------------- 730class Doku_Parser_Mode_smiley extends Doku_Parser_Mode { 731 // A list 732 var $smileys = array(); 733 var $pattern = ''; 734 735 function __construct($smileys) { 736 $this->smileys = $smileys; 737 } 738 739 function preConnect() { 740 if(!count($this->smileys) || $this->pattern != '') return; 741 742 $sep = ''; 743 foreach ( $this->smileys as $smiley ) { 744 $this->pattern .= $sep.'(?<=\W|^)'.Doku_Lexer_Escape($smiley).'(?=\W|$)'; 745 $sep = '|'; 746 } 747 } 748 749 function connectTo($mode) { 750 if(!count($this->smileys)) return; 751 752 if ( strlen($this->pattern) > 0 ) { 753 $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley'); 754 } 755 } 756 757 function getSort() { 758 return 230; 759 } 760} 761 762//------------------------------------------------------------------- 763class Doku_Parser_Mode_wordblock extends Doku_Parser_Mode { 764 // A list 765 var $badwords = array(); 766 var $pattern = ''; 767 768 function __construct($badwords) { 769 $this->badwords = $badwords; 770 } 771 772 function preConnect() { 773 774 if ( count($this->badwords) == 0 || $this->pattern != '') { 775 return; 776 } 777 778 $sep = ''; 779 foreach ( $this->badwords as $badword ) { 780 $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)'; 781 $sep = '|'; 782 } 783 784 } 785 786 function connectTo($mode) { 787 if ( strlen($this->pattern) > 0 ) { 788 $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock'); 789 } 790 } 791 792 function getSort() { 793 return 250; 794 } 795} 796 797//------------------------------------------------------------------- 798class Doku_Parser_Mode_entity extends Doku_Parser_Mode { 799 // A list 800 var $entities = array(); 801 var $pattern = ''; 802 803 function __construct($entities) { 804 $this->entities = $entities; 805 } 806 807 function preConnect() { 808 if(!count($this->entities) || $this->pattern != '') return; 809 810 $sep = ''; 811 foreach ( $this->entities as $entity ) { 812 $this->pattern .= $sep.Doku_Lexer_Escape($entity); 813 $sep = '|'; 814 } 815 } 816 817 function connectTo($mode) { 818 if(!count($this->entities)) return; 819 820 if ( strlen($this->pattern) > 0 ) { 821 $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity'); 822 } 823 } 824 825 function getSort() { 826 return 260; 827 } 828} 829 830//------------------------------------------------------------------- 831// Implements the 640x480 replacement 832class Doku_Parser_Mode_multiplyentity extends Doku_Parser_Mode { 833 834 function connectTo($mode) { 835 836 $this->Lexer->addSpecialPattern( 837 '(?<=\b)(?:[1-9]|\d{2,})[xX]\d+(?=\b)',$mode,'multiplyentity' 838 ); 839 840 } 841 842 function getSort() { 843 return 270; 844 } 845} 846 847//------------------------------------------------------------------- 848class Doku_Parser_Mode_quotes extends Doku_Parser_Mode { 849 850 function connectTo($mode) { 851 global $conf; 852 853 $ws = '\s/\#~:+=&%@\-\x28\x29\]\[{}><"\''; // whitespace 854 $punc = ';,\.?!'; 855 856 if($conf['typography'] == 2){ 857 $this->Lexer->addSpecialPattern( 858 "(?<=^|[$ws])'(?=[^$ws$punc])",$mode,'singlequoteopening' 859 ); 860 $this->Lexer->addSpecialPattern( 861 "(?<=^|[^$ws]|[$punc])'(?=$|[$ws$punc])",$mode,'singlequoteclosing' 862 ); 863 $this->Lexer->addSpecialPattern( 864 "(?<=^|[^$ws$punc])'(?=$|[^$ws$punc])",$mode,'apostrophe' 865 ); 866 } 867 868 $this->Lexer->addSpecialPattern( 869 "(?<=^|[$ws])\"(?=[^$ws$punc])",$mode,'doublequoteopening' 870 ); 871 $this->Lexer->addSpecialPattern( 872 "\"",$mode,'doublequoteclosing' 873 ); 874 875 } 876 877 function getSort() { 878 return 280; 879 } 880} 881 882//------------------------------------------------------------------- 883class Doku_Parser_Mode_camelcaselink extends Doku_Parser_Mode { 884 885 function connectTo($mode) { 886 $this->Lexer->addSpecialPattern( 887 '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' 888 ); 889 } 890 891 function getSort() { 892 return 290; 893 } 894} 895 896//------------------------------------------------------------------- 897class Doku_Parser_Mode_internallink extends Doku_Parser_Mode { 898 899 function connectTo($mode) { 900 // Word boundaries? 901 $this->Lexer->addSpecialPattern("\[\[.*?\]\](?!\])",$mode,'internallink'); 902 } 903 904 function getSort() { 905 return 300; 906 } 907} 908 909//------------------------------------------------------------------- 910class Doku_Parser_Mode_media extends Doku_Parser_Mode { 911 912 function connectTo($mode) { 913 // Word boundaries? 914 $this->Lexer->addSpecialPattern("\{\{(?:[^\}]|(?:\}[^\}]))+\}\}",$mode,'media'); 915 } 916 917 function getSort() { 918 return 320; 919 } 920} 921 922//------------------------------------------------------------------- 923class Doku_Parser_Mode_rss extends Doku_Parser_Mode { 924 925 function connectTo($mode) { 926 $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss'); 927 } 928 929 function getSort() { 930 return 310; 931 } 932} 933 934//------------------------------------------------------------------- 935class Doku_Parser_Mode_externallink extends Doku_Parser_Mode { 936 var $schemes = array(); 937 var $patterns = array(); 938 939 function preConnect() { 940 if(count($this->patterns)) return; 941 942 $ltrs = '\w'; 943 $gunk = '/\#~:.?+=&%@!\-\[\]'; 944 $punc = '.:?\-;,'; 945 $host = $ltrs.$punc; 946 $any = $ltrs.$gunk.$punc; 947 948 $this->schemes = getSchemes(); 949 foreach ( $this->schemes as $scheme ) { 950 $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 951 } 952 953 $this->patterns[] = '(?<=\s)(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 954 $this->patterns[] = '(?<=\s)(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 955 } 956 957 function connectTo($mode) { 958 959 foreach ( $this->patterns as $pattern ) { 960 $this->Lexer->addSpecialPattern($pattern,$mode,'externallink'); 961 } 962 } 963 964 function getSort() { 965 return 330; 966 } 967} 968 969//------------------------------------------------------------------- 970class Doku_Parser_Mode_filelink extends Doku_Parser_Mode { 971 972 var $pattern; 973 974 function preConnect() { 975 976 $ltrs = '\w'; 977 $gunk = '/\#~:.?+=&%@!\-'; 978 $punc = '.:?\-;,'; 979 $host = $ltrs.$punc; 980 $any = $ltrs.$gunk.$punc; 981 982 $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['. 983 $punc.']*[^'.$any.']'; 984 } 985 986 function connectTo($mode) { 987 $this->Lexer->addSpecialPattern( 988 $this->pattern,$mode,'filelink'); 989 } 990 991 function getSort() { 992 return 360; 993 } 994} 995 996//------------------------------------------------------------------- 997class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode { 998 999 var $pattern; 1000 1001 function preConnect() { 1002 $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w\-$]+)+"; 1003 } 1004 1005 function connectTo($mode) { 1006 $this->Lexer->addSpecialPattern( 1007 $this->pattern,$mode,'windowssharelink'); 1008 } 1009 1010 function getSort() { 1011 return 350; 1012 } 1013} 1014 1015//------------------------------------------------------------------- 1016class Doku_Parser_Mode_emaillink extends Doku_Parser_Mode { 1017 1018 function connectTo($mode) { 1019 // pattern below is defined in inc/mail.php 1020 $this->Lexer->addSpecialPattern('<'.PREG_PATTERN_VALID_EMAIL.'>',$mode,'emaillink'); 1021 } 1022 1023 function getSort() { 1024 return 340; 1025 } 1026} 1027 1028 1029//Setup VIM: ex: et ts=4 : 1030