1*2bb62bcaSAndreas Gohr<?php 2*2bb62bcaSAndreas Gohr 3*2bb62bcaSAndreas Gohrnamespace dokuwiki\Parsing\ParserMode; 4*2bb62bcaSAndreas Gohr 5*2bb62bcaSAndreas Gohruse dokuwiki\Parsing\Handler; 6*2bb62bcaSAndreas Gohr 7*2bb62bcaSAndreas Gohr/** 8*2bb62bcaSAndreas Gohr * GFM / CommonMark em-wrapping-strong via triple asterisks: `***text***`. 9*2bb62bcaSAndreas Gohr * 10*2bb62bcaSAndreas Gohr * Renders as <em><strong>text</strong></em>. Only the exact 3+3 symmetric 11*2bb62bcaSAndreas Gohr * variant is supported. Longer symmetric runs (`****foo****`, 12*2bb62bcaSAndreas Gohr * `******foo******`) or asymmetric runs (`***foo**`) require CommonMark's 13*2bb62bcaSAndreas Gohr * full delimiter-pairing algorithm and are out of scope. 14*2bb62bcaSAndreas Gohr * 15*2bb62bcaSAndreas Gohr * Sort 65 is below Strong (70) so this mode wins the lexer race for 16*2bb62bcaSAndreas Gohr * `***...***` patterns. 17*2bb62bcaSAndreas Gohr */ 18*2bb62bcaSAndreas Gohrclass GfmEmphasisStrong extends AbstractFormatting 19*2bb62bcaSAndreas Gohr{ 20*2bb62bcaSAndreas Gohr /** @inheritdoc */ 21*2bb62bcaSAndreas Gohr public function getSort() 22*2bb62bcaSAndreas Gohr { 23*2bb62bcaSAndreas Gohr return 65; 24*2bb62bcaSAndreas Gohr } 25*2bb62bcaSAndreas Gohr 26*2bb62bcaSAndreas Gohr /** @inheritdoc */ 27*2bb62bcaSAndreas Gohr protected function getModeName(): string 28*2bb62bcaSAndreas Gohr { 29*2bb62bcaSAndreas Gohr return 'gfm_emphasis_strong'; 30*2bb62bcaSAndreas Gohr } 31*2bb62bcaSAndreas Gohr 32*2bb62bcaSAndreas Gohr /** @inheritdoc */ 33*2bb62bcaSAndreas Gohr protected function getEntryPattern(): string 34*2bb62bcaSAndreas Gohr { 35*2bb62bcaSAndreas Gohr // Broken down: 36*2bb62bcaSAndreas Gohr // (?<!\*) — opener not preceded by `*` (so we 37*2bb62bcaSAndreas Gohr // don't match inside `****...` runs) 38*2bb62bcaSAndreas Gohr // \*\*\* — exactly three opening `*` 39*2bb62bcaSAndreas Gohr // (?=[^\s*]) — next body char: not whitespace, not `*` 40*2bb62bcaSAndreas Gohr // (flanking-opener rule) 41*2bb62bcaSAndreas Gohr // (?= — lookahead: a valid closer must exist 42*2bb62bcaSAndreas Gohr // CONTENT_UNTIL_PARA — body that doesn't cross a paragraph 43*2bb62bcaSAndreas Gohr // [^\s] — last body char: not whitespace 44*2bb62bcaSAndreas Gohr // (flanking-closer rule) 45*2bb62bcaSAndreas Gohr // \*\*\* — closing `***` 46*2bb62bcaSAndreas Gohr // (?!\*) — and not followed by another `*` 47*2bb62bcaSAndreas Gohr // (exactly 3, not 4+) 48*2bb62bcaSAndreas Gohr // ) 49*2bb62bcaSAndreas Gohr return '(?<!\*)\*\*\*(?=[^\s*])' 50*2bb62bcaSAndreas Gohr . '(?=' . self::CONTENT_UNTIL_PARA . '[^\s]\*\*\*(?!\*))'; 51*2bb62bcaSAndreas Gohr } 52*2bb62bcaSAndreas Gohr 53*2bb62bcaSAndreas Gohr /** @inheritdoc */ 54*2bb62bcaSAndreas Gohr protected function getExitPattern(): string 55*2bb62bcaSAndreas Gohr { 56*2bb62bcaSAndreas Gohr return '(?<=[^\s])\*\*\*(?!\*)'; 57*2bb62bcaSAndreas Gohr } 58*2bb62bcaSAndreas Gohr 59*2bb62bcaSAndreas Gohr /** 60*2bb62bcaSAndreas Gohr * Emit em wrapping strong (and their closers in reverse order). 61*2bb62bcaSAndreas Gohr * Overridden because AbstractFormatting's default emits a single 62*2bb62bcaSAndreas Gohr * open/close pair — we need two each. 63*2bb62bcaSAndreas Gohr * 64*2bb62bcaSAndreas Gohr * @inheritdoc 65*2bb62bcaSAndreas Gohr */ 66*2bb62bcaSAndreas Gohr public function handle($match, $state, $pos, Handler $handler) 67*2bb62bcaSAndreas Gohr { 68*2bb62bcaSAndreas Gohr switch ($state) { 69*2bb62bcaSAndreas Gohr case DOKU_LEXER_ENTER: 70*2bb62bcaSAndreas Gohr $handler->addCall('emphasis_open', [], $pos); 71*2bb62bcaSAndreas Gohr $handler->addCall('strong_open', [], $pos); 72*2bb62bcaSAndreas Gohr break; 73*2bb62bcaSAndreas Gohr case DOKU_LEXER_EXIT: 74*2bb62bcaSAndreas Gohr $handler->addCall('strong_close', [], $pos); 75*2bb62bcaSAndreas Gohr $handler->addCall('emphasis_close', [], $pos); 76*2bb62bcaSAndreas Gohr break; 77*2bb62bcaSAndreas Gohr case DOKU_LEXER_UNMATCHED: 78*2bb62bcaSAndreas Gohr $handler->addCall('cdata', [$match], $pos); 79*2bb62bcaSAndreas Gohr break; 80*2bb62bcaSAndreas Gohr } 81*2bb62bcaSAndreas Gohr return true; 82*2bb62bcaSAndreas Gohr } 83*2bb62bcaSAndreas Gohr} 84