Skip to content

Commit 12301e3

Browse files
authored
Merge pull request #3546 from Textualize/faster-cell-len
use sets
2 parents afcc5c5 + 02f3d14 commit 12301e3

File tree

1 file changed

+30
-25
lines changed

1 file changed

+30
-25
lines changed

rich/cells.py

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
from __future__ import annotations
22

3-
import re
43
from functools import lru_cache
54
from typing import Callable
65

76
from ._cell_widths import CELL_WIDTHS
87

9-
# Regex to match sequence of the most common character ranges
10-
_is_single_cell_widths = re.compile(
11-
"^[\u0020-\u007e\u00a0-\u02ff\u0370-\u0482\u2500-\u25FF]*$"
12-
).match
8+
# Ranges of unicode ordinals that produce a 1-cell wide character
9+
# This is non-exhaustive, but covers most common Western characters
10+
_SINGLE_CELL_UNICODE_RANGES: list[tuple[int, int]] = [
11+
(0x20, 0x7E), # Latin (excluding non-printable)
12+
(0xA0, 0xAC),
13+
(0xAE, 0x002FF),
14+
(0x00370, 0x00482), # Greek / Cyrillic
15+
(0x02500, 0x025FC), # Box drawing, box elements, geometric shapes
16+
(0x02800, 0x028FF), # Braille
17+
]
18+
19+
# A set of characters that are a single cell wide
20+
_SINGLE_CELLS = frozenset(
21+
[
22+
character
23+
for _start, _end in _SINGLE_CELL_UNICODE_RANGES
24+
for character in map(chr, range(_start, _end + 1))
25+
]
26+
)
27+
28+
# When called with a string this will return True if all
29+
# characters are single-cell, otherwise False
30+
_is_single_cell_widths: Callable[[str], bool] = _SINGLE_CELLS.issuperset
1331

1432

1533
@lru_cache(4096)
@@ -25,9 +43,9 @@ def cached_cell_len(text: str) -> int:
2543
Returns:
2644
int: Get the number of cells required to display text.
2745
"""
28-
_get_size = get_character_cell_size
29-
total_size = sum(_get_size(character) for character in text)
30-
return total_size
46+
if _is_single_cell_widths(text):
47+
return len(text)
48+
return sum(map(get_character_cell_size, text))
3149

3250

3351
def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> int:
@@ -41,9 +59,9 @@ def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> in
4159
"""
4260
if len(text) < 512:
4361
return _cell_len(text)
44-
_get_size = get_character_cell_size
45-
total_size = sum(_get_size(character) for character in text)
46-
return total_size
62+
if _is_single_cell_widths(text):
63+
return len(text)
64+
return sum(map(get_character_cell_size, text))
4765

4866

4967
@lru_cache(maxsize=4096)
@@ -56,20 +74,7 @@ def get_character_cell_size(character: str) -> int:
5674
Returns:
5775
int: Number of cells (0, 1 or 2) occupied by that character.
5876
"""
59-
return _get_codepoint_cell_size(ord(character))
60-
61-
62-
@lru_cache(maxsize=4096)
63-
def _get_codepoint_cell_size(codepoint: int) -> int:
64-
"""Get the cell size of a character.
65-
66-
Args:
67-
codepoint (int): Codepoint of a character.
68-
69-
Returns:
70-
int: Number of cells (0, 1 or 2) occupied by that character.
71-
"""
72-
77+
codepoint = ord(character)
7378
_table = CELL_WIDTHS
7479
lower_bound = 0
7580
upper_bound = len(_table) - 1

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy