1<?php 2 3namespace dokuwiki\Parsing\ParserMode; 4 5use dokuwiki\Parsing\Handler; 6use dokuwiki\Parsing\Helpers\Escape; 7 8/** 9 * GFM backslash escapes: a backslash before any ASCII punctuation 10 * character produces the literal punctuation character; the backslash 11 * itself is consumed and the following char loses any markup meaning. 12 * 13 * Backslashes before any other character (letters, digits, multibyte, 14 * spaces, tabs, newlines) are NOT escapes — those sequences stay 15 * literal because the pattern doesn't match them and the lexer leaves 16 * them as cdata. 17 * 18 * Sort 5 places this mode ahead of every other inline mode so that 19 * leftmost-then-priority resolution claims `\X` before any competing 20 * delimiter (emphasis `*`, heading `#`, link `[`, …) can match the 21 * unescaped char. 22 * 23 * Category SUBSTITION (alongside Smiley and Entity) so the mode is 24 * reachable everywhere those run: inside paragraphs, formatting 25 * modes (emphasis, strong, deleted), list items, table cells, headers 26 * — every container whose allowedModes include SUBSTITION. Whole-span 27 * code modes (GfmCode, GfmFile, GfmBacktickSingle, GfmBacktickDouble) 28 * capture their entire body in one regex shot and therefore bypass 29 * GfmEscape on their content — matching GFM's rule that escapes don't 30 * fire inside code blocks or code spans. 31 * 32 * Modes that capture a literal string and need GFM unescape applied 33 * post-hoc (link URL/label, fence info string) call 34 * {@see \dokuwiki\Parsing\Helpers\Escape::unescapeBackslashes()} from 35 * their handle() — same character class. 36 */ 37class GfmEscape extends AbstractMode 38{ 39 public function __construct() 40 { 41 $this->allowedModes = []; 42 } 43 44 /** @inheritdoc */ 45 public function getSort() 46 { 47 return 5; 48 } 49 50 /** @inheritdoc */ 51 public function connectTo($mode) 52 { 53 $this->Lexer->addSpecialPattern( 54 '\\\\' . Escape::PUNCTUATION_CHAR_CLASS, 55 $mode, 56 'gfm_escape' 57 ); 58 } 59 60 /** @inheritdoc */ 61 public function handle($match, $state, $pos, Handler $handler) 62 { 63 $handler->addCall('cdata', [substr($match, 1)], $pos); 64 return true; 65 } 66} 67