| 96 | |
| 97 | |
| 98 | class ParserInline: |
| 99 | def __init__(self) -> None: |
| 100 | self.ruler = Ruler[RuleFuncInlineType]() |
| 101 | for name, rule in _rules: |
| 102 | self.ruler.push(name, rule) |
| 103 | # Second ruler used for post-processing (e.g. in emphasis-like rules) |
| 104 | self.ruler2 = Ruler[RuleFuncInline2Type]() |
| 105 | for name, rule2 in _rules2: |
| 106 | self.ruler2.push(name, rule2) |
| 107 | # Characters that stop the text rule, allowing other inline rules to fire. |
| 108 | # _extra_terminator_chars is only allocated when add_terminator_char() is called |
| 109 | # with a char outside the defaults, keeping __init__ allocation-free. |
| 110 | self._extra_terminator_chars: set[str] = set() |
| 111 | # Pre-compiled regex shared with all default instances (no copy in the common path). |
| 112 | self.terminator_re: re.Pattern[str] = _default_terminator_re() |
| 113 | |
| 114 | def add_terminator_char(self, ch: str) -> None: |
| 115 | """Register a character that stops the ``text`` rule, allowing inline rules to fire. |
| 116 | |
| 117 | This lets plugins declare which characters their inline rules react to, |
| 118 | mirroring the ``MARKER`` mechanism in the Rust markdown-it implementation. |
| 119 | |
| 120 | :param ch: A single character to add to the terminator set. |
| 121 | """ |
| 122 | if ch not in _DEFAULT_TERMINATORS and ch not in self._extra_terminator_chars: |
| 123 | self._extra_terminator_chars.add(ch) |
| 124 | self.terminator_re = re.compile( |
| 125 | "[" |
| 126 | + re.escape( |
| 127 | "".join(_DEFAULT_TERMINATORS | self._extra_terminator_chars) |
| 128 | ) |
| 129 | + "]" |
| 130 | ) |
| 131 | |
| 132 | def skipToken(self, state: StateInline) -> None: |
| 133 | """Skip single token by running all rules in validation mode; |
| 134 | returns `True` if any rule reported success |
| 135 | """ |
| 136 | ok = False |
| 137 | pos = state.pos |
| 138 | rules = self.ruler.getRules("") |
| 139 | maxNesting = state.md.options["maxNesting"] |
| 140 | cache = state.cache |
| 141 | |
| 142 | if pos in cache: |
| 143 | state.pos = cache[pos] |
| 144 | return |
| 145 | |
| 146 | if state.level < maxNesting: |
| 147 | for rule in rules: |
| 148 | # Increment state.level and decrement it later to limit recursion. |
| 149 | # It's harmless to do here, because no tokens are created. |
| 150 | # But ideally, we'd need a separate private state variable for this purpose. |
| 151 | state.level += 1 |
| 152 | ok = rule(state, True) |
| 153 | state.level -= 1 |
| 154 | if ok: |
| 155 | break |
no outgoing calls
no test coverage detected
searching dependent graphs…