add
This commit is contained in:
@@ -0,0 +1,589 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: wcwidth
|
||||
Version: 0.9.2
|
||||
Summary: Measures the displayed width of unicode strings in a terminal
|
||||
Author-email: Jeff Quast <contact@jeffquast.com>
|
||||
Project-URL: Homepage, https://github.com/jquast/wcwidth
|
||||
Keywords: cjk,combining,console,eastasian,emoji,emulator,terminal,unicode,wcswidth,wcwidth,xterm
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Programming Language :: Python :: 3.14
|
||||
Classifier: Programming Language :: Python :: 3.15
|
||||
Classifier: Topic :: Software Development :: Internationalization
|
||||
Classifier: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: Software Development :: Localization
|
||||
Classifier: Topic :: Terminals
|
||||
Classifier: Typing :: Typed
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
Dynamic: license-file
|
||||
|
||||
|pypi_downloads| |codecov| |license|
|
||||
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
This Python and C11 library is mainly for CLI/TUI programs that carefully produce output for
|
||||
Terminals. This page is about the Python library, see libwcwidth_ for the portable C11 library.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The stable version of this package is maintained on pypi, install or upgrade, using pip::
|
||||
|
||||
pip install --upgrade wcwidth
|
||||
|
||||
Problem
|
||||
-------
|
||||
|
||||
All Python string-formatting functions, `textwrap.wrap()`_, `str.ljust()`_, `str.rjust()`_, and
|
||||
`str.center()`_ **incorrectly** measure the displayed width of a string as equal to the number of
|
||||
their codepoints.
|
||||
|
||||
Some examples of **incorrect results**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # result consumes 16 total cells, 11 expected,
|
||||
>>> 'コンニチハ'.rjust(11, 'X')
|
||||
'XXXXXXコンニチハ'
|
||||
|
||||
>>> # combining acute accent: result consumes 5 total cells, 6 expected,
|
||||
>>> 'cafe\u0301'.center(6, 'X')
|
||||
'caféX'
|
||||
|
||||
Solution
|
||||
--------
|
||||
|
||||
The lowest-level functions in this library are derived from POSIX.1-2001 and POSIX.1-2008
|
||||
`wcwidth(3)`_ and `wcswidth(3)`_, which this library precisely copies by interface as `wcwidth()`_
|
||||
and `wcswidth()`_. These functions return -1 when C0 and C1 control codes are present.
|
||||
|
||||
An easy-to-use `width()`_ function is provided as a wrapper of `wcswidth()`_ that is also capable of
|
||||
measuring most terminal control codes and sequences, like colors, bold, tabstops, and horizontal
|
||||
cursor movement. `width()`_ argument ``term_program`` may provide more accurate terminal measurement
|
||||
Corrections_ as a wrapper of `wcstwidth()`_.
|
||||
|
||||
Text-justification is solved by the sequence-aware functions `ljust()`_, `rjust()`_, `center()`_,
|
||||
and the grapheme-aware function `wrap()`_, serving as drop-in replacements to python standard
|
||||
functions.
|
||||
|
||||
The `clip()`_ function extracts substrings by their displayed column positions, and
|
||||
`strip_sequences()`_ removes terminal escape sequences from text altogether.
|
||||
|
||||
The iterator functions `iter_graphemes()`_ and `iter_sequences()`_ allow for careful navigation of
|
||||
grapheme and terminal control sequence boundaries as required by editors or REPLs with cursor
|
||||
control. `iter_graphemes_reverse()`_ and `grapheme_boundary_before()`_ are necessary for backward
|
||||
cursor control over complex unicode.
|
||||
|
||||
Discrepancies
|
||||
-------------
|
||||
|
||||
You may find that support *varies* for complex unicode sequences or codepoints.
|
||||
|
||||
This library may be considered to presume the terminal is enabled for DEC Private Mode 2027
|
||||
("Grapheme Clustering") by default, which may require to be enabled by a TUI application but
|
||||
is often the default mode for those terminals that support it.
|
||||
|
||||
This library does not support any specific "legacy width" measurement by API, but it does provide
|
||||
Corrections_ for terminals using "legacy width" measurements or are without basic emoji or grapheme
|
||||
support.
|
||||
|
||||
See also:
|
||||
|
||||
- `terminal-unicode-core.tex`_ (2021)
|
||||
- `Grapheme Clusters and Terminal Emulators`_ (2023)
|
||||
- `State of Terminal Emulators in 2025`_
|
||||
- `Perfecting Terminal Character Width Using Correction Tables`_ (2026)
|
||||
|
||||
The `jquast/ucs-detect`_ project publishes automatic results of compliance to our standard for Wide
|
||||
character, Languages, grapheme clustering, complex or combining scripts, emojis, zero-width joiner,
|
||||
variations, and regional indicator (flags) as a `General Tabulated Summary`_ by terminal emulator
|
||||
software and version. The results of the ucs-detect project create our correction tables.
|
||||
|
||||
========
|
||||
Overview
|
||||
========
|
||||
|
||||
A brief overview, through examples, for all of the public API functions.
|
||||
|
||||
Full API Documentation at https://wcwidth.readthedocs.io/en/latest/api.html
|
||||
|
||||
wcwidth()
|
||||
---------
|
||||
|
||||
Measures width of a single codepoint,
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # '♀' narrow emoji
|
||||
>>> wcwidth.wcwidth('\u2640')
|
||||
1
|
||||
|
||||
Use function `wcwidth()`_ to determine the length of a *single unicode character*.
|
||||
|
||||
See specification_ of character measurements. Note that ``-1`` is returned for control codes.
|
||||
|
||||
wcswidth()
|
||||
----------
|
||||
|
||||
Measures width of a string, returns -1 for control codes.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # '♀️' emoji w/vs-16
|
||||
>>> wcwidth.wcswidth('\u2640\ufe0f')
|
||||
2
|
||||
|
||||
Use function `wcswidth()`_ to determine the length of many, a *string of unicode characters*.
|
||||
|
||||
See specification_ of character measurements. Note that ``-1`` is returned if control codes occurs
|
||||
anywhere in the string.
|
||||
|
||||
wcstwidth()
|
||||
-----------
|
||||
|
||||
`wcstwidth()`_ is a variant of `wcswidth()`_ that provides terminal-specific Corrections_, reading
|
||||
``TERM_PROGRAM`` or ``TERM`` when ``True`` (default), or caller can provide terminal query
|
||||
XTVERSION_ or ENQ_ response:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # '♀️' emoji w/vs-16, uncorrected:
|
||||
>>> wcwidth.wcswidth('\u2640\ufe0f')
|
||||
2
|
||||
>>> # corrected,
|
||||
>>> wcwidth.wcstwidth('\u2640\ufe0f', term_program='vte')
|
||||
1
|
||||
|
||||
width()
|
||||
-------
|
||||
|
||||
Use function `width()`_ to measure a string with improved handling of ``control_codes`` and
|
||||
measurement Corrections_ through ``term_program``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # same support as wcswidth(), eg. regional indicator flag:
|
||||
>>> wcwidth.width('\U0001F1FF\U0001F1FC')
|
||||
2
|
||||
>>> # set term_program=True to use wcstwidth()
|
||||
>>> wcwidth.width('\U0001F1FF\U0001F1FC', term_program=True)
|
||||
1
|
||||
>>> # or set term_program for measurement of a specific terminal
|
||||
>>> wcwidth.width('\U0001F1FF\U0001F1FC', term_program='contour')
|
||||
2
|
||||
>>> # but also supports sequences, like SGR colored text, "WARN", followed by reset
|
||||
>>> wcwidth.width('\x1b[38;2;255;150;100mWARN\x1b[0m')
|
||||
4
|
||||
>>> # tabs are measured as though the string begins at a tabstop,
|
||||
>>> wcwidth.width('\t', tabsize=4)
|
||||
4
|
||||
>>> # or, all control characters can be ignored (including tab)
|
||||
>>> wcwidth.width('\t\n\a\r', control_codes='ignore')
|
||||
0
|
||||
>>> # sequences with "indeterminate" effects like Home + Clear are zero-width
|
||||
>>> wcwidth.width('\x1b[H\x1b[2J')
|
||||
0
|
||||
>>> # horizontal cursor movements are parsed,
|
||||
>>> wcwidth.width('hello\b\b\b\b\bworld')
|
||||
5
|
||||
>>> wcwidth.width('hello\x1b[5Dworld')
|
||||
5
|
||||
>>> # or ignored,
|
||||
>>> wcwidth.width('hello\x1b[5Dworld', control_codes='ignore')
|
||||
10
|
||||
>>> # Measure width of text using kitty text sizing protocol (OSC 66),
|
||||
>>> width('\x1b]66;w=2;XY\x07')
|
||||
2
|
||||
>>> # Scaled text sizing: each grapheme occupies 'scale' cells
|
||||
>>> width('\x1b]66;s=2;ABC\x07')
|
||||
6
|
||||
|
||||
Use ``control_codes='ignore'`` when the input is known not to contain any control characters or
|
||||
terminal sequences for slightly improved performance. Note that TAB (``'\t'``) is a control
|
||||
character and is also ignored, you may want to use `str.expandtabs()`_, first.
|
||||
|
||||
Use ``control_codes='strict'`` when input is known to contain some control sequences, such as
|
||||
SGR color, bold, hyperlinks and cursor movement. Any sequence that cannot be accurately parsed
|
||||
for horizontal measurement, such as clearing the screen, vertical, or absolute cursor movement will
|
||||
raise ``ValueError``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # or, raise ValueError for "indeterminate" effects using control_codes='strict'
|
||||
>>> wcwidth.width('\n', control_codes='strict')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Vertical movement character 0xa at position 0
|
||||
|
||||
|
||||
>>> wcwidth.width('\x1b[H\x1b[2J', control_codes='strict')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Indeterminate cursor sequence at position 0, '\x1b[H'
|
||||
|
||||
|
||||
>>> # cursor left movement beyond string start raises in strict mode,
|
||||
>>> wcwidth.width('a\x1b[5Da', control_codes='strict')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Cursor left movement at position 1 would move 5 cells left from column 1, exceeding string start
|
||||
|
||||
iter_sequences()
|
||||
----------------
|
||||
|
||||
Iterates through text, segmented by terminal sequence,
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> list(wcwidth.iter_sequences('hello'))
|
||||
[('hello', False)]
|
||||
>>> list(wcwidth.iter_sequences('\x1b[31mred\x1b[0m'))
|
||||
[('\x1b[31m', True), ('red', False), ('\x1b[0m', True)]
|
||||
|
||||
Use `iter_sequences()`_ to split text into segments of plain text and escape sequences. Each tuple
|
||||
contains the segment string and a boolean indicating whether it is an escape sequence (``True``) or
|
||||
text (``False``).
|
||||
|
||||
iter_graphemes()
|
||||
----------------
|
||||
|
||||
Use `iter_graphemes()`_ to iterate over *grapheme clusters* of a string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from wcwidth import iter_graphemes
|
||||
>>> # ok + Regional Indicator 'Z', 'W' (Zimbabwe)
|
||||
>>> list(wcwidth.iter_graphemes('ok\U0001F1FF\U0001F1FC'))
|
||||
['o', 'k', '🇿🇼']
|
||||
|
||||
>>> # cafe + combining acute accent
|
||||
>>> list(wcwidth.iter_graphemes('cafe\u0301'))
|
||||
['c', 'a', 'f', 'é']
|
||||
|
||||
>>> # ok + Emoji Man + ZWJ + Woman + ZWJ + Girl
|
||||
>>> list(wcwidth.iter_graphemes('ok\U0001F468\u200D\U0001F469\u200D\U0001F467'))
|
||||
['o', 'k', '👨\u200d👩\u200d👧']
|
||||
|
||||
A grapheme cluster is what a user perceives as a single character, even if it is composed of
|
||||
multiple Unicode codepoints. This function implements `Unicode Standard Annex #29`_ grapheme cluster
|
||||
boundary rules.
|
||||
|
||||
ljust()
|
||||
-------
|
||||
|
||||
Use `ljust()`_ as replacement of `str.ljust()`_:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> 'コンニチハ'.ljust(11, '*') # don't do this
|
||||
'コンニチハ******'
|
||||
>>> wcwidth.ljust('コンニチハ', 11, '*') # do this!
|
||||
'コンニチハ*'
|
||||
|
||||
rjust()
|
||||
-------
|
||||
|
||||
Use `rjust()`_ as replacement of `str.rjust()`_:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> 'コンニチハ'.rjust(11, '*') # don't do this
|
||||
'******コンニチハ'
|
||||
>>> wcwidth.rjust('コンニチハ', 11, '*') # do this!
|
||||
'*コンニチハ'
|
||||
|
||||
center()
|
||||
--------
|
||||
|
||||
Use `center()`_ as replacement of `str.center()`_:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> 'cafe\u0301'.center(6, '*') # don't do this
|
||||
'café*'
|
||||
>>> wcwidth.center('cafe\u0301', 6, '*')
|
||||
'*café*' # do this!
|
||||
|
||||
wrap()
|
||||
------
|
||||
|
||||
Use function `wrap()`_ to wrap text containing terminal sequences, Unicode grapheme
|
||||
clusters, and wide characters to a given display width.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from wcwidth import wrap
|
||||
>>> # Basic wrapping
|
||||
>>> wrap('hello world', 5)
|
||||
['hello', 'world']
|
||||
|
||||
>>> # Wrapping CJK text (each character is 2 cells wide)
|
||||
>>> wrap('コンニチハ', 4)
|
||||
['コン', 'ニチ', 'ハ']
|
||||
|
||||
>>> # Text with ANSI color sequences - SGR codes are propagated by default
|
||||
>>> # Each line ends with reset, next line starts with restored style
|
||||
>>> wrap('\x1b[1;31mhello world\x1b[0m', 5)
|
||||
['\x1b[1;31mhello\x1b[0m', '\x1b[1;31mworld\x1b[0m']
|
||||
|
||||
clip()
|
||||
------
|
||||
|
||||
Use `clip()`_ to extract a substring by column positions, preserving terminal sequences.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from wcwidth import clip
|
||||
>>> # Wide characters split to Narrow boundaries using fillchar=' '
|
||||
>>> clip('中文字', 0, 3)
|
||||
'中 '
|
||||
>>> clip('中文字', 1, 5, fillchar='.')
|
||||
'.文.'
|
||||
|
||||
>>> # 'end' defaults to -1, meaning "to the end of the line"
|
||||
>>> clip('中文字', 1)
|
||||
' 文字'
|
||||
>>> clip('\x1b[1;31mHello world\x1b[0m', 6)
|
||||
'\x1b[1;31mworld\x1b[0m'
|
||||
|
||||
>>> # SGR codes are propagated by default - result begins with active style
|
||||
>>> # and ends with reset if styles are active
|
||||
>>> clip('\x1b[1;31mHello world\x1b[0m', 6, 11)
|
||||
'\x1b[1;31mworld\x1b[0m'
|
||||
|
||||
>>> # Disable SGR propagation to preserve sequence order outside of clip boundary
|
||||
>>> clip('\x1b[31m中文\x1b[32m', 0, 3, propagate_sgr=False)
|
||||
'\x1b[31m中 \x1b[32m'
|
||||
|
||||
>>> # Cursor-left overwrites previous text (painter's algorithm)
|
||||
>>> clip('hello\x1b[2DXY', 0, 5)
|
||||
'helXY'
|
||||
>>> # Carriage return resets to column 0, overwriting earlier cells
|
||||
>>> clip('abc\rXY', 0, 5)
|
||||
'XYc'
|
||||
|
||||
>>> # even OSC 8 hyperlink text may be clipped, 'Click This link' -> 'is link' !
|
||||
>>> clip('\x1b]8;;http://example.com\x07Click This link\x1b]8;;\x07', 8, 15)
|
||||
'\x1b]8;;http://example.com\x07is link\x1b]8;;\x07'
|
||||
|
||||
>>> # and OSC 66 kitty text sizing, supporting width and scale, 'Look' -> '...ook'
|
||||
>>> clip('\x1b]66;w=4:s=4;Look\x07', 1, 16, fillchar='.')
|
||||
'...\x1b]66;s=4:w=3;ook\x07'
|
||||
|
||||
Use ``overtyping=False`` when the input is known not to contain any cursor movement characters
|
||||
(``\b``, ``\r``, ``CSI C``, ``CSI D``, ``CSI G``) for improved performance. When
|
||||
``overtyping=None`` (default), a slower "Painter's algorithm" may be used after testing for the
|
||||
presence of these characters. ``overtyping`` has no effect when ``control_codes='ignore'``.
|
||||
|
||||
strip_sequences()
|
||||
-----------------
|
||||
|
||||
Use `strip_sequences()`_ to remove all terminal escape sequences from text.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from wcwidth import strip_sequences
|
||||
>>> strip_sequences('\x1b[31mred\x1b[0m')
|
||||
'red'
|
||||
|
||||
.. _ambiguous_width:
|
||||
|
||||
Ambiguous Width
|
||||
---------------
|
||||
|
||||
Some Unicode characters have "East Asian Ambiguous" (A) width. These characters display as 1 cell by
|
||||
default, matching Western terminal contexts, but many CJK (Chinese, Japanese, Korean) environments
|
||||
may have a preference for 2 cells. This is often found as boolean option, "Ambiguous width as wide"
|
||||
in Terminal Emulator software preferences.
|
||||
|
||||
The ``ambiguous_width`` parameter is available on all width-measuring functions: `wcwidth()`_,
|
||||
`wcswidth()`_, `width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
|
||||
|
||||
By default, wcwidth treats ambiguous characters as narrow (width 1). For CJK environments where your
|
||||
terminal is configured to display ambiguous characters as double-width, pass ``ambiguous_width=2``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # CIRCLED DIGIT ONE - ambiguous width
|
||||
>>> wcwidth.width('\u2460')
|
||||
1
|
||||
>>> wcwidth.width('\u2460', ambiguous_width=2)
|
||||
2
|
||||
|
||||
**Terminal Detection**
|
||||
|
||||
The most reliable method to detect whether a terminal profile is set for "Ambiguous width as wide"
|
||||
mode is to display an ambiguous character surrounded by a pair of Cursor Position Report (CPR)
|
||||
queries with a terminal in cooked or raw mode, and to parse the responses for their ``(y, x)``
|
||||
locations and measure the difference ``x``.
|
||||
|
||||
This code should also be careful to check whether it is attached to a terminal and be careful of
|
||||
possible timeout, slow network, or non-response when working with "dumb terminals" like a CI build.
|
||||
|
||||
`jquast/blessed`_ library provides such a helping `Terminal.detect_ambiguous_width()`_ method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import blessed, functools
|
||||
>>> # Detect terminal ambiguous width as wide (2) or narrow (1)
|
||||
>>> ambiguous_width = blessed.Terminal().detect_ambiguous_width()
|
||||
>>> # Define a new 'width' function with this argument
|
||||
>>> awidth = functools.partial(wcwidth.width, ambiguous_width=ambiguous_width)
|
||||
>>> # result depends on attached terminal mode
|
||||
>>> awidth('\u2460')
|
||||
1
|
||||
|
||||
Corrections
|
||||
-----------
|
||||
|
||||
Corrections may be automatically applied depending on the detected or given terminal software name
|
||||
beginning with wcwidth release 0.8.0. This allows to correct widths for terminal software that
|
||||
differs from the python wcwidth specification_. These corrections are sourced from the
|
||||
`jquast/ucs-detect`_ project.
|
||||
|
||||
The ``term_program`` parameter is available on all width-measuring functions: `wcstwidth()`_,
|
||||
`width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
|
||||
|
||||
`wcstwidth()`_ defaults to ``term_program=True``, auto-detecting the terminal from the
|
||||
``TERM_PROGRAM`` or ``TERM`` environment variable. All other functions default to
|
||||
``term_program=False``, disabling corrections. Use ``term_program=True`` for automatic
|
||||
detection by environment values of ``TERM`` and ``TERM_PROGRAM``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# VTE terminals (Gnome Terminal Et al.) still render trigrams as narrow (1 cell), but their
|
||||
# definition was changed to wide in Unicode 16 (September 2024).
|
||||
>>> wcwidth.wcswidth('\u2630')
|
||||
2
|
||||
>>> wcwidth.wcstwidth('\u2630', term_program='vte')
|
||||
1
|
||||
|
||||
# account for Alacritty non-support of emoji ZWJ:
|
||||
# man + ZWJ + woman + ZWJ + girl + ZWJ + boy
|
||||
>>> family = '\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466'
|
||||
>>> wcwidth.wcswidth(family)
|
||||
2
|
||||
>>> wcwidth.wcstwidth(family, term_program='alacritty')
|
||||
8
|
||||
|
||||
Only detectable_ terminals are included: those that identify themselves by XTVERSION_, ENQ_, any
|
||||
``TERM_PROGRAM`` or a unique ``TERM`` environment value. For the most accurate correction tables,
|
||||
query the terminal's software version via XTVERSION_ (``CSI > q``) using a higher-level interactive
|
||||
terminal library like `jquast/blessed`_:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import blessed, wcwidth
|
||||
>>> term = blessed.Terminal()
|
||||
>>> sw_ver = term.get_software_version()
|
||||
>>> print(sw_ver)
|
||||
SoftwareVersion(name='VTE', version='7600')
|
||||
>>> wcwidth.width('\u2630', term_program=sw_ver.name)
|
||||
1
|
||||
|
||||
This is important because ``TERM_PROGRAM`` is not forwarded for remote hosts, like SSH, and many
|
||||
terminals may only be identified using XTVERSION_ or ENQ_. Use `list_term_programs()`_ to see all
|
||||
recognized names:
|
||||
|
||||
.. BEGIN_LIST_TERM_PROGRAMS
|
||||
.. code-block:: python
|
||||
|
||||
>>> wcwidth.list_term_programs()
|
||||
('absolutetelnet/ssh', 'alacritty', 'apple_terminal', 'bobcat', 'contour',
|
||||
'extraterm', 'foot', 'ghostty', 'hyper', 'iterm.app', 'iterm2', 'kitty',
|
||||
'konsole', 'mintty', 'mlterm', 'pterm', 'putty', 'rio', 'rxvt',
|
||||
'rxvt-unicode-256color', 'st', 'st-256color', 'tabby', 'terminology',
|
||||
'urxvt', 'vscode', 'vte', 'warp', 'warpterminal', 'wezterm', 'xterm',
|
||||
'xterm-ghostty', 'xterm-kitty', 'xterm.js')
|
||||
|
||||
.. END_LIST_TERM_PROGRAMS
|
||||
|
||||
``term_program=False`` (the default for `width()`_, `ljust()`_, `rjust()`_, `center()`_,
|
||||
`wrap()`_, and `clip()`_) disables terminal corrections.
|
||||
|
||||
For automatic tests and other purposes that require cross-environment consistency, set static values
|
||||
or unset ``TERM`` and ``TERM_PROGRAM`` environment values, such as in ``conftest.py`` with pytest:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_term_program():
|
||||
"""unset TERM/TERM_PROGRAM before each test."""
|
||||
saved_term = os.environ.pop('TERM', None)
|
||||
saved_tprog = os.environ.pop('TERM_PROGRAM', None)
|
||||
yield
|
||||
if saved_term is not None:
|
||||
os.environ['TERM'] = saved_term
|
||||
if saved_tprog is not None:
|
||||
os.environ['TERM_PROGRAM'] = saved_tprog
|
||||
|
||||
==================
|
||||
More documentation
|
||||
==================
|
||||
|
||||
Developer documentation, for building and contributing to this project, at
|
||||
https://wcwidth.readthedocs.io/en/latest/developing.html
|
||||
|
||||
Projects using wcwidth, and implementations in other languages, at
|
||||
https://wcwidth.readthedocs.io/en/latest/related.html
|
||||
|
||||
.. _`specification`: https://wcwidth.readthedocs.io/en/latest/specs.html
|
||||
.. _`jquast/blessed`: https://github.com/jquast/blessed
|
||||
.. _`wcwidth(3)`: https://man7.org/linux/man-pages/man3/wcwidth.3.html
|
||||
.. _`wcswidth(3)`: https://man7.org/linux/man-pages/man3/wcswidth.3.html
|
||||
.. _`jquast/ucs-detect`: https://github.com/jquast/ucs-detect
|
||||
.. _`textwrap.wrap()`: https://docs.python.org/3/library/textwrap.html#textwrap.wrap
|
||||
.. _`str.ljust()`: https://docs.python.org/3/library/stdtypes.html#str.ljust
|
||||
.. _`str.rjust()`: https://docs.python.org/3/library/stdtypes.html#str.rjust
|
||||
.. _`str.center()`: https://docs.python.org/3/library/stdtypes.html#str.center
|
||||
.. _`str.expandtabs()`: https://docs.python.org/3/library/stdtypes.html#str.expandtabs
|
||||
.. _`General Tabulated Summary`: https://ucs-detect.readthedocs.io/results.html#general-tabulated-summary
|
||||
.. _`wcwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcwidth
|
||||
.. _`wcswidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcswidth
|
||||
.. _`wcstwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcstwidth
|
||||
.. _`width()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.width
|
||||
.. _`iter_graphemes()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes
|
||||
.. _`iter_graphemes_reverse()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes_reverse
|
||||
.. _`grapheme_boundary_before()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.grapheme_boundary_before
|
||||
.. _`ljust()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.ljust
|
||||
.. _`rjust()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.rjust
|
||||
.. _`center()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.center
|
||||
.. _`wrap()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wrap
|
||||
.. _`clip()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.clip
|
||||
.. _`strip_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.strip_sequences
|
||||
.. _`iter_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_sequences
|
||||
.. _`list_term_programs()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.list_term_programs
|
||||
.. _`Unicode Standard Annex #29`: https://www.unicode.org/reports/tr29/
|
||||
.. _`Terminal.detect_ambiguous_width()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.detect_ambiguous_width
|
||||
.. _`Grapheme Clusters and Terminal Emulators`: https://mitchellh.com/writing/grapheme-clusters-in-terminals
|
||||
.. _`terminal-unicode-core.tex`: https://github.com/contour-terminal/terminal-unicode-core/blob/master/spec/terminal-unicode-core.tex
|
||||
.. _`State of Terminal Emulators in 2025`: https://www.jeffquast.com/post/state-of-terminal-emulation-2025/
|
||||
.. _`Perfecting Terminal Character Width Using Correction Tables`: https://www.jeffquast.com/post/perfecting-terminal-character-width-using-correction-tables/
|
||||
.. _XTVERSION: https://vtdn.dev/docs/dcs/xtversion/
|
||||
.. _ENQ: https://documentation.help/PuTTY/config-answerback.html
|
||||
.. _detectable: https://ucs-detect.readthedocs.io/results.html#terminal-identification
|
||||
.. _libwcwidth: https://wcwidth.readthedocs.io/en/latest/libwcwidth.html
|
||||
.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi
|
||||
:alt: Downloads
|
||||
:target: https://pypi.org/project/wcwidth/
|
||||
.. |codecov| image:: https://codecov.io/gh/jquast/wcwidth/branch/master/graph/badge.svg
|
||||
:alt: codecov.io Code Coverage
|
||||
:target: https://app.codecov.io/gh/jquast/wcwidth/
|
||||
.. |license| image:: https://img.shields.io/pypi/l/wcwidth.svg
|
||||
:target: https://pypi.org/project/wcwidth/
|
||||
:alt: MIT License
|
||||
|
||||
Reference in New Issue
Block a user