mirror of https://github.com/Textualize/rich.git
Replacing some uses of cell_len with Cells.measure
This commit is contained in:
parent
d4450d9e43
commit
6139a0a6f3
|
@ -7,7 +7,6 @@ repos:
|
|||
- id: check-ast
|
||||
- id: check-builtin-literals
|
||||
- id: check-case-conflict
|
||||
- id: check-docstring-first
|
||||
- id: check-merge-conflict
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
|
|
|
@ -33,6 +33,7 @@ pygments = "^2.6.0"
|
|||
commonmark = "^0.9.0"
|
||||
colorama = "^0.4.0"
|
||||
ipywidgets = { version = "^7.5.1", optional = true }
|
||||
cells = { path = "../cells/" }
|
||||
|
||||
|
||||
[tool.poetry.extras]
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import re
|
||||
from typing import Iterable, List, Tuple
|
||||
|
||||
from .cells import cell_len, chop_cells
|
||||
from cells.core import Cells
|
||||
|
||||
from ._loop import loop_last
|
||||
from .cells import cell_len, chop_cells
|
||||
|
||||
re_word = re.compile(r"\s*\S+\s*")
|
||||
|
||||
|
@ -17,13 +19,13 @@ def words(text: str) -> Iterable[Tuple[int, int, str]]:
|
|||
word_match = re_word.match(text, end)
|
||||
|
||||
|
||||
def divide_line(text: str, width: int, fold: bool = True) -> List[int]:
|
||||
def divide_line(text: str, width: int, cells: Cells, fold: bool = True) -> List[int]:
|
||||
divides: List[int] = []
|
||||
append = divides.append
|
||||
line_position = 0
|
||||
_cell_len = cell_len
|
||||
_cell_width = cells.measure
|
||||
for start, _end, word in words(text):
|
||||
word_length = _cell_len(word.rstrip())
|
||||
word_length = _cell_width(word.rstrip())
|
||||
if line_position + word_length > width:
|
||||
if word_length > width:
|
||||
if fold:
|
||||
|
@ -31,19 +33,19 @@ def divide_line(text: str, width: int, fold: bool = True) -> List[int]:
|
|||
chop_cells(word, width, position=line_position)
|
||||
):
|
||||
if last:
|
||||
line_position = _cell_len(line)
|
||||
line_position = _cell_width(line)
|
||||
else:
|
||||
start += len(line)
|
||||
append(start)
|
||||
else:
|
||||
if start:
|
||||
append(start)
|
||||
line_position = _cell_len(word)
|
||||
line_position = _cell_width(word)
|
||||
elif line_position and start:
|
||||
append(start)
|
||||
line_position = _cell_len(word)
|
||||
line_position = _cell_width(word)
|
||||
else:
|
||||
line_position += _cell_len(word)
|
||||
line_position += _cell_width(word)
|
||||
return divides
|
||||
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ from getpass import getpass
|
|||
from html import escape
|
||||
from inspect import isclass
|
||||
from itertools import islice
|
||||
from time import monotonic
|
||||
from threading import RLock
|
||||
from types import FrameType, TracebackType, ModuleType
|
||||
from time import monotonic
|
||||
from types import FrameType, ModuleType, TracebackType
|
||||
from typing import (
|
||||
IO,
|
||||
TYPE_CHECKING,
|
||||
|
@ -32,6 +32,8 @@ from typing import (
|
|||
cast,
|
||||
)
|
||||
|
||||
from cells.core import Cells
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal, Protocol, runtime_checkable
|
||||
else:
|
||||
|
@ -71,6 +73,25 @@ if TYPE_CHECKING:
|
|||
|
||||
WINDOWS = platform.system() == "Windows"
|
||||
|
||||
DEFAULT_UNICODE_VERSION = "9.0.0"
|
||||
UnicodeVersion = Literal[
|
||||
"4.1.0",
|
||||
"5.0.0",
|
||||
"5.1.0",
|
||||
"5.2.0",
|
||||
"6.0.0",
|
||||
"6.1.0",
|
||||
"6.2.0",
|
||||
"6.3.0",
|
||||
"7.0.0",
|
||||
"8.0.0",
|
||||
"9.0.0",
|
||||
"10.0.0",
|
||||
"11.0.0",
|
||||
"12.0.0",
|
||||
"12.1.0",
|
||||
"13.0.0",
|
||||
]
|
||||
HighlighterType = Callable[[Union[str, "Text"]], "Text"]
|
||||
JustifyMethod = Literal["default", "left", "center", "right", "full"]
|
||||
OverflowMethod = Literal["fold", "crop", "ellipsis", "ignore"]
|
||||
|
@ -616,6 +637,10 @@ class Console:
|
|||
get_datetime (Callable[[], datetime], optional): Callable that gets the current time as a datetime.datetime object (used by Console.log),
|
||||
or None for datetime.now.
|
||||
get_time (Callable[[], time], optional): Callable that gets the current time in seconds, default uses time.monotonic.
|
||||
unicode_version (UnicodeVersion, optional): Version of the Unicode database to use.
|
||||
If ``None``, the default ``"9.0.0"`` will be used.
|
||||
cells (Cells, optional): ``Cells`` instance to use for character cell width measurement. If ``None``, Rich will instantiate
|
||||
``Cell`` internally using the specified ``unicode_version``.
|
||||
"""
|
||||
|
||||
_environ: Mapping[str, str] = os.environ
|
||||
|
@ -652,6 +677,8 @@ class Console:
|
|||
safe_box: bool = True,
|
||||
get_datetime: Optional[Callable[[], datetime]] = None,
|
||||
get_time: Optional[Callable[[], float]] = None,
|
||||
unicode_version: Optional[UnicodeVersion] = DEFAULT_UNICODE_VERSION,
|
||||
cells: Optional[Cells] = None,
|
||||
_environ: Optional[Mapping[str, str]] = None,
|
||||
):
|
||||
# Copy of os.environ allows us to replace it for testing
|
||||
|
@ -713,6 +740,7 @@ class Console:
|
|||
self.safe_box = safe_box
|
||||
self.get_datetime = get_datetime or datetime.now
|
||||
self.get_time = get_time or monotonic
|
||||
self.cells = cells or Cells(unicode_version or DEFAULT_UNICODE_VERSION)
|
||||
self.style = style
|
||||
self.no_color = (
|
||||
no_color if no_color is not None else "NO_COLOR" in self._environ
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
from itertools import zip_longest
|
||||
from typing import (
|
||||
Iterator,
|
||||
TYPE_CHECKING,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
TypeVar,
|
||||
TYPE_CHECKING,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -21,7 +21,6 @@ if TYPE_CHECKING:
|
|||
)
|
||||
from .text import Text
|
||||
|
||||
from .cells import cell_len
|
||||
from .measure import Measurement
|
||||
|
||||
T = TypeVar("T")
|
||||
|
@ -126,6 +125,7 @@ class Lines:
|
|||
"""
|
||||
from .text import Text
|
||||
|
||||
_cell_width = console.cells.measure
|
||||
if justify == "left":
|
||||
for line in self._lines:
|
||||
line.truncate(width, overflow=overflow, pad=True)
|
||||
|
@ -133,19 +133,19 @@ class Lines:
|
|||
for line in self._lines:
|
||||
line.rstrip()
|
||||
line.truncate(width, overflow=overflow)
|
||||
line.pad_left((width - cell_len(line.plain)) // 2)
|
||||
line.pad_right(width - cell_len(line.plain))
|
||||
line.pad_left((width - _cell_width(line.plain)) // 2)
|
||||
line.pad_right(width - _cell_width(line.plain))
|
||||
elif justify == "right":
|
||||
for line in self._lines:
|
||||
line.rstrip()
|
||||
line.truncate(width, overflow=overflow)
|
||||
line.pad_left(width - cell_len(line.plain))
|
||||
line.pad_left(width - _cell_width(line.plain))
|
||||
elif justify == "full":
|
||||
for line_index, line in enumerate(self._lines):
|
||||
if line_index == len(self._lines) - 1:
|
||||
break
|
||||
words = line.split(" ")
|
||||
words_size = sum(cell_len(word.plain) for word in words)
|
||||
words_size = sum(_cell_width(word.plain) for word in words)
|
||||
num_spaces = len(words) - 1
|
||||
spaces = [1 for _ in range(num_spaces)]
|
||||
index = 0
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
import builtins
|
||||
import dataclasses
|
||||
import os
|
||||
from rich.repr import RichReprResult
|
||||
import re
|
||||
import sys
|
||||
from array import array
|
||||
from collections import Counter, defaultdict, deque, UserDict, UserList
|
||||
import dataclasses
|
||||
from collections import Counter, UserDict, UserList, defaultdict, deque
|
||||
from dataclasses import dataclass, fields, is_dataclass
|
||||
from inspect import isclass
|
||||
from itertools import islice
|
||||
import re
|
||||
from types import MappingProxyType
|
||||
from typing import (
|
||||
DefaultDict,
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
DefaultDict,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
Optional,
|
||||
Set,
|
||||
Union,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
from types import MappingProxyType
|
||||
|
||||
from cells.core import Cells
|
||||
|
||||
from rich.repr import RichReprResult
|
||||
|
||||
try:
|
||||
import attr as _attr_module
|
||||
|
@ -30,12 +33,10 @@ except ImportError: # pragma: no cover
|
|||
_attr_module = None # type: ignore
|
||||
|
||||
|
||||
from .highlighter import ReprHighlighter
|
||||
from . import get_console
|
||||
from ._loop import loop_last
|
||||
from ._pick import pick_bool
|
||||
from .abc import RichRenderable
|
||||
from .cells import cell_len
|
||||
from .highlighter import ReprHighlighter
|
||||
from .jupyter import JupyterMixin, JupyterRenderable
|
||||
from .measure import Measurement
|
||||
|
@ -278,8 +279,11 @@ class Pretty(JupyterMixin):
|
|||
max_length=self.max_length,
|
||||
max_string=self.max_string,
|
||||
)
|
||||
_cell_width = console.cells.measure
|
||||
text_width = (
|
||||
max(cell_len(line) for line in pretty_str.splitlines()) if pretty_str else 0
|
||||
max(_cell_width(line) for line in pretty_str.splitlines())
|
||||
if pretty_str
|
||||
else 0
|
||||
)
|
||||
return Measurement(text_width, text_width)
|
||||
|
||||
|
@ -339,6 +343,10 @@ class Node:
|
|||
children: Optional[List["Node"]] = None
|
||||
key_separator = ": "
|
||||
separator: str = ", "
|
||||
cells: Optional[Cells] = None
|
||||
|
||||
def __post_init__(self):
|
||||
self.cells = self.cells or Cells()
|
||||
|
||||
def iter_tokens(self) -> Iterable[str]:
|
||||
"""Generate tokens for this node."""
|
||||
|
@ -373,8 +381,9 @@ class Node:
|
|||
bool: True if the node can be rendered within max length, otherwise False.
|
||||
"""
|
||||
total_length = start_length
|
||||
_cell_width = self.cells.measure
|
||||
for token in self.iter_tokens():
|
||||
total_length += cell_len(token)
|
||||
total_length += _cell_width(token)
|
||||
if total_length > max_length:
|
||||
return False
|
||||
return True
|
||||
|
@ -401,7 +410,7 @@ class Node:
|
|||
while line_no < len(lines):
|
||||
line = lines[line_no]
|
||||
if line.expandable and not line.expanded:
|
||||
if expand_all or not line.check_length(max_width):
|
||||
if expand_all or not line.check_length(max_width, self.cells):
|
||||
lines[line_no : line_no + 1] = line.expand(indent_size)
|
||||
line_no += 1
|
||||
|
||||
|
@ -427,10 +436,11 @@ class _Line:
|
|||
"""Check if the line may be expanded."""
|
||||
return bool(self.node is not None and self.node.children)
|
||||
|
||||
def check_length(self, max_length: int) -> bool:
|
||||
def check_length(self, max_length: int, cells: Cells) -> bool:
|
||||
"""Check this line fits within a given number of cells."""
|
||||
_cell_width = cells.measure
|
||||
start_length = (
|
||||
len(self.whitespace) + cell_len(self.text) + cell_len(self.suffix)
|
||||
len(self.whitespace) + _cell_width(self.text) + _cell_width(self.suffix)
|
||||
)
|
||||
assert self.node is not None
|
||||
return self.node.check_length(start_length, max_length)
|
||||
|
|
|
@ -2,7 +2,6 @@ import re
|
|||
from functools import partial, reduce
|
||||
from math import gcd
|
||||
from operator import itemgetter
|
||||
from rich.emoji import EmojiVariant
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
|
@ -16,6 +15,8 @@ from typing import (
|
|||
Union,
|
||||
)
|
||||
|
||||
from rich.emoji import EmojiVariant
|
||||
|
||||
from ._loop import loop_last
|
||||
from ._pick import pick_bool
|
||||
from ._wrap import divide_line
|
||||
|
@ -1148,6 +1149,7 @@ class Text(JupyterMixin):
|
|||
|
||||
no_wrap = pick_bool(no_wrap, self.no_wrap, False) or overflow == "ignore"
|
||||
|
||||
cells = console.cells
|
||||
lines = Lines()
|
||||
for line in self.split(allow_blank=True):
|
||||
if "\t" in line:
|
||||
|
@ -1155,7 +1157,9 @@ class Text(JupyterMixin):
|
|||
if no_wrap:
|
||||
new_lines = Lines([line])
|
||||
else:
|
||||
offsets = divide_line(str(line), width, fold=wrap_overflow == "fold")
|
||||
offsets = divide_line(
|
||||
str(line), width, cells, fold=wrap_overflow == "fold"
|
||||
)
|
||||
new_lines = line.divide(offsets)
|
||||
for line in new_lines:
|
||||
line.rstrip_end(width)
|
||||
|
|
Loading…
Reference in New Issue