aboutsummaryrefslogtreecommitdiffstats
path: root/env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswakalyan Bhuyan <biswa@surgot.in> 2022-11-13 23:46:45 +0530
committerLibravatarLibravatar Biswakalyan Bhuyan <biswa@surgot.in> 2022-11-13 23:46:45 +0530
commit9468226a9e2e2ab8cdd599f1d8538e860ca86120 (patch)
tree0a77ada226d6db80639f96b438bf83e4e756edb5 /env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py
downloadidcard-9468226a9e2e2ab8cdd599f1d8538e860ca86120.tar.gz
idcard-9468226a9e2e2ab8cdd599f1d8538e860ca86120.tar.bz2
idcard-9468226a9e2e2ab8cdd599f1d8538e860ca86120.zip
id card generator
Diffstat (limited to 'env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py')
-rw-r--r--env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py246
1 files changed, 246 insertions, 0 deletions
diff --git a/env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py b/env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py
new file mode 100644
index 0000000..fd80d8c
--- /dev/null
+++ b/env/lib/python3.10/site-packages/pip/_vendor/rich/markup.py
@@ -0,0 +1,246 @@
+import re
+from ast import literal_eval
+from operator import attrgetter
+from typing import Callable, Iterable, List, Match, NamedTuple, Optional, Tuple, Union
+
+from ._emoji_replace import _emoji_replace
+from .emoji import EmojiVariant
+from .errors import MarkupError
+from .style import Style
+from .text import Span, Text
+
+RE_TAGS = re.compile(
+ r"""((\\*)\[([a-z#/@][^[]*?)])""",
+ re.VERBOSE,
+)
+
+RE_HANDLER = re.compile(r"^([\w.]*?)(\(.*?\))?$")
+
+
+class Tag(NamedTuple):
+ """A tag in console markup."""
+
+ name: str
+ """The tag name. e.g. 'bold'."""
+ parameters: Optional[str]
+ """Any additional parameters after the name."""
+
+ def __str__(self) -> str:
+ return (
+ self.name if self.parameters is None else f"{self.name} {self.parameters}"
+ )
+
+ @property
+ def markup(self) -> str:
+ """Get the string representation of this tag."""
+ return (
+ f"[{self.name}]"
+ if self.parameters is None
+ else f"[{self.name}={self.parameters}]"
+ )
+
+
+_ReStringMatch = Match[str] # regex match object
+_ReSubCallable = Callable[[_ReStringMatch], str] # Callable invoked by re.sub
+_EscapeSubMethod = Callable[[_ReSubCallable, str], str] # Sub method of a compiled re
+
+
+def escape(
+ markup: str,
+ _escape: _EscapeSubMethod = re.compile(r"(\\*)(\[[a-z#/@][^[]*?])").sub,
+) -> str:
+ """Escapes text so that it won't be interpreted as markup.
+
+ Args:
+ markup (str): Content to be inserted in to markup.
+
+ Returns:
+ str: Markup with square brackets escaped.
+ """
+
+ def escape_backslashes(match: Match[str]) -> str:
+ """Called by re.sub replace matches."""
+ backslashes, text = match.groups()
+ return f"{backslashes}{backslashes}\\{text}"
+
+ markup = _escape(escape_backslashes, markup)
+ return markup
+
+
+def _parse(markup: str) -> Iterable[Tuple[int, Optional[str], Optional[Tag]]]:
+ """Parse markup in to an iterable of tuples of (position, text, tag).
+
+ Args:
+ markup (str): A string containing console markup
+
+ """
+ position = 0
+ _divmod = divmod
+ _Tag = Tag
+ for match in RE_TAGS.finditer(markup):
+ full_text, escapes, tag_text = match.groups()
+ start, end = match.span()
+ if start > position:
+ yield start, markup[position:start], None
+ if escapes:
+ backslashes, escaped = _divmod(len(escapes), 2)
+ if backslashes:
+ # Literal backslashes
+ yield start, "\\" * backslashes, None
+ start += backslashes * 2
+ if escaped:
+ # Escape of tag
+ yield start, full_text[len(escapes) :], None
+ position = end
+ continue
+ text, equals, parameters = tag_text.partition("=")
+ yield start, None, _Tag(text, parameters if equals else None)
+ position = end
+ if position < len(markup):
+ yield position, markup[position:], None
+
+
+def render(
+ markup: str,
+ style: Union[str, Style] = "",
+ emoji: bool = True,
+ emoji_variant: Optional[EmojiVariant] = None,
+) -> Text:
+ """Render console markup in to a Text instance.
+
+ Args:
+ markup (str): A string containing console markup.
+ emoji (bool, optional): Also render emoji code. Defaults to True.
+
+ Raises:
+ MarkupError: If there is a syntax error in the markup.
+
+ Returns:
+ Text: A test instance.
+ """
+ emoji_replace = _emoji_replace
+ if "[" not in markup:
+ return Text(
+ emoji_replace(markup, default_variant=emoji_variant) if emoji else markup,
+ style=style,
+ )
+ text = Text(style=style)
+ append = text.append
+ normalize = Style.normalize
+
+ style_stack: List[Tuple[int, Tag]] = []
+ pop = style_stack.pop
+
+ spans: List[Span] = []
+ append_span = spans.append
+
+ _Span = Span
+ _Tag = Tag
+
+ def pop_style(style_name: str) -> Tuple[int, Tag]:
+ """Pop tag matching given style name."""
+ for index, (_, tag) in enumerate(reversed(style_stack), 1):
+ if tag.name == style_name:
+ return pop(-index)
+ raise KeyError(style_name)
+
+ for position, plain_text, tag in _parse(markup):
+ if plain_text is not None:
+ # Handle open brace escapes, where the brace is not part of a tag.
+ plain_text = plain_text.replace("\\[", "[")
+ append(emoji_replace(plain_text) if emoji else plain_text)
+ elif tag is not None:
+ if tag.name.startswith("/"): # Closing tag
+ style_name = tag.name[1:].strip()
+
+ if style_name: # explicit close
+ style_name = normalize(style_name)
+ try:
+ start, open_tag = pop_style(style_name)
+ except KeyError:
+ raise MarkupError(
+ f"closing tag '{tag.markup}' at position {position} doesn't match any open tag"
+ ) from None
+ else: # implicit close
+ try:
+ start, open_tag = pop()
+ except IndexError:
+ raise MarkupError(
+ f"closing tag '[/]' at position {position} has nothing to close"
+ ) from None
+
+ if open_tag.name.startswith("@"):
+ if open_tag.parameters:
+ handler_name = ""
+ parameters = open_tag.parameters.strip()
+ handler_match = RE_HANDLER.match(parameters)
+ if handler_match is not None:
+ handler_name, match_parameters = handler_match.groups()
+ parameters = (
+ "()" if match_parameters is None else match_parameters
+ )
+
+ try:
+ meta_params = literal_eval(parameters)
+ except SyntaxError as error:
+ raise MarkupError(
+ f"error parsing {parameters!r} in {open_tag.parameters!r}; {error.msg}"
+ )
+ except Exception as error:
+ raise MarkupError(
+ f"error parsing {open_tag.parameters!r}; {error}"
+ ) from None
+
+ if handler_name:
+ meta_params = (
+ handler_name,
+ meta_params
+ if isinstance(meta_params, tuple)
+ else (meta_params,),
+ )
+
+ else:
+ meta_params = ()
+
+ append_span(
+ _Span(
+ start, len(text), Style(meta={open_tag.name: meta_params})
+ )
+ )
+ else:
+ append_span(_Span(start, len(text), str(open_tag)))
+
+ else: # Opening tag
+ normalized_tag = _Tag(normalize(tag.name), tag.parameters)
+ style_stack.append((len(text), normalized_tag))
+
+ text_length = len(text)
+ while style_stack:
+ start, tag = style_stack.pop()
+ style = str(tag)
+ if style:
+ append_span(_Span(start, text_length, style))
+
+ text.spans = sorted(spans[::-1], key=attrgetter("start"))
+ return text
+
+
+if __name__ == "__main__": # pragma: no cover
+
+ MARKUP = [
+ "[red]Hello World[/red]",
+ "[magenta]Hello [b]World[/b]",
+ "[bold]Bold[italic] bold and italic [/bold]italic[/italic]",
+ "Click [link=https://www.willmcgugan.com]here[/link] to visit my Blog",
+ ":warning-emoji: [bold red blink] DANGER![/]",
+ ]
+
+ from pip._vendor.rich import print
+ from pip._vendor.rich.table import Table
+
+ grid = Table("Markup", "Result", padding=(0, 1))
+
+ for markup in MARKUP:
+ grid.add_row(Text(markup), markup)
+
+ print(grid)