Воркед
This commit is contained in:
1 parent
ac32c55ab9
commit
ee94d8e529
1138 files changed
+55771
-77901
No files matched your search
@@ -11,6 +11,7 @@ from typing import (
|
||||
List,
|
||||
NamedTuple,
|
||||
Optional,
|
||||
Pattern,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
@@ -38,6 +39,7 @@ DEFAULT_OVERFLOW: "OverflowMethod" = "fold"
|
||||
_re_whitespace = re.compile(r"\s+$")
|
||||
|
||||
TextType = Union[str, "Text"]
|
||||
"""A plain string or a :class:`Text` instance."""
|
||||
|
||||
GetStyleCallable = Callable[[str], Optional[StyleType]]
|
||||
|
||||
@@ -53,11 +55,7 @@ class Span(NamedTuple):
|
||||
"""Style associated with the span."""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Span({self.start}, {self.end}, {self.style!r})"
|
||||
if (isinstance(self.style, Style) and self.style._meta)
|
||||
else f"Span({self.start}, {self.end}, {repr(self.style)})"
|
||||
)
|
||||
return f"Span({self.start}, {self.end}, {self.style!r})"
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return self.end > self.start
|
||||
@@ -101,6 +99,21 @@ class Span(NamedTuple):
|
||||
return self
|
||||
return Span(start, min(offset, end), style)
|
||||
|
||||
def extend(self, cells: int) -> "Span":
|
||||
"""Extend the span by the given number of cells.
|
||||
|
||||
Args:
|
||||
cells (int): Additional space to add to end of span.
|
||||
|
||||
Returns:
|
||||
Span: A span.
|
||||
"""
|
||||
if cells:
|
||||
start, end, style = self
|
||||
return Span(start, end + cells, style)
|
||||
else:
|
||||
return self
|
||||
|
||||
|
||||
class Text(JupyterMixin):
|
||||
"""Text with color / style.
|
||||
@@ -112,7 +125,7 @@ class Text(JupyterMixin):
|
||||
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
|
||||
no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None.
|
||||
end (str, optional): Character to end text with. Defaults to "\\\\n".
|
||||
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to 8.
|
||||
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None.
|
||||
spans (List[Span], optional). A list of predefined style spans. Defaults to None.
|
||||
"""
|
||||
|
||||
@@ -137,7 +150,7 @@ class Text(JupyterMixin):
|
||||
overflow: Optional["OverflowMethod"] = None,
|
||||
no_wrap: Optional[bool] = None,
|
||||
end: str = "\n",
|
||||
tab_size: Optional[int] = 8,
|
||||
tab_size: Optional[int] = None,
|
||||
spans: Optional[List[Span]] = None,
|
||||
) -> None:
|
||||
sanitized_text = strip_control_codes(text)
|
||||
@@ -161,7 +174,7 @@ class Text(JupyterMixin):
|
||||
return self.plain
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<text {self.plain!r} {self._spans!r}>"
|
||||
return f"<text {self.plain!r} {self._spans!r} {self.style!r}>"
|
||||
|
||||
def __add__(self, other: Any) -> "Text":
|
||||
if isinstance(other, (str, Text)):
|
||||
@@ -259,7 +272,9 @@ class Text(JupyterMixin):
|
||||
|
||||
Args:
|
||||
text (str): A string containing console markup.
|
||||
style (Union[str, Style], optional): Base style for text. Defaults to "".
|
||||
emoji (bool, optional): Also render emoji code. Defaults to True.
|
||||
emoji_variant (str, optional): Optional emoji variant, either "text" or "emoji". Defaults to None.
|
||||
justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None.
|
||||
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
|
||||
end (str, optional): Character to end text with. Defaults to "\\\\n".
|
||||
@@ -296,7 +311,7 @@ class Text(JupyterMixin):
|
||||
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
|
||||
no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None.
|
||||
end (str, optional): Character to end text with. Defaults to "\\\\n".
|
||||
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to 8.
|
||||
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None.
|
||||
"""
|
||||
from .ansi import AnsiDecoder
|
||||
|
||||
@@ -357,8 +372,9 @@ class Text(JupyterMixin):
|
||||
style (Union[str, Style], optional): Base style for text. Defaults to "".
|
||||
justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None.
|
||||
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
|
||||
no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None.
|
||||
end (str, optional): Character to end text with. Defaults to "\\\\n".
|
||||
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to 8.
|
||||
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None.
|
||||
meta (Dict[str, Any], optional). Meta data to apply to text, or None for no meta data. Default to None
|
||||
|
||||
Returns:
|
||||
@@ -412,7 +428,7 @@ class Text(JupyterMixin):
|
||||
self._spans = spans[:]
|
||||
|
||||
def blank_copy(self, plain: str = "") -> "Text":
|
||||
"""Return a new Text instance with copied meta data (but not the string or spans)."""
|
||||
"""Return a new Text instance with copied metadata (but not the string or spans)."""
|
||||
copy_self = Text(
|
||||
plain,
|
||||
style=self.style,
|
||||
@@ -450,7 +466,6 @@ class Text(JupyterMixin):
|
||||
style (Union[str, Style]): Style instance or style definition to apply.
|
||||
start (int): Start offset (negative indexing is supported). Defaults to 0.
|
||||
end (Optional[int], optional): End offset (negative indexing is supported), or None for end of text. Defaults to None.
|
||||
|
||||
"""
|
||||
if style:
|
||||
length = len(self)
|
||||
@@ -465,10 +480,36 @@ class Text(JupyterMixin):
|
||||
return
|
||||
self._spans.append(Span(start, min(length, end), style))
|
||||
|
||||
def stylize_before(
|
||||
self,
|
||||
style: Union[str, Style],
|
||||
start: int = 0,
|
||||
end: Optional[int] = None,
|
||||
) -> None:
|
||||
"""Apply a style to the text, or a portion of the text. Styles will be applied before other styles already present.
|
||||
|
||||
Args:
|
||||
style (Union[str, Style]): Style instance or style definition to apply.
|
||||
start (int): Start offset (negative indexing is supported). Defaults to 0.
|
||||
end (Optional[int], optional): End offset (negative indexing is supported), or None for end of text. Defaults to None.
|
||||
"""
|
||||
if style:
|
||||
length = len(self)
|
||||
if start < 0:
|
||||
start = length + start
|
||||
if end is None:
|
||||
end = length
|
||||
if end < 0:
|
||||
end = length + end
|
||||
if start >= length or end <= start:
|
||||
# Span not in text or not valid
|
||||
return
|
||||
self._spans.insert(0, Span(start, min(length, end), style))
|
||||
|
||||
def apply_meta(
|
||||
self, meta: Dict[str, Any], start: int = 0, end: Optional[int] = None
|
||||
) -> None:
|
||||
"""Apply meta data to the text, or a portion of the text.
|
||||
"""Apply metadata to the text, or a portion of the text.
|
||||
|
||||
Args:
|
||||
meta (Dict[str, Any]): A dict of meta information.
|
||||
@@ -528,9 +569,30 @@ class Text(JupyterMixin):
|
||||
style += get_style(span_style, default="")
|
||||
return style
|
||||
|
||||
def extend_style(self, spaces: int) -> None:
|
||||
"""Extend the Text given number of spaces where the spaces have the same style as the last character.
|
||||
|
||||
Args:
|
||||
spaces (int): Number of spaces to add to the Text.
|
||||
"""
|
||||
if spaces <= 0:
|
||||
return
|
||||
spans = self.spans
|
||||
new_spaces = " " * spaces
|
||||
if spans:
|
||||
end_offset = len(self)
|
||||
self._spans[:] = [
|
||||
span.extend(spaces) if span.end >= end_offset else span
|
||||
for span in spans
|
||||
]
|
||||
self._text.append(new_spaces)
|
||||
self._length += spaces
|
||||
else:
|
||||
self.plain += new_spaces
|
||||
|
||||
def highlight_regex(
|
||||
self,
|
||||
re_highlight: str,
|
||||
re_highlight: Union[Pattern[str], str],
|
||||
style: Optional[Union[GetStyleCallable, StyleType]] = None,
|
||||
*,
|
||||
style_prefix: str = "",
|
||||
@@ -539,7 +601,7 @@ class Text(JupyterMixin):
|
||||
translated to styles.
|
||||
|
||||
Args:
|
||||
re_highlight (str): A regular expression.
|
||||
re_highlight (Union[re.Pattern, str]): A regular expression object or string.
|
||||
style (Union[GetStyleCallable, StyleType]): Optional style to apply to whole match, or a callable
|
||||
which accepts the matched text and returns a style. Defaults to None.
|
||||
style_prefix (str, optional): Optional prefix to add to style group names.
|
||||
@@ -551,7 +613,9 @@ class Text(JupyterMixin):
|
||||
append_span = self._spans.append
|
||||
_Span = Span
|
||||
plain = self.plain
|
||||
for match in re.finditer(re_highlight, plain):
|
||||
if isinstance(re_highlight, str):
|
||||
re_highlight = re.compile(re_highlight)
|
||||
for match in re_highlight.finditer(plain):
|
||||
get_span = match.span
|
||||
if style:
|
||||
start, end = get_span()
|
||||
@@ -576,9 +640,9 @@ class Text(JupyterMixin):
|
||||
"""Highlight words with a style.
|
||||
|
||||
Args:
|
||||
words (Iterable[str]): Worlds to highlight.
|
||||
words (Iterable[str]): Words to highlight.
|
||||
style (Union[str, Style]): Style to apply.
|
||||
case_sensitive (bool, optional): Enable case sensitive matchings. Defaults to True.
|
||||
case_sensitive (bool, optional): Enable case sensitive matching. Defaults to True.
|
||||
|
||||
Returns:
|
||||
int: Number of words highlighted.
|
||||
@@ -625,7 +689,7 @@ class Text(JupyterMixin):
|
||||
def __rich_console__(
|
||||
self, console: "Console", options: "ConsoleOptions"
|
||||
) -> Iterable[Segment]:
|
||||
tab_size: int = console.tab_size or self.tab_size or 8
|
||||
tab_size: int = console.tab_size if self.tab_size is None else self.tab_size
|
||||
justify = self.justify or options.justify or DEFAULT_JUSTIFY
|
||||
|
||||
overflow = self.overflow or options.overflow or DEFAULT_OVERFLOW
|
||||
@@ -760,27 +824,35 @@ class Text(JupyterMixin):
|
||||
"""
|
||||
if "\t" not in self.plain:
|
||||
return
|
||||
pos = 0
|
||||
if tab_size is None:
|
||||
tab_size = self.tab_size
|
||||
assert tab_size is not None
|
||||
result = self.blank_copy()
|
||||
append = result.append
|
||||
if tab_size is None:
|
||||
tab_size = 8
|
||||
|
||||
new_text: List[Text] = []
|
||||
append = new_text.append
|
||||
|
||||
_style = self.style
|
||||
for line in self.split("\n", include_separator=True):
|
||||
parts = line.split("\t", include_separator=True)
|
||||
for part in parts:
|
||||
if part.plain.endswith("\t"):
|
||||
part._text = [part.plain[:-1] + " "]
|
||||
append(part)
|
||||
pos += len(part)
|
||||
spaces = tab_size - ((pos - 1) % tab_size) - 1
|
||||
if spaces:
|
||||
append(" " * spaces, _style)
|
||||
pos += spaces
|
||||
else:
|
||||
if "\t" not in line.plain:
|
||||
append(line)
|
||||
else:
|
||||
cell_position = 0
|
||||
parts = line.split("\t", include_separator=True)
|
||||
for part in parts:
|
||||
if part.plain.endswith("\t"):
|
||||
part._text[-1] = part._text[-1][:-1] + " "
|
||||
cell_position += part.cell_len
|
||||
tab_remainder = cell_position % tab_size
|
||||
if tab_remainder:
|
||||
spaces = tab_size - tab_remainder
|
||||
part.extend_style(spaces)
|
||||
cell_position += spaces
|
||||
else:
|
||||
cell_position += part.cell_len
|
||||
append(part)
|
||||
|
||||
result = Text("").join(new_text)
|
||||
|
||||
self._text = [result.plain]
|
||||
self._length = len(self.plain)
|
||||
self._spans[:] = result._spans
|
||||
@@ -831,6 +903,7 @@ class Text(JupyterMixin):
|
||||
|
||||
Args:
|
||||
count (int): Width of padding.
|
||||
character (str): The character to pad with. Must be a string of length 1.
|
||||
"""
|
||||
assert len(character) == 1, "Character must be a string of length 1"
|
||||
if count:
|
||||
@@ -911,7 +984,7 @@ class Text(JupyterMixin):
|
||||
self._text.append(sanitized_text)
|
||||
offset = len(self)
|
||||
text_length = len(sanitized_text)
|
||||
if style is not None:
|
||||
if style:
|
||||
self._spans.append(Span(offset, offset + text_length, style))
|
||||
self._length += text_length
|
||||
elif isinstance(text, Text):
|
||||
@@ -921,14 +994,14 @@ class Text(JupyterMixin):
|
||||
"style must not be set when appending Text instance"
|
||||
)
|
||||
text_length = self._length
|
||||
if text.style is not None:
|
||||
if text.style:
|
||||
self._spans.append(
|
||||
_Span(text_length, text_length + len(text), text.style)
|
||||
)
|
||||
self._text.append(text.plain)
|
||||
self._spans.extend(
|
||||
_Span(start + text_length, end + text_length, style)
|
||||
for start, end, style in text._spans
|
||||
for start, end, style in text._spans.copy()
|
||||
)
|
||||
self._length += len(text)
|
||||
return self
|
||||
@@ -937,17 +1010,20 @@ class Text(JupyterMixin):
|
||||
"""Append another Text instance. This method is more performant that Text.append, but
|
||||
only works for Text.
|
||||
|
||||
Args:
|
||||
text (Text): The Text instance to append to this instance.
|
||||
|
||||
Returns:
|
||||
Text: Returns self for chaining.
|
||||
"""
|
||||
_Span = Span
|
||||
text_length = self._length
|
||||
if text.style is not None:
|
||||
if text.style:
|
||||
self._spans.append(_Span(text_length, text_length + len(text), text.style))
|
||||
self._text.append(text.plain)
|
||||
self._spans.extend(
|
||||
_Span(start + text_length, end + text_length, style)
|
||||
for start, end, style in text._spans
|
||||
for start, end, style in text._spans.copy()
|
||||
)
|
||||
self._length += len(text)
|
||||
return self
|
||||
@@ -958,7 +1034,7 @@ class Text(JupyterMixin):
|
||||
"""Append iterable of str and style. Style may be a Style instance or a str style definition.
|
||||
|
||||
Args:
|
||||
pairs (Iterable[Tuple[str, Optional[StyleType]]]): An iterable of tuples containing str content and style.
|
||||
tokens (Iterable[Tuple[str, Optional[StyleType]]]): An iterable of tuples containing str content and style.
|
||||
|
||||
Returns:
|
||||
Text: Returns self for chaining.
|
||||
@@ -968,8 +1044,9 @@ class Text(JupyterMixin):
|
||||
_Span = Span
|
||||
offset = len(self)
|
||||
for content, style in tokens:
|
||||
content = strip_control_codes(content)
|
||||
append_text(content)
|
||||
if style is not None:
|
||||
if style:
|
||||
append_span(_Span(offset, offset + len(content), style))
|
||||
offset += len(content)
|
||||
self._length = offset
|
||||
@@ -1067,7 +1144,6 @@ class Text(JupyterMixin):
|
||||
_Span = Span
|
||||
|
||||
for span_start, span_end, style in self._spans:
|
||||
|
||||
lower_bound = 0
|
||||
upper_bound = line_count
|
||||
start_line_no = (lower_bound + upper_bound) // 2
|
||||
@@ -1137,8 +1213,7 @@ class Text(JupyterMixin):
|
||||
|
||||
Args:
|
||||
console (Console): Console instance.
|
||||
width (int): Number of characters per line.
|
||||
emoji (bool, optional): Also render emoji code. Defaults to True.
|
||||
width (int): Number of cells available per line.
|
||||
justify (str, optional): Justify method: "default", "left", "center", "full", "right". Defaults to "default".
|
||||
overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None.
|
||||
tab_size (int, optional): Default tab size. Defaults to 8.
|
||||
@@ -1179,7 +1254,7 @@ class Text(JupyterMixin):
|
||||
width (int): Maximum characters in a line.
|
||||
|
||||
Returns:
|
||||
Lines: List of lines.
|
||||
Lines: Lines container.
|
||||
"""
|
||||
lines: Lines = Lines()
|
||||
append = lines.append
|
||||
|
||||
Reference in new issue
Block a user