| | """Tokenizes paragraph content.""" |
| |
|
| | from __future__ import annotations |
| |
|
| | from collections.abc import Callable |
| | from typing import TYPE_CHECKING |
| |
|
| | from . import rules_inline |
| | from .ruler import Ruler |
| | from .rules_inline.state_inline import StateInline |
| | from .token import Token |
| | from .utils import EnvType |
| |
|
| | if TYPE_CHECKING: |
| | from markdown_it import MarkdownIt |
| |
|
| |
|
| | |
| | RuleFuncInlineType = Callable[[StateInline, bool], bool] |
| | """(state: StateInline, silent: bool) -> matched: bool) |
| | |
| | `silent` disables token generation, useful for lookahead. |
| | """ |
| | _rules: list[tuple[str, RuleFuncInlineType]] = [ |
| | ("text", rules_inline.text), |
| | ("linkify", rules_inline.linkify), |
| | ("newline", rules_inline.newline), |
| | ("escape", rules_inline.escape), |
| | ("backticks", rules_inline.backtick), |
| | ("strikethrough", rules_inline.strikethrough.tokenize), |
| | ("emphasis", rules_inline.emphasis.tokenize), |
| | ("link", rules_inline.link), |
| | ("image", rules_inline.image), |
| | ("autolink", rules_inline.autolink), |
| | ("html_inline", rules_inline.html_inline), |
| | ("entity", rules_inline.entity), |
| | ] |
| |
|
| | |
| | |
| | |
| | |
| | |
| | RuleFuncInline2Type = Callable[[StateInline], None] |
| | _rules2: list[tuple[str, RuleFuncInline2Type]] = [ |
| | ("balance_pairs", rules_inline.link_pairs), |
| | ("strikethrough", rules_inline.strikethrough.postProcess), |
| | ("emphasis", rules_inline.emphasis.postProcess), |
| | |
| | |
| | ("fragments_join", rules_inline.fragments_join), |
| | ] |
| |
|
| |
|
| | class ParserInline: |
| | def __init__(self) -> None: |
| | self.ruler = Ruler[RuleFuncInlineType]() |
| | for name, rule in _rules: |
| | self.ruler.push(name, rule) |
| | |
| | self.ruler2 = Ruler[RuleFuncInline2Type]() |
| | for name, rule2 in _rules2: |
| | self.ruler2.push(name, rule2) |
| |
|
| | def skipToken(self, state: StateInline) -> None: |
| | """Skip single token by running all rules in validation mode; |
| | returns `True` if any rule reported success |
| | """ |
| | ok = False |
| | pos = state.pos |
| | rules = self.ruler.getRules("") |
| | maxNesting = state.md.options["maxNesting"] |
| | cache = state.cache |
| |
|
| | if pos in cache: |
| | state.pos = cache[pos] |
| | return |
| |
|
| | if state.level < maxNesting: |
| | for rule in rules: |
| | |
| | |
| | |
| | state.level += 1 |
| | ok = rule(state, True) |
| | state.level -= 1 |
| | if ok: |
| | break |
| | else: |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | state.pos = state.posMax |
| |
|
| | if not ok: |
| | state.pos += 1 |
| | cache[pos] = state.pos |
| |
|
| | def tokenize(self, state: StateInline) -> None: |
| | """Generate tokens for input range.""" |
| | ok = False |
| | rules = self.ruler.getRules("") |
| | end = state.posMax |
| | maxNesting = state.md.options["maxNesting"] |
| |
|
| | while state.pos < end: |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if state.level < maxNesting: |
| | for rule in rules: |
| | ok = rule(state, False) |
| | if ok: |
| | break |
| |
|
| | if ok: |
| | if state.pos >= end: |
| | break |
| | continue |
| |
|
| | state.pending += state.src[state.pos] |
| | state.pos += 1 |
| |
|
| | if state.pending: |
| | state.pushPending() |
| |
|
| | def parse( |
| | self, src: str, md: MarkdownIt, env: EnvType, tokens: list[Token] |
| | ) -> list[Token]: |
| | """Process input string and push inline tokens into `tokens`""" |
| | state = StateInline(src, md, env, tokens) |
| | self.tokenize(state) |
| | rules2 = self.ruler2.getRules("") |
| | for rule in rules2: |
| | rule(state) |
| | return state.tokens |
| |
|