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