Unify terminal display-width helpers
key_help, selector and control each carried their own East Asian width and truncation logic with slightly different rules, and cli clipped tmux labels by code point, so a CJK display name ran twice as wide as an ASCII one before its ellipsis appeared. Move the cell-width helpers into herdr_hub.text, make truncate_label cell-aware, and sanitise control characters before curses draws a row so an escape sequence in a remote error cannot be rendered as ^[ and misalign the list. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+4
-33
@@ -3,7 +3,8 @@ from __future__ import annotations
|
||||
|
||||
import curses
|
||||
from dataclasses import dataclass
|
||||
import unicodedata
|
||||
|
||||
from .text import pad_display, truncate_display
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -48,36 +49,6 @@ KEY_SECTIONS: tuple[tuple[str, tuple[KeyMapping, ...]], ...] = (
|
||||
)
|
||||
|
||||
|
||||
def display_width(value: str) -> int:
|
||||
return sum(
|
||||
0
|
||||
if unicodedata.combining(character)
|
||||
else 2
|
||||
if unicodedata.east_asian_width(character) in {"W", "F"}
|
||||
else 1
|
||||
for character in value
|
||||
)
|
||||
|
||||
|
||||
def truncate(value: str, width: int) -> str:
|
||||
if width <= 0:
|
||||
return ""
|
||||
result = ""
|
||||
used = 0
|
||||
for character in value:
|
||||
size = display_width(character)
|
||||
if used + size > width:
|
||||
break
|
||||
result += character
|
||||
used += size
|
||||
return result
|
||||
|
||||
|
||||
def pad(value: str, width: int) -> str:
|
||||
clipped = truncate(value, width)
|
||||
return clipped + " " * max(0, width - display_width(clipped))
|
||||
|
||||
|
||||
class KeyHelpPopup:
|
||||
def __init__(self) -> None:
|
||||
self.scroll = 0
|
||||
@@ -95,7 +66,7 @@ class KeyHelpPopup:
|
||||
if wide:
|
||||
lines.append(
|
||||
(
|
||||
f" {pad(mapping.keys, key_width)} {mapping.action}",
|
||||
f" {pad_display(mapping.keys, key_width)} {mapping.action}",
|
||||
curses.A_NORMAL,
|
||||
)
|
||||
)
|
||||
@@ -172,6 +143,6 @@ class KeyHelpPopup:
|
||||
if y < 0 or y >= height or x >= width:
|
||||
return
|
||||
try:
|
||||
screen.addstr(y, x, truncate(value, max(0, width - x - 1)), attribute)
|
||||
screen.addstr(y, x, truncate_display(value, max(0, width - x - 1)), attribute)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user