Skip to content

Commit 7635ba9

Browse files
committed
wcwidth>=0.3 integration with iter_graphemes()
1 parent 0752ff0 commit 7635ba9

35 files changed

+175
-12239
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [14.3.3] - 2026-02-02
9+
10+
- Fixed width of more emojis and languages with new runtime module dependency wcwidth, https://github.com/Textualize/rich/pull/XXX
11+
812
## [14.3.2] - 2026-02-01
913

1014
### Fixed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,4 @@ The following people have contributed to the development of Rich:
100100
- [Brandon Capener](https://github.com/bcapener)
101101
- [Alex Zheng](https://github.com/alexzheng111)
102102
- [Sebastian Speitel](https://github.com/SebastianSpeitel)
103+
- [Jeff Quast](https://github.com/jquast)

FAQ.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,9 @@ See the docs on [console markup](https://rich.readthedocs.io/en/latest/markup.ht
100100
<a name="why-does-emoji-break-alignment-in-a-table-or-panel"></a>
101101
## Why does emoji break alignment in a Table or Panel?
102102

103-
Certain emoji take up double space within the terminal. Unfortunately, terminals don't always agree how wide a given character should be.
103+
Rich uses python wcwidth for character width measurement, which follows a [specification](https://wcwidth.readthedocs.io/en/latest/specs.html) that includes support for complex emoji and languages (grapheme clustering).
104104

105-
Rich has no way of knowing how wide a character will be on any given terminal. This can break alignment in containers like Table and Panel, where Rich needs to know the width of the content.
106-
107-
There are also *multiple codepoints* characters, such as country flags, and emoji modifiers, which produce wildly different results across terminal emulators.
108-
109-
Fortunately, most characters will work just fine. But you may have to avoid using the emojis that break alignment. You will get good results if you stick to emoji released on or before version 9 of the Unicode database,
105+
Although *all* terminals do not fully support complex emoji, Rich support matches the correct presentation of many actively developed terminal emulators, tabulated and reported as [ucs-detect results](https://ucs-detect.readthedocs.io/results.html).
110106

111107
<hr>
112108

examples/emoji.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""
2+
Demonstrates emoji, grapheme clusters, and multilingual text in tables and panels.
3+
4+
Useful for visually testing terminal Unicode support.
5+
"""
6+
7+
from rich.console import Console
8+
from rich.panel import Panel
9+
from rich.table import Table
10+
11+
console = Console()
12+
13+
# Emoji and grapheme cluster table
14+
table = Table(title="Emoji & Grapheme Clusters")
15+
table.add_column("Type", style="cyan")
16+
table.add_column("Example", justify="center")
17+
table.add_column("Codepoints", style="dim")
18+
19+
table.add_row(
20+
"ZWJ Family",
21+
"\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466",
22+
"4 emoji + 3 ZWJ",
23+
)
24+
table.add_row("Skin Tone", "\U0001F44B\U0001F3FD", "wave + modifier")
25+
table.add_row(
26+
"Flags",
27+
"\U0001F1FA\U0001F1F8 \U0001F1EC\U0001F1E7 \U0001F1EF\U0001F1F5",
28+
"regional indicators",
29+
)
30+
table.add_row(
31+
"VS16 Emoji", "\u2764\uFE0F \u2728 \u267B\uFE0F \u2615", "with variation selectors"
32+
)
33+
table.add_row(
34+
"Keycap", "1\uFE0F\u20E3 2\uFE0F\u20E3 #\uFE0F\u20E3", "digit + VS16 + combining"
35+
)
36+
table.add_row("Combining", "e\u0301 n\u0303 u\u0308", "base + combining accent")
37+
table.add_row("CJK", "\u5bcc\u58eb\u5c71 \u6771\u4eac", "wide characters")
38+
39+
console.print(table, justify="center")
40+
console.print()
41+
42+
# Multilingual panel (UDHR Article 1 excerpts)
43+
text = (
44+
"[bold]Universal Declaration of Human Rights, Article 1[/]\n\n"
45+
"[cyan]English:[/] All human beings are born free and equal in dignity.\n"
46+
"[cyan]Arabic:[/] \u064A\u0648\u0644\u062F \u062C\u0645\u064A\u0639"
47+
" \u0627\u0644\u0646\u0627\u0633 \u0623\u062D\u0631\u0627\u0631\u0627\n"
48+
"[cyan]Hindi:[/] \u0938\u092D\u0940 \u092E\u0928\u0941\u0937\u094D\u092F\u094B\u0902"
49+
" \u0915\u094B \u0917\u094C\u0930\u0935 \u0914\u0930"
50+
" \u0905\u0927\u093F\u0915\u093E\u0930\u094B\u0902\n"
51+
"[cyan]Thai:[/] \u0E21\u0E19\u0E38\u0E29\u0E22\u0E4C\u0E17\u0E31\u0E49\u0E07"
52+
"\u0E2B\u0E25\u0E32\u0E22\u0E40\u0E01\u0E34\u0E14\u0E21\u0E32\n"
53+
"[cyan]Japanese:[/] \u3059\u3079\u3066\u306E\u4EBA\u9593\u306F\u3001"
54+
"\u751F\u307E\u308C\u306A\u304C\u3089\u306B\u3057\u3066\n"
55+
"[cyan]Korean:[/] \ubaa8\ub4e0 \uc0ac\ub78c\uc740 \ud0dc\uc5b4\ub0a0 "
56+
"\ub54c\ubd80\ud130 \uc790\uc720\ub85c\uc6b0\uba70\n"
57+
"[cyan]Tibetan:[/] \u0F66\u0F90\u0FB1\u0F7A\u0F0B\u0F56\u0F7C\u0F0B"
58+
"\u0F58\u0F72\u0F0B\u0F62\u0F72\u0F42\u0F66\u0F0B\u0F40\u0F72"
59+
)
60+
console.print(Panel(text, title="\U0001F30D Languages", border_style="blue"))

poetry.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ include = ["rich/py.typed"]
3030
[tool.poetry.dependencies]
3131
python = ">=3.8.0"
3232
pygments = "^2.13.0"
33+
wcwidth = ">=0.5.3"
3334
ipywidgets = { version = ">=7.5.1,<9", optional = true }
3435
markdown-it-py = ">=2.2.0"
3536

questions/emoji_broken.question.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
title: "Why does emoji break alignment in a Table or Panel?"
33
---
44

5-
Certain emoji take up double space within the terminal. Unfortunately, terminals don't always agree how wide a given character should be.
5+
Rich uses python wcwidth for character width measurement, which follows a [specification](https://wcwidth.readthedocs.io/en/latest/specs.html) that includes support for complex emoji and languages (grapheme clustering).
66

7-
Rich has no way of knowing how wide a character will be on any given terminal. This can break alignment in containers like Table and Panel, where Rich needs to know the width of the content.
8-
9-
There are also *multiple codepoints* characters, such as country flags, and emoji modifiers, which produce wildly different results across terminal emulators.
10-
11-
Fortunately, most characters will work just fine. But you may have to avoid using the emojis that break alignment. You will get good results if you stick to emoji released on or before version 9 of the Unicode database,
7+
Although *all* terminals do not fully support complex emoji, Rich support matches the correct presentation of many actively developed terminal emulators, tabulated and reported as [ucs-detect results](https://ucs-detect.readthedocs.io/results.html).

rich/_unicode_data/__init__.py

Lines changed: 0 additions & 93 deletions
This file was deleted.

rich/_unicode_data/_versions.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)