kannadaLettersClassification
/
env
/lib
/python3.12
/site-packages
/prompt_toolkit
/formatted_text
/html.py
| from __future__ import annotations | |
| import xml.dom.minidom as minidom | |
| from string import Formatter | |
| from typing import Any | |
| from .base import FormattedText, StyleAndTextTuples | |
| __all__ = ["HTML"] | |
| class HTML: | |
| """ | |
| HTML formatted text. | |
| Take something HTML-like, for use as a formatted string. | |
| :: | |
| # Turn something into red. | |
| HTML('<style fg="ansired" bg="#00ff44">...</style>') | |
| # Italic, bold, underline and strike. | |
| HTML('<i>...</i>') | |
| HTML('<b>...</b>') | |
| HTML('<u>...</u>') | |
| HTML('<s>...</s>') | |
| All HTML elements become available as a "class" in the style sheet. | |
| E.g. ``<username>...</username>`` can be styled, by setting a style for | |
| ``username``. | |
| """ | |
| def __init__(self, value: str) -> None: | |
| self.value = value | |
| document = minidom.parseString(f"<html-root>{value}</html-root>") | |
| result: StyleAndTextTuples = [] | |
| name_stack: list[str] = [] | |
| fg_stack: list[str] = [] | |
| bg_stack: list[str] = [] | |
| def get_current_style() -> str: | |
| "Build style string for current node." | |
| parts = [] | |
| if name_stack: | |
| parts.append("class:" + ",".join(name_stack)) | |
| if fg_stack: | |
| parts.append("fg:" + fg_stack[-1]) | |
| if bg_stack: | |
| parts.append("bg:" + bg_stack[-1]) | |
| return " ".join(parts) | |
| def process_node(node: Any) -> None: | |
| "Process node recursively." | |
| for child in node.childNodes: | |
| if child.nodeType == child.TEXT_NODE: | |
| result.append((get_current_style(), child.data)) | |
| else: | |
| add_to_name_stack = child.nodeName not in ( | |
| "#document", | |
| "html-root", | |
| "style", | |
| ) | |
| fg = bg = "" | |
| for k, v in child.attributes.items(): | |
| if k == "fg": | |
| fg = v | |
| if k == "bg": | |
| bg = v | |
| if k == "color": | |
| fg = v # Alias for 'fg'. | |
| # Check for spaces in attributes. This would result in | |
| # invalid style strings otherwise. | |
| if " " in fg: | |
| raise ValueError('"fg" attribute contains a space.') | |
| if " " in bg: | |
| raise ValueError('"bg" attribute contains a space.') | |
| if add_to_name_stack: | |
| name_stack.append(child.nodeName) | |
| if fg: | |
| fg_stack.append(fg) | |
| if bg: | |
| bg_stack.append(bg) | |
| process_node(child) | |
| if add_to_name_stack: | |
| name_stack.pop() | |
| if fg: | |
| fg_stack.pop() | |
| if bg: | |
| bg_stack.pop() | |
| process_node(document) | |
| self.formatted_text = FormattedText(result) | |
| def __repr__(self) -> str: | |
| return f"HTML({self.value!r})" | |
| def __pt_formatted_text__(self) -> StyleAndTextTuples: | |
| return self.formatted_text | |
| def format(self, *args: object, **kwargs: object) -> HTML: | |
| """ | |
| Like `str.format`, but make sure that the arguments are properly | |
| escaped. | |
| """ | |
| return HTML(FORMATTER.vformat(self.value, args, kwargs)) | |
| def __mod__(self, value: object) -> HTML: | |
| """ | |
| HTML('<b>%s</b>') % value | |
| """ | |
| if not isinstance(value, tuple): | |
| value = (value,) | |
| value = tuple(html_escape(i) for i in value) | |
| return HTML(self.value % value) | |
| class HTMLFormatter(Formatter): | |
| def format_field(self, value: object, format_spec: str) -> str: | |
| return html_escape(format(value, format_spec)) | |
| def html_escape(text: object) -> str: | |
| # The string interpolation functions also take integers and other types. | |
| # Convert to string first. | |
| if not isinstance(text, str): | |
| text = f"{text}" | |
| return ( | |
| text.replace("&", "&") | |
| .replace("<", "<") | |
| .replace(">", ">") | |
| .replace('"', """) | |
| ) | |
| FORMATTER = HTMLFormatter() | |