Parse markup in to an iterable of tuples of (position, text, tag). Args: markup (str): A string containing console markup
(markup: str)
| 71 | |
| 72 | |
| 73 | def _parse(markup: str) -> Iterable[Tuple[int, Optional[str], Optional[Tag]]]: |
| 74 | """Parse markup in to an iterable of tuples of (position, text, tag). |
| 75 | |
| 76 | Args: |
| 77 | markup (str): A string containing console markup |
| 78 | |
| 79 | """ |
| 80 | position = 0 |
| 81 | _divmod = divmod |
| 82 | _Tag = Tag |
| 83 | for match in RE_TAGS.finditer(markup): |
| 84 | full_text, escapes, tag_text = match.groups() |
| 85 | start, end = match.span() |
| 86 | if start > position: |
| 87 | yield start, markup[position:start], None |
| 88 | if escapes: |
| 89 | backslashes, escaped = _divmod(len(escapes), 2) |
| 90 | if backslashes: |
| 91 | # Literal backslashes |
| 92 | yield start, "\\" * backslashes, None |
| 93 | start += backslashes * 2 |
| 94 | if escaped: |
| 95 | # Escape of tag |
| 96 | yield start, full_text[len(escapes) :], None |
| 97 | position = end |
| 98 | continue |
| 99 | text, equals, parameters = tag_text.partition("=") |
| 100 | yield start, None, _Tag(text, parameters if equals else None) |
| 101 | position = end |
| 102 | if position < len(markup): |
| 103 | yield position, markup[position:], None |
| 104 | |
| 105 | |
| 106 | def render( |