wcwidth 0.7.0__tar.gz → 0.8.0__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.0}/.pylintrc +2 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/PKG-INFO +173 -26
- {wcwidth-0.7.0 → wcwidth-0.8.0}/bin/update-tables.py +592 -51
- wcwidth-0.8.0/code_templates/grapheme_override_per_terminal.py.j2 +13 -0
- wcwidth-0.8.0/code_templates/grapheme_override_table.py.j2 +18 -0
- wcwidth-0.8.0/code_templates/grapheme_registry.py.j2 +13 -0
- wcwidth-0.8.0/code_templates/table_overrides.py.j2 +37 -0
- wcwidth-0.8.0/code_templates/term_programs.py.j2 +22 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/api.rst +6 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/intro.rst +171 -25
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/requirements.txt +2 -2
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/specs.rst +38 -22
- {wcwidth-0.7.0 → wcwidth-0.8.0}/pyproject.toml +5 -1
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-tests39.txt +3 -4
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-update.in +1 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-update.txt +7 -4
- wcwidth-0.8.0/tests/conftest.py +38 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_benchmarks.py +84 -2
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_clip.py +2 -2
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_core.py +48 -11
- wcwidth-0.8.0/tests/test_term_overrides.py +493 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_text_sizing.py +2 -1
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_width.py +6 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tox.ini +7 -3
- wcwidth-0.8.0/ucs-detect/data/AbsoluteTelnetSSH.yaml +789 -0
- wcwidth-0.8.0/ucs-detect/data/_linuxfbdev.yaml +50 -0
- wcwidth-0.8.0/ucs-detect/data/_syncterm.yaml +38 -0
- wcwidth-0.8.0/ucs-detect/data/alacritty.yaml +8755 -0
- wcwidth-0.8.0/ucs-detect/data/bobcat.yaml +10780 -0
- wcwidth-0.8.0/ucs-detect/data/conemu.exe.yaml +29154 -0
- wcwidth-0.8.0/ucs-detect/data/contour.yaml +16580 -0
- wcwidth-0.8.0/ucs-detect/data/coolretroterm.yaml +10905 -0
- wcwidth-0.8.0/ucs-detect/data/extraterm.yaml +27161 -0
- wcwidth-0.8.0/ucs-detect/data/foot.yaml +8336 -0
- wcwidth-0.8.0/ucs-detect/data/ghostty.yaml +1001 -0
- wcwidth-0.8.0/ucs-detect/data/gnometerminal.yaml +13095 -0
- wcwidth-0.8.0/ucs-detect/data/hyper.yaml +12481 -0
- wcwidth-0.8.0/ucs-detect/data/iterm2.yaml +6576 -0
- wcwidth-0.8.0/ucs-detect/data/kitty.yaml +15571 -0
- wcwidth-0.8.0/ucs-detect/data/konsole.yaml +6187 -0
- wcwidth-0.8.0/ucs-detect/data/libvterm.yaml +11631 -0
- wcwidth-0.8.0/ucs-detect/data/lxterminal.yaml +12887 -0
- wcwidth-0.8.0/ucs-detect/data/mintty.yaml +27871 -0
- wcwidth-0.8.0/ucs-detect/data/mlterm.yaml +14706 -0
- wcwidth-0.8.0/ucs-detect/data/putty.yaml +10658 -0
- wcwidth-0.8.0/ucs-detect/data/qterminal.yaml +8394 -0
- wcwidth-0.8.0/ucs-detect/data/rio.yaml +9924 -0
- wcwidth-0.8.0/ucs-detect/data/rxvtunicode.yaml +10826 -0
- wcwidth-0.8.0/ucs-detect/data/screen.yaml +18026 -0
- wcwidth-0.8.0/ucs-detect/data/securecrt.yaml +16450 -0
- wcwidth-0.8.0/ucs-detect/data/st.yaml +10759 -0
- wcwidth-0.8.0/ucs-detect/data/tabby.yaml +12135 -0
- wcwidth-0.8.0/ucs-detect/data/teraterm.yaml +6678 -0
- wcwidth-0.8.0/ucs-detect/data/terminalapp.yaml +10895 -0
- wcwidth-0.8.0/ucs-detect/data/terminalexe.yaml +5649 -0
- wcwidth-0.8.0/ucs-detect/data/terminator.yaml +13065 -0
- wcwidth-0.8.0/ucs-detect/data/terminology.yaml +26742 -0
- wcwidth-0.8.0/ucs-detect/data/tmux.yaml +6895 -0
- wcwidth-0.8.0/ucs-detect/data/vscodeterminal.yaml +11720 -0
- wcwidth-0.8.0/ucs-detect/data/warp.yaml +11038 -0
- wcwidth-0.8.0/ucs-detect/data/westonterminal.yaml +26416 -0
- wcwidth-0.8.0/ucs-detect/data/wezterm.yaml +10565 -0
- wcwidth-0.8.0/ucs-detect/data/xfce4terminal.yaml +13020 -0
- wcwidth-0.8.0/ucs-detect/data/xterm.yaml +10881 -0
- wcwidth-0.8.0/ucs-detect/data/zellij.yaml +12096 -0
- wcwidth-0.8.0/ucs-detect/data/zutty.yaml +10797 -0
- wcwidth-0.8.0/wcwidth/__init__.py +81 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/_clip.py +31 -5
- wcwidth-0.8.0/wcwidth/_constants.py +151 -0
- wcwidth-0.8.0/wcwidth/_wcswidth.py +427 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/_wcwidth.py +4 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/_width.py +220 -56
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/align.py +32 -3
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/grapheme.py +67 -2
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/table_grapheme.py +53 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/__init__.py +37 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_27e0693f.py +2677 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_45d92e98.py +1969 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_4cdf59ce.py +42 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_50bf0759.py +2571 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_529fbb4a.py +1799 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_5bfac390.py +2571 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_813fee16.py +2570 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_8589765c.py +1310 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_8f94b404.py +2581 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_970dbe10.py +2839 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_c0a2cdbf.py +3617 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_c0d5dc9e.py +6427 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_c2157f7e.py +1153 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_c3db41c0.py +3401 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_da9ceb0a.py +1910 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_e08bd75e.py +2641 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_e22030f3.py +6396 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_fcc05a0f.py +6648 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_known_fd9d4c44.py +3671 -0
- wcwidth-0.8.0/wcwidth/table_grapheme_overrides/_registry.py +32 -0
- wcwidth-0.8.0/wcwidth/table_overrides.py +714 -0
- wcwidth-0.8.0/wcwidth/table_term_programs.py +49 -0
- wcwidth-0.8.0/wcwidth/table_vs15.py +104 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/text_sizing.py +3 -1
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/textwrap.py +20 -1
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/unicode_versions.py +1 -1
- {wcwidth-0.7.0 → wcwidth-0.8.0}/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.0}/.gitignore +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/LICENSE +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/README.rst +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/bin/show-sequences +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/bin/strip-sequences +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/bin/verify-table-integrity.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/bin/wcwidth-browser.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/bin/wcwidth-libc-comparator.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/code_templates/grapheme_table.py.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/code_templates/python_table.py.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/code_templates/unicode_version.rst.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/code_templates/unicode_versions.py.j2 +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/conf.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/index.rst +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/docs/unicode_version.rst +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-develop.txt +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-docs.in +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-tests38.in +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-tests38.txt +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/requirements-tests39.in +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/__init__.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_ambiguous.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_clip_cjk_emoji.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_clip_overtyping.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_emojis.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_grapheme.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_hyperlink.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_justify.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_sgr_state.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_textwrap.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/tests/test_ucslevel.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/bisearch.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/control_codes.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/escape_sequences.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/hyperlink.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/py.typed +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/sgr_state.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/table_ambiguous.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/table_mc.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/table_vs16.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/wcwidth/table_wide.py +0 -0
- {wcwidth-0.7.0 → wcwidth-0.8.0}/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.0
|
|
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
|
+
- `Report of terminals supporting Graphemes (2027)`_
|
|
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,90 @@ 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 are automatically applied depending on 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 standard. These corrections are sourced from the `jquast/ucs-detect`_ project.
|
|
454
|
+
|
|
455
|
+
The ``term_program`` parameter is available on all width-measuring functions: `wcstwidth()`_,
|
|
456
|
+
`width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
|
|
457
|
+
|
|
458
|
+
`wcstwidth()`_ defaults to ``term_program=True``, auto-detecting the terminal from the
|
|
459
|
+
``TERM_PROGRAM`` or ``TERM`` environment variable. All other functions default to
|
|
460
|
+
``term_program=False``, disabling corrections. Use ``term_program=True`` for automatic
|
|
461
|
+
detection by environment values of ``TERM`` and ``TERM_PROGRAM``.
|
|
462
|
+
|
|
463
|
+
.. code-block:: python
|
|
464
|
+
|
|
465
|
+
# VTE terminals (Gnome Terminal Et al.) still render trigrams as narrow (1 cell), but their
|
|
466
|
+
# definition was changed to wide in Unicode 16 (September 2024).
|
|
467
|
+
>>> wcwidth.wcswidth('\u2630')
|
|
468
|
+
2
|
|
469
|
+
>>> wcwidth.wcstwidth('\u2630', term_program='vte')
|
|
470
|
+
1
|
|
471
|
+
|
|
472
|
+
# account for Alacritty non-support of emoji ZWJ:
|
|
473
|
+
# man + ZWJ + woman + ZWJ + girl + ZWJ + boy
|
|
474
|
+
>>> family = '\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466'
|
|
475
|
+
>>> wcwidth.wcswidth(family)
|
|
476
|
+
2
|
|
477
|
+
>>> wcwidth.wcstwidth(family, term_program='alacritty')
|
|
478
|
+
8
|
|
479
|
+
|
|
480
|
+
Only detectable_ terminals are included: those that identify themselves by XTVERSION_, ENQ_, any
|
|
481
|
+
``TERM_PROGRAM`` or a unique ``TERM`` environment value. For the most accurate correction tables,
|
|
482
|
+
query the terminal's software version via XTVERSION_ (``CSI > q``) using a higher-level interactive
|
|
483
|
+
terminal library like `jquast/blessed`_:
|
|
484
|
+
|
|
485
|
+
.. code-block:: python
|
|
486
|
+
|
|
487
|
+
>>> import blessed, wcwidth
|
|
488
|
+
>>> term = blessed.Terminal()
|
|
489
|
+
>>> sw_ver = term.get_software_version()
|
|
490
|
+
>>> print(sw_ver)
|
|
491
|
+
SoftwareVersion(name='VTE', version='7600')
|
|
492
|
+
>>> wcwidth.width('\u2630', term_program=sw_ver.name)
|
|
493
|
+
1
|
|
494
|
+
|
|
495
|
+
This is important because ``TERM_PROGRAM`` is not forwarded for remote hosts, like SSH, and many
|
|
496
|
+
terminals may only be identified using XTVERSION_ or ENQ_. Use `list_term_programs()`_ to see all
|
|
497
|
+
recognized names:
|
|
498
|
+
|
|
499
|
+
.. BEGIN_LIST_TERM_PROGRAMS
|
|
500
|
+
.. code-block:: python
|
|
501
|
+
|
|
502
|
+
>>> wcwidth.list_term_programs()
|
|
503
|
+
('alacritty', 'apple_terminal', 'bobcat', 'contour', 'extraterm', 'foot',
|
|
504
|
+
'ghostty', 'hyper', 'iterm.app', 'iterm2', 'kitty', 'konsole', 'mintty',
|
|
505
|
+
'mlterm', 'pterm', 'putty', 'rio', 'rxvt', 'rxvt-unicode-256color', 'st',
|
|
506
|
+
'st-256color', 'tabby', 'terminology', 'urxvt', 'vscode', 'vte', 'warp',
|
|
507
|
+
'warpterminal', 'wezterm', 'xterm', 'xterm-ghostty', 'xterm-kitty',
|
|
508
|
+
'xterm.js')
|
|
509
|
+
|
|
510
|
+
.. END_LIST_TERM_PROGRAMS
|
|
511
|
+
|
|
512
|
+
``term_program=False`` (the default for `width()`_, `ljust()`_, `rjust()`_, `center()`_,
|
|
513
|
+
`wrap()`_, and `clip()`_) disables terminal corrections. `wcstwidth()`_ defaults to
|
|
514
|
+
``term_program=True`` for auto-detection.
|
|
515
|
+
|
|
516
|
+
For automatic tests and other purposes that require cross-environment consistency, set static values
|
|
517
|
+
or unset ``TERM`` and ``TERM_PROGRAM`` environment values, such as in ``conftest.py`` with pytest:
|
|
518
|
+
|
|
519
|
+
.. code-block:: python
|
|
520
|
+
|
|
521
|
+
@pytest.fixture(autouse=True)
|
|
522
|
+
def _clear_term_program():
|
|
523
|
+
"""unset TERM/TERM_PROGRAM before each test."""
|
|
524
|
+
saved_term = os.environ.pop('TERM', None)
|
|
525
|
+
saved_tprog = os.environ.pop('TERM_PROGRAM', None)
|
|
526
|
+
yield
|
|
527
|
+
if saved_term is not None:
|
|
528
|
+
os.environ['TERM'] = saved_term
|
|
529
|
+
if saved_tprog is not None:
|
|
530
|
+
os.environ['TERM_PROGRAM'] = saved_tprog
|
|
531
|
+
|
|
416
532
|
==========
|
|
417
533
|
Developing
|
|
418
534
|
==========
|
|
@@ -536,10 +652,15 @@ This library is used in:
|
|
|
536
652
|
Other Languages
|
|
537
653
|
===============
|
|
538
654
|
|
|
539
|
-
|
|
540
|
-
|
|
655
|
+
The following libraries provide grapheme and emoji support and closely align with our
|
|
656
|
+
specification_:
|
|
657
|
+
|
|
658
|
+
- `jacobsandlund/uucode`_ Zig
|
|
659
|
+
- `contour-terminal/libunicode`_ C++20
|
|
660
|
+
|
|
661
|
+
There are similar implementations of at least the `wcwidth()`_ and `wcswidth()`_ functions in other
|
|
662
|
+
languages:
|
|
541
663
|
|
|
542
|
-
- `contour-terminal/libunicode`_: C++20
|
|
543
664
|
- `ridiculousfish/widecharwidth`_: Python
|
|
544
665
|
- `termux/wcwidth`_: C
|
|
545
666
|
- `powerman/wcwidth-icons`_: C
|
|
@@ -563,6 +684,20 @@ languages.
|
|
|
563
684
|
History
|
|
564
685
|
=======
|
|
565
686
|
|
|
687
|
+
0.8.0 *(unreleased)*
|
|
688
|
+
* **New** support for Variation Selector 15 Emojis as narrow, `Issue #211`_.
|
|
689
|
+
* **New** argument, ``term_program`` for `wcstwidth()`_, `width()`_, `clip()`_, `wrap()`_,
|
|
690
|
+
`ljust()`_, `rjust()`_, and `center()`_. ``False`` disables corrections; ``True``
|
|
691
|
+
auto-detects by ``TERM_PROGRAM`` or ``TERM``; string values accept canonical names matching
|
|
692
|
+
`list_term_programs()`_. `wcstwidth()`_ defaults to ``True``; all other functions
|
|
693
|
+
default to ``False``.
|
|
694
|
+
* **Improved** performance on Python 3.15 using standard library iter_graphemes() `PR #206`_.
|
|
695
|
+
* **Improved** memory usage and import time for Python 3.15 using lazy imports `PR #221`_.
|
|
696
|
+
* **Bugfix** Invisible_Stacker viramas now form conjuncts (Burmese, Khmer, etc.) and
|
|
697
|
+
change some Virama width calculations to match `jacobsandlund/uucode`_ (ghostty) `PR #223`_.
|
|
698
|
+
* **Updated** graphemes width maximum now 2, matching Ghostty, foot, and Windows Terminal `PR
|
|
699
|
+
#224`_.
|
|
700
|
+
|
|
566
701
|
0.7.0 *2026-05-02*
|
|
567
702
|
* **New** support for `kitty text sizing protocol`_ (OSC 66) in `width()`_ and `clip()`_.
|
|
568
703
|
* **New** `clip()`_ parameter ``control_codes='parse'``, ``'ignore'``, and ``'strict'``. `clip()`_
|
|
@@ -793,9 +928,14 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
793
928
|
.. _`PR #200`: https://github.com/jquast/wcwidth/pull/200
|
|
794
929
|
.. _`PR #202`: https://github.com/jquast/wcwidth/pull/202
|
|
795
930
|
.. _`PR #204`: https://github.com/jquast/wcwidth/pull/204
|
|
931
|
+
.. _`PR #206`: https://github.com/jquast/wcwidth/pull/206
|
|
932
|
+
.. _`PR #221`: https://github.com/jquast/wcwidth/pull/221
|
|
933
|
+
.. _`PR #223`: https://github.com/jquast/wcwidth/pull/223
|
|
934
|
+
.. _`PR #224`: https://github.com/jquast/wcwidth/pull/224
|
|
796
935
|
.. _`Issue #101`: https://github.com/jquast/wcwidth/issues/101
|
|
797
936
|
.. _`Issue #155`: https://github.com/jquast/wcwidth/issues/155
|
|
798
937
|
.. _`Issue #190`: https://github.com/jquast/wcwidth/issues/190
|
|
938
|
+
.. _`Issue #211`: https://github.com/jquast/wcwidth/issues/211
|
|
799
939
|
.. _`jquast/blessed`: https://github.com/jquast/blessed
|
|
800
940
|
.. _`jquast/telix`: https://github.com/jquast/telix
|
|
801
941
|
.. _`selectel/pyte`: https://github.com/selectel/pyte
|
|
@@ -823,6 +963,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
823
963
|
.. _`joshuarubin/wcwidth9`: https://github.com/joshuarubin/wcwidth9
|
|
824
964
|
.. _`spectreconsole/wcwidth`: https://github.com/spectreconsole/wcwidth
|
|
825
965
|
.. _`contour-terminal/libunicode`: https://github.com/contour-terminal/libunicode
|
|
966
|
+
.. _`jacobsandlund/uucode`: https://github.com/jacobsandlund/uucode
|
|
826
967
|
.. _`ridiculousfish/widecharwidth`: https://github.com/ridiculousfish/widecharwidth
|
|
827
968
|
.. _`termux/wcwidth`: https://github.com/termux/wcwidth
|
|
828
969
|
.. _`powerman/wcwidth-icons`: https://github.com/powerman/wcwidth-icons
|
|
@@ -834,7 +975,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
834
975
|
.. _`ihabunek/toot`: https://github.com/ihabunek/toot
|
|
835
976
|
.. _`saulpw/visidata`: https://github.com/saulpw/visidata
|
|
836
977
|
.. _`urwid/urwid`: https://github.com/urwid/urwid
|
|
837
|
-
.. _`prettytable/prettytable`: https://github.com/
|
|
978
|
+
.. _`prettytable/prettytable`: https://github.com/prettytable/prettytable
|
|
838
979
|
.. _`leviathan0992/Pylsy`: https://github.com/leviathan0992/Pylsy
|
|
839
980
|
.. _`pip-tools`: https://pip-tools.readthedocs.io/
|
|
840
981
|
.. _`sphinx`: https://www.sphinx-doc.org/
|
|
@@ -846,6 +987,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
846
987
|
.. _`General Tabulated Summary`: https://ucs-detect.readthedocs.io/results.html#tabulated-results
|
|
847
988
|
.. _`wcwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcwidth
|
|
848
989
|
.. _`wcswidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcswidth
|
|
990
|
+
.. _`wcstwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcstwidth
|
|
849
991
|
.. _`width()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.width
|
|
850
992
|
.. _`iter_graphemes()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes
|
|
851
993
|
.. _`iter_graphemes_reverse()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes_reverse
|
|
@@ -861,6 +1003,7 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
861
1003
|
.. _`TextSizingParams`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.TextSizingParams
|
|
862
1004
|
.. _`iter_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_sequences
|
|
863
1005
|
.. _`list_versions()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.list_versions
|
|
1006
|
+
.. _`list_term_programs()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.list_term_programs
|
|
864
1007
|
.. _`Unicode Standard Annex #29`: https://www.unicode.org/reports/tr29/
|
|
865
1008
|
.. _`Terminal.detect_ambiguous_width()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.detect_ambiguous_width
|
|
866
1009
|
.. _`parity padding`: https://jazcap53.github.io/pythons-eccentric-strcenter.html
|
|
@@ -868,6 +1011,10 @@ https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
|
|
|
868
1011
|
.. _`Grapheme Clusters and Terminal Emulators`: https://mitchellh.com/writing/grapheme-clusters-in-terminals
|
|
869
1012
|
.. _`terminal-unicode-core.tex`: https://github.com/contour-terminal/terminal-unicode-core/blob/master/spec/terminal-unicode-core.tex
|
|
870
1013
|
.. _`State of Terminal Emulators in 2025`: https://www.jeffquast.com/post/state-of-terminal-emulation-2025/
|
|
1014
|
+
.. _`Report of terminals supporting Graphemes (2027)`: https://ucs-detect.readthedocs.io/results.html#terminal-features
|
|
1015
|
+
.. _XTVERSION: https://vtdn.dev/docs/dcs/xtversion/
|
|
1016
|
+
.. _ENQ: https://documentation.help/PuTTY/config-answerback.html
|
|
1017
|
+
.. _detectable: https://ucs-detect.readthedocs.io/results.html#terminal-identification
|
|
871
1018
|
.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi
|
|
872
1019
|
:alt: Downloads
|
|
873
1020
|
:target: https://pypi.org/project/wcwidth/
|