From 71a038325855a718b6d2d0a16865613425e5e8c4 Mon Sep 17 00:00:00 2001 From: imSp4rky Date: Thu, 15 Oct 2026 17:36:04 -0600 Subject: [PATCH] fix(console): count spacing combining marks as one cell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rich measures Indic marks like ि as zero width, so the --list panel border drifted on Hindi, Telugu and Tamil labels. --- tests/core/test_console_cell_width.py | 24 ++++++++++++++++++++++++ unshackle/core/console.py | 15 +++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/core/test_console_cell_width.py diff --git a/tests/core/test_console_cell_width.py b/tests/core/test_console_cell_width.py new file mode 100644 index 00000000..5aa2ae1b --- /dev/null +++ b/tests/core/test_console_cell_width.py @@ -0,0 +1,24 @@ +"""Rich measures Indic spacing marks as one cell, so a panel border stays aligned after such a label.""" + +from __future__ import annotations + +import io + +from rich.cells import cell_len +from rich.console import Console +from rich.panel import Panel + +import unshackle.core.console # noqa: F401 # installs the cell width override + + +def test_spacing_marks_take_one_cell() -> None: + assert cell_len("हिंदी") == 4 # two Mc marks count, the Mn anusvara does not + assert cell_len("தமிழ்") == 4 + assert cell_len("ไทย") == 3 + + +def test_panel_pads_an_indic_label_to_the_border() -> None: + out = io.StringIO() + Console(file=out, width=20, color_system=None).print(Panel("हिंदी")) + + assert out.getvalue().splitlines()[1] == "│ हिंदी" + " " * 12 + " │" diff --git a/unshackle/core/console.py b/unshackle/core/console.py index 029995f1..843b2fb2 100644 --- a/unshackle/core/console.py +++ b/unshackle/core/console.py @@ -4,10 +4,13 @@ import logging import math import shutil import sys +import unicodedata from datetime import datetime +from functools import lru_cache from types import ModuleType from typing import IO, Any, Callable, Iterable, List, Literal, Mapping, Optional, TextIO, Union +import rich.cells from rich import box from rich._log_render import FormatTimeCallable, LogRender from rich.color import Color, blend_rgb @@ -414,6 +417,18 @@ def force_utf8_streams() -> None: force_utf8_streams() +_rich_cell_size = rich.cells.get_character_cell_size + + +@lru_cache(maxsize=4096) +def _cell_size(character: str, *args: str) -> int: + """Count a spacing combining mark (Mc, e.g. Devanagari ि) as one cell, as terminals draw it; Rich's table says 0.""" + return 1 if unicodedata.category(character) == "Mc" else _rich_cell_size(character, *args) + + +rich.cells.get_character_cell_size = _cell_size +rich.cells.cached_cell_len.cache_clear() + console = ComfyConsole( log_time=False, log_path=False,