wcwidth 0.7.0__tar.gz → 0.8.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wcwidth-0.7.0 → wcwidth-0.8.1}/.pylintrc +2 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/PKG-INFO +179 -26
- {wcwidth-0.7.0 → wcwidth-0.8.1}/bin/update-tables.py +610 -51
- wcwidth-0.8.1/code_templates/grapheme_override_per_terminal.py.j2 +13 -0
- wcwidth-0.8.1/code_templates/grapheme_override_table.py.j2 +18 -0
- wcwidth-0.8.1/code_templates/grapheme_registry.py.j2 +13 -0
- wcwidth-0.8.1/code_templates/table_overrides.py.j2 +40 -0
- wcwidth-0.8.1/code_templates/term_programs.py.j2 +22 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/api.rst +6 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/intro.rst +177 -25
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/requirements.txt +2 -2
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/specs.rst +40 -24
- {wcwidth-0.7.0 → wcwidth-0.8.1}/pyproject.toml +5 -1
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-tests39.txt +3 -4
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-update.in +1 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-update.txt +7 -4
- wcwidth-0.8.1/tests/conftest.py +38 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_benchmarks.py +84 -2
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_clip.py +2 -2
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_core.py +48 -11
- wcwidth-0.8.1/tests/test_term_overrides.py +590 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_text_sizing.py +2 -1
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_width.py +6 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tox.ini +7 -3
- wcwidth-0.8.1/ucs-detect/data/AbsoluteTelnetSSH.yaml +789 -0
- wcwidth-0.8.1/ucs-detect/data/_linuxfbdev.yaml +50 -0
- wcwidth-0.8.1/ucs-detect/data/_syncterm.yaml +38 -0
- wcwidth-0.8.1/ucs-detect/data/alacritty.yaml +8821 -0
- wcwidth-0.8.1/ucs-detect/data/bobcat.yaml +10804 -0
- wcwidth-0.8.1/ucs-detect/data/conemu.exe.yaml +27608 -0
- wcwidth-0.8.1/ucs-detect/data/contour.yaml +21578 -0
- wcwidth-0.8.1/ucs-detect/data/coolretroterm.yaml +10734 -0
- wcwidth-0.8.1/ucs-detect/data/emoji-test-latest.txt +5518 -0
- wcwidth-0.8.1/ucs-detect/data/emoji-variation-sequences-latest.txt +757 -0
- wcwidth-0.8.1/ucs-detect/data/emoji-zwj-sequences-latest.txt +1675 -0
- wcwidth-0.8.1/ucs-detect/data/extraterm.yaml +33248 -0
- wcwidth-0.8.1/ucs-detect/data/foot.yaml +8258 -0
- wcwidth-0.8.1/ucs-detect/data/ghostty.yaml +1010 -0
- wcwidth-0.8.1/ucs-detect/data/gnometerminal.yaml +16247 -0
- wcwidth-0.8.1/ucs-detect/data/hyper.yaml +12553 -0
- wcwidth-0.8.1/ucs-detect/data/iterm2.yaml +6564 -0
- wcwidth-0.8.1/ucs-detect/data/kitty.yaml +15643 -0
- wcwidth-0.8.1/ucs-detect/data/konsole.yaml +7624 -0
- wcwidth-0.8.1/ucs-detect/data/libvterm.yaml +13536 -0
- wcwidth-0.8.1/ucs-detect/data/lxterminal.yaml +12959 -0
- wcwidth-0.8.1/ucs-detect/data/mintty.yaml +26246 -0
- wcwidth-0.8.1/ucs-detect/data/mlterm.yaml +17478 -0
- wcwidth-0.8.1/ucs-detect/data/putty.yaml +10682 -0
- wcwidth-0.8.1/ucs-detect/data/qterminal.yaml +9153 -0
- wcwidth-0.8.1/ucs-detect/data/rio.yaml +11346 -0
- wcwidth-0.8.1/ucs-detect/data/rxvtunicode.yaml +10736 -0
- wcwidth-0.8.1/ucs-detect/data/screen.yaml +19446 -0
- wcwidth-0.8.1/ucs-detect/data/securecrt.yaml +16450 -0
- wcwidth-0.8.1/ucs-detect/data/st.yaml +10669 -0
- wcwidth-0.8.1/ucs-detect/data/tabby.yaml +13641 -0
- wcwidth-0.8.1/ucs-detect/data/teraterm.yaml +6684 -0
- wcwidth-0.8.1/ucs-detect/data/terminalapp.yaml +10901 -0
- wcwidth-0.8.1/ucs-detect/data/terminalexe.yaml +3078 -0
- wcwidth-0.8.1/ucs-detect/data/terminator.yaml +15308 -0
- wcwidth-0.8.1/ucs-detect/data/terminology.yaml +31854 -0
- wcwidth-0.8.1/ucs-detect/data/tmux.yaml +8371 -0
- wcwidth-0.8.1/ucs-detect/data/vscodeterminal.yaml +11720 -0
- wcwidth-0.8.1/ucs-detect/data/warp.yaml +13297 -0
- wcwidth-0.8.1/ucs-detect/data/westonterminal.yaml +26416 -0
- wcwidth-0.8.1/ucs-detect/data/wezterm.yaml +10571 -0
- wcwidth-0.8.1/ucs-detect/data/xfce4terminal.yaml +13040 -0
- wcwidth-0.8.1/ucs-detect/data/xterm.yaml +10794 -0
- wcwidth-0.8.1/ucs-detect/data/zellij.yaml +13479 -0
- wcwidth-0.8.1/ucs-detect/data/zutty.yaml +10704 -0
- wcwidth-0.8.1/wcwidth/__init__.py +81 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/_clip.py +31 -5
- wcwidth-0.8.1/wcwidth/_constants.py +164 -0
- wcwidth-0.8.1/wcwidth/_wcswidth.py +439 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/_wcwidth.py +4 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/_width.py +232 -56
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/align.py +32 -3
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/grapheme.py +67 -2
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/table_grapheme.py +53 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/__init__.py +37 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_27e0693f.py +2677 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_3d4826b8.py +6462 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_45d92e98.py +1969 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_4cdf59ce.py +42 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_50bf0759.py +2571 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_529fbb4a.py +1799 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_5bfac390.py +2571 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_813fee16.py +2570 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_8589765c.py +1310 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_8f94b404.py +2581 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_970dbe10.py +2839 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_c0a2cdbf.py +3617 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_c2157f7e.py +1153 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_c3db41c0.py +3401 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_da9ceb0a.py +1910 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_e08bd75e.py +2641 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_e22030f3.py +6396 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_fcc05a0f.py +6648 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_known_fd9d4c44.py +3671 -0
- wcwidth-0.8.1/wcwidth/table_grapheme_overrides/_registry.py +32 -0
- wcwidth-0.8.1/wcwidth/table_overrides.py +853 -0
- wcwidth-0.8.1/wcwidth/table_term_programs.py +49 -0
- wcwidth-0.8.1/wcwidth/table_vs15.py +104 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/text_sizing.py +3 -1
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/textwrap.py +20 -1
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/unicode_versions.py +1 -1
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/wcwidth.py +28 -9
- wcwidth-0.7.0/tests/conftest.py +0 -17
- wcwidth-0.7.0/wcwidth/__init__.py +0 -52
- wcwidth-0.7.0/wcwidth/_constants.py +0 -65
- wcwidth-0.7.0/wcwidth/_wcswidth.py +0 -150
- {wcwidth-0.7.0 → wcwidth-0.8.1}/.gitignore +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/LICENSE +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/README.rst +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/bin/show-sequences +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/bin/strip-sequences +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/bin/verify-table-integrity.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/bin/wcwidth-browser.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/bin/wcwidth-libc-comparator.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/code_templates/grapheme_table.py.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/code_templates/python_table.py.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/code_templates/unicode_version.rst.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/code_templates/unicode_versions.py.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/conf.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/index.rst +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/docs/unicode_version.rst +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-develop.txt +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-docs.in +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-tests38.in +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-tests38.txt +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/requirements-tests39.in +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/__init__.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_ambiguous.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_clip_cjk_emoji.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_clip_overtyping.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_emojis.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_grapheme.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_hyperlink.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_justify.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_sgr_state.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_textwrap.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/tests/test_ucslevel.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/bisearch.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/control_codes.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/escape_sequences.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/hyperlink.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/py.typed +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/sgr_state.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/table_ambiguous.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/table_mc.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/table_vs16.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/table_wide.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.1}/wcwidth/table_zero.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wcwidth
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: Measures the displayed width of unicode strings in a terminal
|
|
5
5
|
Project-URL: Homepage, https://github.com/jquast/wcwidth
|
|
6
6
|
Author-email: Jeff Quast <contact@jeffquast.com>
|
|
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
23
24
|
Classifier: Topic :: Software Development :: Internationalization
|
|
24
25
|
Classifier: Topic :: Software Development :: Libraries
|
|
25
26
|
Classifier: Topic :: Software Development :: Localization
|
|
@@ -72,7 +73,8 @@ and `wcswidth()`_. These functions return -1 when C0 and C1 control codes are p
|
|
|
72
73
|
|
|
73
74
|
An easy-to-use `width()`_ function is provided as a wrapper of `wcswidth()`_ that is also capable of
|
|
74
75
|
measuring most terminal control codes and sequences, like colors, bold, tabstops, and horizontal
|
|
75
|
-
cursor movement.
|
|
76
|
+
cursor movement. `width()`_ argument ``term_program`` may provide more accurate terminal measurement
|
|
77
|
+
Corrections_ as a wrapper of `wcstwidth()`_.
|
|
76
78
|
|
|
77
79
|
Text-justification is solved by the sequence-aware functions `ljust()`_, `rjust()`_, `center()`_,
|
|
78
80
|
and the grapheme-aware function `wrap()`_, serving as drop-in replacements to python standard
|
|
@@ -83,25 +85,31 @@ The `clip()`_ function extracts substrings by their displayed column positions,
|
|
|
83
85
|
|
|
84
86
|
The iterator functions `iter_graphemes()`_ and `iter_sequences()`_ allow for careful navigation of
|
|
85
87
|
grapheme and terminal control sequence boundaries as required by editors or REPLs with cursor
|
|
86
|
-
control. `iter_graphemes_reverse()`_
|
|
87
|
-
|
|
88
|
+
control. `iter_graphemes_reverse()`_ and `grapheme_boundary_before()`_ are necessary for backward
|
|
89
|
+
cursor control over complex unicode.
|
|
88
90
|
|
|
89
91
|
Discrepancies
|
|
90
92
|
-------------
|
|
91
93
|
|
|
92
|
-
You may find that support *varies* for complex unicode sequences or codepoints.
|
|
93
|
-
considered to presume the terminal is enabled for DEC Private Mode 2027 ("Grapheme Clustering"), but
|
|
94
|
-
the specification does not fully describe varying unicode versions, feature levels, or details of
|
|
95
|
-
specific language support. This library does *not* support any alternate "legacy width"
|
|
96
|
-
measurement.
|
|
94
|
+
You may find that support *varies* for complex unicode sequences or codepoints.
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
This library may be considered to presume the terminal is enabled for DEC Private Mode 2027
|
|
97
|
+
("Grapheme Clustering") by default, which may require to be enabled by a TUI application but
|
|
98
|
+
is often the default mode for those terminals that support it: Windows Terminal, WezTerm, ghostty,
|
|
99
|
+
contour, and foot. This library does support any specific "legacy width" measurement, but does
|
|
100
|
+
provide Corrections_ for those terminals without grapheme support.
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
See also:
|
|
103
|
+
|
|
104
|
+
- `Grapheme Clusters and Terminal Emulators`_
|
|
105
|
+
- `terminal-unicode-core.tex`_
|
|
106
|
+
- `State of Terminal Emulators in 2025`_
|
|
107
|
+
- `Perfecting Terminal Character Width Using Correction Tables (2026)`_
|
|
108
|
+
|
|
109
|
+
The `jquast/ucs-detect`_ project publishes automatic results of compliance to our standard for Wide
|
|
110
|
+
character, Languages, grapheme clustering, complex or combining scripts, emojis, zero-width joiner,
|
|
111
|
+
variations, and regional indicator (flags) as a `General Tabulated Summary`_ by terminal emulator
|
|
112
|
+
software and version. The results of the ucs-detect project create our correction tables.
|
|
105
113
|
|
|
106
114
|
========
|
|
107
115
|
Overview
|
|
@@ -148,16 +156,39 @@ Use function `wcswidth()`_ to determine the length of many, a *string of unicode
|
|
|
148
156
|
See specification_ of character measurements. Note that ``-1`` is returned if control codes occurs
|
|
149
157
|
anywhere in the string.
|
|
150
158
|
|
|
159
|
+
wcstwidth()
|
|
160
|
+
-----------
|
|
161
|
+
|
|
162
|
+
Same behavior as `wcswidth()`_ with automatic terminal-specific Corrections_, reading
|
|
163
|
+
``TERM_PROGRAM`` or ``TERM`` when ``True`` (default), or caller can provide terminal query
|
|
164
|
+
XTVERSION_ or ENQ_ response:
|
|
165
|
+
|
|
166
|
+
.. code-block:: python
|
|
167
|
+
|
|
168
|
+
>>> # '♀️' emoji w/vs-16, uncorrected:
|
|
169
|
+
>>> wcwidth.wcswidth('\u2640\ufe0f')
|
|
170
|
+
2
|
|
171
|
+
>>> # corrected,
|
|
172
|
+
>>> wcwidth.wcstwidth('\u2640\ufe0f', term_program='vte')
|
|
173
|
+
1
|
|
174
|
+
|
|
151
175
|
width()
|
|
152
176
|
-------
|
|
153
177
|
|
|
154
|
-
Use function `width()`_ to measure a string with improved handling of ``control_codes
|
|
178
|
+
Use function `width()`_ to measure a string with improved handling of ``control_codes`` and
|
|
179
|
+
measurement Corrections_ through ``term_program``:.
|
|
155
180
|
|
|
156
181
|
.. code-block:: python
|
|
157
182
|
|
|
158
183
|
>>> # same support as wcswidth(), eg. regional indicator flag:
|
|
159
184
|
>>> wcwidth.width('\U0001F1FF\U0001F1FC')
|
|
160
185
|
2
|
|
186
|
+
>>> # set term_program=True to use wcstwidth()
|
|
187
|
+
>>> wcwidth.width('\U0001F1FF\U0001F1FC', term_program=True)
|
|
188
|
+
1
|
|
189
|
+
>>> # or set term_program for measurement of a specific terminal
|
|
190
|
+
>>> wcwidth.width('\U0001F1FF\U0001F1FC', term_program='contour')
|
|
191
|
+
2
|
|
161
192
|
>>> # but also supports sequences, like SGR colored text, "WARN", followed by reset
|
|
162
193
|
>>> wcwidth.width('\x1b[38;2;255;150;100mWARN\x1b[0m')
|
|
163
194
|
4
|
|
@@ -190,8 +221,9 @@ terminal sequences for slightly improved performance. Note that TAB (``'\t'``) i
|
|
|
190
221
|
character and is also ignored, you may want to use `str.expandtabs()`_, first.
|
|
191
222
|
|
|
192
223
|
Use ``control_codes='strict'`` when input is known to contain some control sequences, such as
|
|
193
|
-
SGR color, bold, hyperlinks and cursor movement. Any sequence that cannot be accurately parsed
|
|
194
|
-
such as clearing the screen, vertical, or absolute cursor movement will
|
|
224
|
+
SGR color, bold, hyperlinks and cursor movement. Any sequence that cannot be accurately parsed
|
|
225
|
+
for horizontal measurement, such as clearing the screen, vertical, or absolute cursor movement will
|
|
226
|
+
raise ``ValueError``:
|
|
195
227
|
|
|
196
228
|
.. code-block:: python
|
|
197
229
|
|
|
@@ -368,7 +400,7 @@ Use `strip_sequences()`_ to remove all terminal escape sequences from text.
|
|
|
368
400
|
|
|
369
401
|
.. _ambiguous_width:
|
|
370
402
|
|
|
371
|
-
|
|
403
|
+
Ambiguous Width
|
|
372
404
|
---------------
|
|
373
405
|
|
|
374
406
|
Some Unicode characters have "East Asian Ambiguous" (A) width. These characters display as 1 cell by
|
|
@@ -376,6 +408,9 @@ default, matching Western terminal contexts, but many CJK (Chinese, Japanese, Ko
|
|
|
376
408
|
may have a preference for 2 cells. This is often found as boolean option, "Ambiguous width as wide"
|
|
377
409
|
in Terminal Emulator software preferences.
|
|
378
410
|
|
|
411
|
+
The ``ambiguous_width`` parameter is available on all width-measuring functions: `wcwidth()`_,
|
|
412
|
+
`wcswidth()`_, `width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
|
|
413
|
+
|
|
379
414
|
By default, wcwidth treats ambiguous characters as narrow (width 1). For CJK environments where your
|
|
380
415
|
terminal is configured to display ambiguous characters as double-width, pass ``ambiguous_width=2``:
|
|
381
416
|
|
|
@@ -387,9 +422,6 @@ terminal is configured to display ambiguous characters as double-width, pass ``a
|
|
|
387
422
|
>>> wcwidth.width('\u2460', ambiguous_width=2)
|
|
388
423
|
2
|
|
389
424
|
|
|
390
|
-
The ``ambiguous_width`` parameter is available on all width-measuring functions: `wcwidth()`_,
|
|
391
|
-
`wcswidth()`_, `width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
|
|
392
|
-
|
|
393
425
|
**Terminal Detection**
|
|
394
426
|
|
|
395
427
|
The most reliable method to detect whether a terminal profile is set for "Ambiguous width as wide"
|
|
@@ -413,6 +445,91 @@ possible timeout, slow network, or non-response when working with "dumb terminal
|
|
|
413
445
|
>>> awidth('\u2460')
|
|
414
446
|
1
|
|
415
447
|
|
|
448
|
+
Corrections
|
|
449
|
+
-----------
|
|
450
|
+
|
|
451
|
+
Corrections may be automatically applied depending on the detected or given terminal software name
|
|
452
|
+
beginning with wcwidth release 0.8.0. This allows to correct widths for terminal software that
|
|
453
|
+
differs from the python wcwidth specification_. These corrections are sourced from the
|
|
454
|
+
`jquast/ucs-detect`_ project.
|
|
455
|
+
|
|
456
|
+
The ``term_program`` parameter is available on all width-measuring functions: `wcstwidth()`_,
|
|
457
|
+
`width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
|
|
458
|
+
|
|
459
|
+
`wcstwidth()`_ defaults to ``term_program=True``, auto-detecting the terminal from the
|
|
460
|
+
``TERM_PROGRAM`` or ``TERM`` environment variable. All other functions default to
|
|
461
|
+
``term_program=False``, disabling corrections. Use ``term_program=True`` for automatic
|
|
462
|
+
detection by environment values of ``TERM`` and ``TERM_PROGRAM``.
|
|
463
|
+
|
|
464
|
+
.. code-block:: python
|
|
465
|
+
|
|
466
|
+
# VTE terminals (Gnome Terminal Et al.) still render trigrams as narrow (1 cell), but their
|
|
467
|
+
# definition was changed to wide in Unicode 16 (September 2024).
|
|
468
|
+
>>> wcwidth.wcswidth('\u2630')
|
|
469
|
+
2
|
|
470
|
+
>>> wcwidth.wcstwidth('\u2630', term_program='vte')
|
|
471
|
+
1
|
|
472
|
+
|
|
473
|
+
# account for Alacritty non-support of emoji ZWJ:
|
|
474
|
+
# man + ZWJ + woman + ZWJ + girl + ZWJ + boy
|
|
475
|
+
>>> family = '\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466'
|
|
476
|
+
>>> wcwidth.wcswidth(family)
|
|
477
|
+
2
|
|
478
|
+
>>> wcwidth.wcstwidth(family, term_program='alacritty')
|
|
479
|
+
8
|
|
480
|
+
|
|
481
|
+
Only detectable_ terminals are included: those that identify themselves by XTVERSION_, ENQ_, any
|
|
482
|
+
``TERM_PROGRAM`` or a unique ``TERM`` environment value. For the most accurate correction tables,
|
|
483
|
+
query the terminal's software version via XTVERSION_ (``CSI > q``) using a higher-level interactive
|
|
484
|
+
terminal library like `jquast/blessed`_:
|
|
485
|
+
|
|
486
|
+
.. code-block:: python
|
|
487
|
+
|
|
488
|
+
>>> import blessed, wcwidth
|
|
489
|
+
>>> term = blessed.Terminal()
|
|
490
|
+
>>> sw_ver = term.get_software_version()
|
|
491
|
+
>>> print(sw_ver)
|
|
492
|
+
SoftwareVersion(name='VTE', version='7600')
|
|
493
|
+
>>> wcwidth.width('\u2630', term_program=sw_ver.name)
|
|
494
|
+
1
|
|
495
|
+
|
|
496
|
+
This is important because ``TERM_PROGRAM`` is not forwarded for remote hosts, like SSH, and many
|
|
497
|
+
terminals may only be identified using XTVERSION_ or ENQ_. Use `list_term_programs()`_ to see all
|
|
498
|
+
recognized names:
|
|
499
|
+
|
|
500
|
+
.. BEGIN_LIST_TERM_PROGRAMS
|
|
501
|
+
.. code-block:: python
|
|
502
|
+
|
|
503
|
+
>>> wcwidth.list_term_programs()
|
|
504
|
+
('alacritty', 'apple_terminal', 'bobcat', 'contour', 'extraterm', 'foot',
|
|
505
|
+
'ghostty', 'hyper', 'iterm.app', 'iterm2', 'kitty', 'konsole', 'mintty',
|
|
506
|
+
'mlterm', 'pterm', 'putty', 'rio', 'rxvt', 'rxvt-unicode-256color', 'st',
|
|
507
|
+
'st-256color', 'tabby', 'terminology', 'urxvt', 'vscode', 'vte', 'warp',
|
|
508
|
+
'warpterminal', 'wezterm', 'xterm', 'xterm-ghostty', 'xterm-kitty',
|
|
509
|
+
'xterm.js')
|
|
510
|
+
|
|
511
|
+
.. END_LIST_TERM_PROGRAMS
|
|
512
|
+
|
|
513
|
+
``term_program=False`` (the default for `width()`_, `ljust()`_, `rjust()`_, `center()`_,
|
|
514
|
+
`wrap()`_, and `clip()`_) disables terminal corrections. `wcstwidth()`_ defaults to
|
|
515
|
+
``term_program=True`` for auto-detection.
|
|
516
|
+
|
|
517
|
+
For automatic tests and other purposes that require cross-environment consistency, set static values
|
|
518
|
+
or unset ``TERM`` and ``TERM_PROGRAM`` environment values, such as in ``conftest.py`` with pytest:
|
|
519
|
+
|
|
520
|
+
.. code-block:: python
|
|
521
|
+
|
|
522
|
+
@pytest.fixture(autouse=True)
|
|
523
|
+
def _clear_term_program():
|
|
524
|
+
"""unset TERM/TERM_PROGRAM before each test."""
|
|
525
|
+
saved_term = os.environ.pop('TERM', None)
|
|
526
|
+
saved_tprog = os.environ.pop('TERM_PROGRAM', None)
|
|
527
|
+
yield
|
|
528
|
+
if saved_term is not None:
|
|
529
|
+
os.environ['TERM'] = saved_term
|
|
530
|
+
if saved_tprog is not None:
|
|
531
|
+
os.environ['TERM_PROGRAM'] = saved_tprog
|
|
532
|
+
|
|
416
533
|
==========
|
|
417
534
|
Developing
|
|
418
535
|
==========
|
|
@@ -536,10 +653,15 @@ This library is used in:
|
|
|
536
653
|
Other Languages
|
|
537
654
|
===============
|
|
538
655
|
|
|
539
|
-
|
|
540
|
-
|
|
656
|
+
The following libraries provide grapheme and emoji support and closely align with our
|
|
657
|
+
specification_:
|
|
658
|
+
|
|
659
|
+
- `jacobsandlund/uucode`_ Zig
|
|
660
|
+
- `contour-terminal/libunicode`_ C++20
|
|
661
|
+
|
|
662
|
+
There are similar implementations of at least the `wcwidth()`_ and `wcswidth()`_ functions in other
|
|
663
|
+
languages:
|
|
541
664
|
|
|
542
|
-
- `contour-terminal/libunicode`_: C++20
|
|
543
665
|
- `ridiculousfish/widecharwidth`_: Python
|
|
544
666
|
- `termux/wcwidth`_: C
|
|
545
667
|
- `powerman/wcwidth-icons`_: C
|
|
@@ -563,6 +685,24 @@ languages.
|
|
|
563
685
|
History
|
|
564
686
|
=======
|
|
565
687
|
|
|
688
|
+
0.8.1 *2026-06-08*
|
|
689
|
+
* **Improved** `wcstwidth()`_ with new ``zeroer``, ``narrow_wider``, and ``narrow_zeroer``
|
|
690
|
+
Corrections_. `PR #226`_
|
|
691
|
+
|
|
692
|
+
0.8.0 *2026-06-05*
|
|
693
|
+
* **New** support for Variation Selector 15 Emojis as narrow, `Issue #211`_.
|
|
694
|
+
* **New** argument, ``term_program`` for `wcstwidth()`_, `width()`_, `clip()`_, `wrap()`_,
|
|
695
|
+
`ljust()`_, `rjust()`_, and `center()`_. ``False`` disables Corrections_; ``True``
|
|
696
|
+
auto-detects by ``TERM_PROGRAM`` or ``TERM``; string values accept canonical names matching
|
|
697
|
+
`list_term_programs()`_. `wcstwidth()`_ defaults to ``True``; all other functions
|
|
698
|
+
default to ``False``.
|
|
699
|
+
* **Improved** performance on Python 3.15 using standard library iter_graphemes() `PR #206`_.
|
|
700
|
+
* **Improved** memory usage and import time for Python 3.15 using lazy imports `PR #221`_.
|
|
701
|
+
* **Bugfix** Invisible_Stacker viramas now form conjuncts (Burmese, Khmer, etc.) and
|
|
702
|
+
change some Virama width calculations to match `jacobsandlund/uucode`_ (ghostty) `PR #223`_.
|
|
703
|
+
* **Updated** graphemes width maximum now 2, matching Ghostty, foot, and Windows Terminal `PR
|
|
704
|
+
#224`_.
|
|
705
|
+
|
|
566
706
|
0.7.0 *2026-05-02*
|
|
567
707
|
* **New** support for `kitty text sizing protocol`_ (OSC 66) in `width()`_ and `clip()`_.
|
|
568
708
|
* **New** `clip()`_ parameter ``control_codes='parse'``, ``'ignore'``, and ``'strict'``. `clip()`_
|
|
@@ -793,9 +933,15 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
793
933
|
.. _`PR #200`: https://github.com/jquast/wcwidth/pull/200
|
|
794
934
|
.. _`PR #202`: https://github.com/jquast/wcwidth/pull/202
|
|
795
935
|
.. _`PR #204`: https://github.com/jquast/wcwidth/pull/204
|
|
936
|
+
.. _`PR #206`: https://github.com/jquast/wcwidth/pull/206
|
|
937
|
+
.. _`PR #221`: https://github.com/jquast/wcwidth/pull/221
|
|
938
|
+
.. _`PR #223`: https://github.com/jquast/wcwidth/pull/223
|
|
939
|
+
.. _`PR #224`: https://github.com/jquast/wcwidth/pull/224
|
|
940
|
+
.. _`PR #226`: https://github.com/jquast/wcwidth/pull/226
|
|
796
941
|
.. _`Issue #101`: https://github.com/jquast/wcwidth/issues/101
|
|
797
942
|
.. _`Issue #155`: https://github.com/jquast/wcwidth/issues/155
|
|
798
943
|
.. _`Issue #190`: https://github.com/jquast/wcwidth/issues/190
|
|
944
|
+
.. _`Issue #211`: https://github.com/jquast/wcwidth/issues/211
|
|
799
945
|
.. _`jquast/blessed`: https://github.com/jquast/blessed
|
|
800
946
|
.. _`jquast/telix`: https://github.com/jquast/telix
|
|
801
947
|
.. _`selectel/pyte`: https://github.com/selectel/pyte
|
|
@@ -823,6 +969,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
823
969
|
.. _`joshuarubin/wcwidth9`: https://github.com/joshuarubin/wcwidth9
|
|
824
970
|
.. _`spectreconsole/wcwidth`: https://github.com/spectreconsole/wcwidth
|
|
825
971
|
.. _`contour-terminal/libunicode`: https://github.com/contour-terminal/libunicode
|
|
972
|
+
.. _`jacobsandlund/uucode`: https://github.com/jacobsandlund/uucode
|
|
826
973
|
.. _`ridiculousfish/widecharwidth`: https://github.com/ridiculousfish/widecharwidth
|
|
827
974
|
.. _`termux/wcwidth`: https://github.com/termux/wcwidth
|
|
828
975
|
.. _`powerman/wcwidth-icons`: https://github.com/powerman/wcwidth-icons
|
|
@@ -834,7 +981,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
834
981
|
.. _`ihabunek/toot`: https://github.com/ihabunek/toot
|
|
835
982
|
.. _`saulpw/visidata`: https://github.com/saulpw/visidata
|
|
836
983
|
.. _`urwid/urwid`: https://github.com/urwid/urwid
|
|
837
|
-
.. _`prettytable/prettytable`: https://github.com/
|
|
984
|
+
.. _`prettytable/prettytable`: https://github.com/prettytable/prettytable
|
|
838
985
|
.. _`leviathan0992/Pylsy`: https://github.com/leviathan0992/Pylsy
|
|
839
986
|
.. _`pip-tools`: https://pip-tools.readthedocs.io/
|
|
840
987
|
.. _`sphinx`: https://www.sphinx-doc.org/
|
|
@@ -846,6 +993,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
846
993
|
.. _`General Tabulated Summary`: https://ucs-detect.readthedocs.io/results.html#tabulated-results
|
|
847
994
|
.. _`wcwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcwidth
|
|
848
995
|
.. _`wcswidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcswidth
|
|
996
|
+
.. _`wcstwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcstwidth
|
|
849
997
|
.. _`width()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.width
|
|
850
998
|
.. _`iter_graphemes()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes
|
|
851
999
|
.. _`iter_graphemes_reverse()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes_reverse
|
|
@@ -861,6 +1009,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
861
1009
|
.. _`TextSizingParams`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.TextSizingParams
|
|
862
1010
|
.. _`iter_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_sequences
|
|
863
1011
|
.. _`list_versions()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.list_versions
|
|
1012
|
+
.. _`list_term_programs()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.list_term_programs
|
|
864
1013
|
.. _`Unicode Standard Annex #29`: https://www.unicode.org/reports/tr29/
|
|
865
1014
|
.. _`Terminal.detect_ambiguous_width()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.detect_ambiguous_width
|
|
866
1015
|
.. _`parity padding`: https://jazcap53.github.io/pythons-eccentric-strcenter.html
|
|
@@ -868,6 +1017,10 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
868
1017
|
.. _`Grapheme Clusters and Terminal Emulators`: https://mitchellh.com/writing/grapheme-clusters-in-terminals
|
|
869
1018
|
.. _`terminal-unicode-core.tex`: https://github.com/contour-terminal/terminal-unicode-core/blob/master/spec/terminal-unicode-core.tex
|
|
870
1019
|
.. _`State of Terminal Emulators in 2025`: https://www.jeffquast.com/post/state-of-terminal-emulation-2025/
|
|
1020
|
+
.. _`Perfecting Terminal Character Width Using Correction Tables (2026)`: https://www.jeffquast.com/post/perfecting-terminal-character-width-using-correction-tables/
|
|
1021
|
+
.. _XTVERSION: https://vtdn.dev/docs/dcs/xtversion/
|
|
1022
|
+
.. _ENQ: https://documentation.help/PuTTY/config-answerback.html
|
|
1023
|
+
.. _detectable: https://ucs-detect.readthedocs.io/results.html#terminal-identification
|
|
871
1024
|
.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi
|
|
872
1025
|
:alt: Downloads
|
|
873
1026
|
:target: https://pypi.org/project/wcwidth/
|