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