1<?php 2 3namespace dokuwiki\Parsing\ParserMode; 4 5/** 6 * GFM / CommonMark emphasis via single asterisks: `*text*`. 7 * 8 * Emits emphasis_open / emphasis_close — the same instructions as DokuWiki's 9 * Emphasis (`//`), so both syntaxes render as <em>. 10 */ 11class GfmEmphasis extends AbstractFormatting 12{ 13 /** @inheritdoc */ 14 public function getSort() 15 { 16 return 80; 17 } 18 19 /** @inheritdoc */ 20 protected function getModeName(): string 21 { 22 return 'gfm_emphasis'; 23 } 24 25 /** @inheritdoc */ 26 protected function getInstructionName(): string 27 { 28 return 'emphasis'; 29 } 30 31 /** @inheritdoc */ 32 protected function getEntryPattern(): string 33 { 34 // Broken down: 35 // \* — opening `*` 36 // (?= — lookahead: a valid closer must exist 37 // [^\s*] — first body char: not whitespace, not `*` 38 // (flanking-opener rule) 39 // (?:NOT_AT_PARA_BREAK — possessive run of any non-`*` char 40 // [^*])*+ — that doesn't start a paragraph break 41 // (?<![\s*]) — last body char: not whitespace, not `*` 42 // (flanking-closer rule) 43 // \* — closing `*` 44 // ) 45 // The lookahead only reaches the nearest `*` (its body is `[^*]`), so 46 // it enforces CommonMark's nearest-delimiter pairing that a plain 47 // closer scan cannot express. The inherited closer check additionally 48 // keeps the opener from spanning an enclosing mode's closer (e.g. a 49 // stray `*` inside ''glob/*.conf''). 50 // 51 // The body run is possessive and the flanking-closer rule is a 52 // lookbehind rather than a trailing character the run must give back: 53 // `[^*]` cannot match `*`, so the run always stops at the nearest `*` 54 // (or a paragraph break) and never needs to backtrack. A plain 55 // quantifier with a trailing `[^\s*]` forced backtracking on every 56 // opener, so a long run of `*` with no valid closer made the non-JIT 57 // PCRE engine retain one backtracking frame per byte. 58 return '\*(?=[^\s*](?:' . self::NOT_AT_PARA_BREAK . '[^*])*+(?<![\s*])\*)'; 59 } 60 61 /** @inheritdoc */ 62 protected function getExitPattern(): string 63 { 64 return '(?<=[^\s])\*'; 65 } 66} 67