METADATA 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. Metadata-Version: 2.4
  2. Name: wcwidth
  3. Version: 0.6.0
  4. Summary: Measures the displayed width of unicode strings in a terminal
  5. Project-URL: Homepage, https://github.com/jquast/wcwidth
  6. Author-email: Jeff Quast <contact@jeffquast.com>
  7. License-Expression: MIT
  8. License-File: LICENSE
  9. Keywords: cjk,combining,console,eastasian,emoji,emulator,terminal,unicode,wcswidth,wcwidth,xterm
  10. Classifier: Development Status :: 5 - Production/Stable
  11. Classifier: Environment :: Console
  12. Classifier: Intended Audience :: Developers
  13. Classifier: Natural Language :: English
  14. Classifier: Operating System :: POSIX
  15. Classifier: Programming Language :: Python :: 3 :: Only
  16. Classifier: Programming Language :: Python :: 3.8
  17. Classifier: Programming Language :: Python :: 3.9
  18. Classifier: Programming Language :: Python :: 3.10
  19. Classifier: Programming Language :: Python :: 3.11
  20. Classifier: Programming Language :: Python :: 3.12
  21. Classifier: Programming Language :: Python :: 3.13
  22. Classifier: Programming Language :: Python :: 3.14
  23. Classifier: Topic :: Software Development :: Internationalization
  24. Classifier: Topic :: Software Development :: Libraries
  25. Classifier: Topic :: Software Development :: Localization
  26. Classifier: Topic :: Terminals
  27. Classifier: Typing :: Typed
  28. Requires-Python: >=3.8
  29. Description-Content-Type: text/x-rst
  30. |pypi_downloads| |codecov| |license|
  31. ============
  32. Introduction
  33. ============
  34. This library is mainly for CLI/TUI programs that carefully produce output for Terminals.
  35. Installation
  36. ------------
  37. The stable version of this package is maintained on pypi, install or upgrade, using pip::
  38. pip install --upgrade wcwidth
  39. Problem
  40. -------
  41. All Python string-formatting functions, `textwrap.wrap()`_, `str.ljust()`_, `str.rjust()`_, and
  42. `str.center()`_ **incorrectly** measure the displayed width of a string as equal to the number of
  43. their codepoints.
  44. Some examples of **incorrect results**:
  45. .. code-block:: python
  46. >>> # result consumes 16 total cells, 11 expected,
  47. >>> 'コンニチハ'.rjust(11, 'X')
  48. 'XXXXXXコンニチハ'
  49. >>> # result consumes 5 total cells, 6 expected,
  50. >>> 'café'.center(6, 'X')
  51. 'caféX'
  52. Solution
  53. --------
  54. The lowest-level functions in this library are the POSIX.1-2001 and POSIX.1-2008 `wcwidth(3)`_ and
  55. `wcswidth(3)`_, which this library precisely copies by interface as `wcwidth()`_ and `wcswidth()`_.
  56. These functions return -1 when C0 and C1 control codes are present.
  57. An easy-to-use `width()`_ function is provided as a wrapper of `wcswidth()`_ that is also capable of
  58. measuring most terminal control codes and sequences, like colors, bold, tabstops, and horizontal
  59. cursor movement.
  60. Text-justification is solved by the grapheme and sequence-aware functions `ljust()`_,
  61. `rjust()`_, `center()`_, and `wrap()`_, serving as drop-in replacements to python standard functions
  62. of the same names.
  63. The iterator functions `iter_graphemes()`_ and `iter_sequences()`_ allow for careful navigation of
  64. grapheme and terminal control sequence boundaries. `iter_graphemes_reverse()`_, and
  65. `grapheme_boundary_before()`_ are useful for editing and searching of complex unicode. The
  66. `clip()`_ function extracts substrings by display column positions, and `strip_sequences()`_ removes
  67. terminal escape sequences from text altogether.
  68. Discrepancies
  69. -------------
  70. You may find that support *varies* for complex unicode sequences or codepoints.
  71. A companion utility, `jquast/ucs-detect`_ was authored to gather and publish the results of Wide
  72. character, language/grapheme clustering and complex script support, emojis and zero-width joiner,
  73. variations, and regional indicator (flags) as a `General Tabulated Summary`_ by terminal emulator
  74. software and version.
  75. ========
  76. Overview
  77. ========
  78. wcwidth()
  79. ---------
  80. Use function ``wcwidth()`` to determine the length of a *single unicode
  81. codepoint*.
  82. A brief overview, through examples, for all of the public API functions.
  83. Full API Documentation at https://wcwidth.readthedocs.io/en/latest/api.html
  84. wcwidth()
  85. ---------
  86. Measures width of a single codepoint,
  87. .. code-block:: python
  88. >>> # '♀' narrow emoji
  89. >>> wcwidth.wcwidth('\u2640')
  90. 1
  91. Use function `wcwidth()`_ to determine the length of a *single unicode character*.
  92. See specification_ of character measurements. Note that ``-1`` is returned for control codes.
  93. wcswidth()
  94. ----------
  95. Measures width of a string, returns -1 for control codes.
  96. .. code-block:: python
  97. >>> # '♀️' emoji w/vs-16
  98. >>> wcwidth.wcswidth('\u2640\ufe0f')
  99. 2
  100. Use function `wcswidth()`_ to determine the length of many, a *string of unicode characters*.
  101. See specification_ of character measurements. Note that ``-1`` is returned if control codes occurs
  102. anywhere in the string.
  103. width()
  104. -------
  105. Use function `width()`_ to measure a string with improved handling of ``control_codes``.
  106. .. code-block:: python
  107. >>> # same support as wcswidth(), eg. regional indicator flag:
  108. >>> wcwidth.width('\U0001F1FF\U0001F1FC')
  109. 2
  110. >>> # but also supports SGR colored text, 'WARN', followed by SGR reset
  111. >>> wcwidth.width('\x1b[38;2;255;150;100mWARN\x1b[0m')
  112. 4
  113. >>> # tabs,
  114. >>> wcwidth.width('\t', tabsize=4)
  115. 4
  116. >>> # or, tab and all other control characters can be ignored
  117. >>> wcwidth.width('\t', control_codes='ignore')
  118. 0
  119. >>> # "vertical" control characters are ignored
  120. >>> wcwidth.width('\n')
  121. 0
  122. >>> # as well as sequences with "indeterminate" effects like Home + Clear
  123. >>> wcwidth.width('\x1b[H\x1b[2J')
  124. 0
  125. >>> # or, raise ValueError for "indeterminate" effects using control_codes='strict'
  126. >>> wcwidth.width('\n', control_codes='strict')
  127. Traceback (most recent call last):
  128. ...
  129. ValueError: Vertical movement character 0xa at position 0
  130. Use ``control_codes='ignore'`` when the input is known not to contain any control characters or
  131. terminal sequences for slightly improved performance. Note that TAB (``'\t'``) is a control
  132. character and is also ignored, you may want to use `str.expandtabs()`_, first.
  133. iter_sequences()
  134. ----------------
  135. Iterates through text, segmented by terminal sequence,
  136. .. code-block:: python
  137. >>> list(wcwidth.iter_sequences('hello'))
  138. [('hello', False)]
  139. >>> list(wcwidth.iter_sequences('\x1b[31mred\x1b[0m'))
  140. [('\x1b[31m', True), ('red', False), ('\x1b[0m', True)]
  141. Use `iter_sequences()`_ to split text into segments of plain text and escape sequences. Each tuple
  142. contains the segment string and a boolean indicating whether it is an escape sequence (``True``) or
  143. text (``False``).
  144. iter_graphemes()
  145. ----------------
  146. Use `iter_graphemes()`_ to iterate over *grapheme clusters* of a string.
  147. .. code-block:: python
  148. >>> from wcwidth import iter_graphemes
  149. >>> # ok + Regional Indicator 'Z', 'W' (Zimbabwe)
  150. >>> list(wcwidth.iter_graphemes('ok\U0001F1FF\U0001F1FC'))
  151. ['o', 'k', '🇿🇼']
  152. >>> # cafe + combining acute accent
  153. >>> list(wcwidth.iter_graphemes('cafe\u0301'))
  154. ['c', 'a', 'f', 'é']
  155. >>> # ok + Emoji Man + ZWJ + Woman + ZWJ + Girl
  156. >>> list(wcwidth.iter_graphemes('ok\U0001F468\u200D\U0001F469\u200D\U0001F467'))
  157. ['o', 'k', '👨\u200d👩\u200d👧']
  158. A grapheme cluster is what a user perceives as a single character, even if it is composed of
  159. multiple Unicode codepoints. This function implements `Unicode Standard Annex #29`_ grapheme cluster
  160. boundary rules.
  161. ljust()
  162. -------
  163. Use `ljust()`_ as replacement of `str.ljust()`_:
  164. .. code-block:: python
  165. >>> 'コンニチハ'.ljust(11, '*') # don't do this
  166. 'コンニチハ******'
  167. >>> wcwidth.ljust('コンニチハ', 11, '*') # do this!
  168. 'コンニチハ*'
  169. rjust()
  170. -------
  171. Use `rjust()`_ as replacement of `str.rjust()`_:
  172. .. code-block:: python
  173. >>> 'コンニチハ'.rjust(11, '*') # don't do this
  174. '******コンニチハ'
  175. >>> wcwidth.rjust('コンニチハ', 11, '*') # do this!
  176. '*コンニチハ'
  177. center()
  178. --------
  179. Use `center()`_ as replacement of `str.center()`_:
  180. .. code-block:: python
  181. >>> 'cafe\u0301'.center(6, '*') # don't do this
  182. 'café*'
  183. >>> wcwidth.center('cafe\u0301', 6, '*')
  184. '*café*' # do this!
  185. wrap()
  186. ------
  187. Use function `wrap()`_ to wrap text containing terminal sequences, Unicode grapheme
  188. clusters, and wide characters to a given display width.
  189. .. code-block:: python
  190. >>> from wcwidth import wrap
  191. >>> # Basic wrapping
  192. >>> wrap('hello world', 5)
  193. ['hello', 'world']
  194. >>> # Wrapping CJK text (each character is 2 cells wide)
  195. >>> wrap('コンニチハ', 4)
  196. ['コン', 'ニチ', 'ハ']
  197. >>> # Text with ANSI color sequences - SGR codes are propagated by default
  198. >>> # Each line ends with reset, next line starts with restored style
  199. >>> wrap('\x1b[1;31mhello world\x1b[0m', 5)
  200. ['\x1b[1;31mhello\x1b[0m', '\x1b[1;31mworld\x1b[0m']
  201. clip()
  202. ------
  203. Use `clip()`_ to extract a substring by column positions, preserving terminal sequences.
  204. .. code-block:: python
  205. >>> from wcwidth import clip
  206. >>> # Wide characters split to Narrow boundaries using fillchar=' '
  207. >>> clip('中文字', 0, 3)
  208. '中 '
  209. >>> clip('中文字', 1, 5, fillchar='.')
  210. '.文.'
  211. >>> # SGR codes are propagated by default - result begins with active style
  212. >>> # and ends with reset if styles are active
  213. >>> clip('\x1b[1;31mHello world\x1b[0m', 6, 11)
  214. '\x1b[1;31mworld\x1b[0m'
  215. >>> # Disable SGR propagation to preserve original sequences as-is
  216. >>> clip('\x1b[31m中文\x1b[0m', 0, 3, propagate_sgr=False)
  217. '\x1b[31m中 \x1b[0m'
  218. strip_sequences()
  219. -----------------
  220. Use `strip_sequences()`_ to remove all terminal escape sequences from text.
  221. .. code-block:: python
  222. >>> from wcwidth import strip_sequences
  223. >>> strip_sequences('\x1b[31mred\x1b[0m')
  224. 'red'
  225. .. _ambiguous_width:
  226. ambiguous_width
  227. ---------------
  228. Some Unicode characters have "East Asian Ambiguous" (A) width. These characters display as 1 cell by
  229. default, matching Western terminal contexts, but many CJK (Chinese, Japanese, Korean) environments
  230. may have a preference for 2 cells. This is often found as boolean option, "Ambiguous width as wide"
  231. in Terminal Emulator software preferences.
  232. By default, wcwidth treats ambiguous characters as narrow (width 1). For CJK environments where your
  233. terminal is configured to display ambiguous characters as double-width, pass ``ambiguous_width=2``:
  234. .. code-block:: python
  235. >>> # CIRCLED DIGIT ONE - ambiguous width
  236. >>> wcwidth.width('\u2460')
  237. 1
  238. >>> wcwidth.width('\u2460', ambiguous_width=2)
  239. 2
  240. The ``ambiguous_width`` parameter is available on all width-measuring functions: `wcwidth()`_,
  241. `wcswidth()`_, `width()`_, `ljust()`_, `rjust()`_, `center()`_, `wrap()`_, and `clip()`_.
  242. **Terminal Detection**
  243. The most reliable method to detect whether a terminal profile is set for "Ambiguous width as wide"
  244. mode is to display an ambiguous character surrounded by a pair of Cursor Position Report (CPR)
  245. queries with a terminal in cooked or raw mode, and to parse the responses for their ``(y, x)``
  246. locations and measure the difference ``x``.
  247. This code should also be careful check whether it is attached to a terminal and be careful of
  248. possible timeout, slow network, or non-response when working with "dumb terminals" like a CI build.
  249. `jquast/blessed`_ library provides such a helping `Terminal.detect_ambiguous_width()`_ method:
  250. .. code-block:: python
  251. >>> import blessed, functools
  252. >>> # Detect terminal ambiguous width as wide (2) or narrow (1)
  253. >>> ambiguous_width = blessed.Terminal().detect_ambiguous_width()
  254. >>> # Define a new 'width' function with this argument
  255. >>> awidth = functools.partial(wcwidth.width, ambiguous_width=ambiguous_width)
  256. >>> # result depends on attached terminal mode
  257. >>> awidth('\u2460')
  258. 1
  259. ==========
  260. Developing
  261. ==========
  262. Install wcwidth in editable mode::
  263. pip install -e .
  264. Execute all code generation, autoformatters, linters and unit tests using tox::
  265. tox
  266. Or execute individual tasks, see ``tox -lv`` for all available targets::
  267. tox -e pylint,py36,py314
  268. To run tests with detailed coverage reporting showing missing lines::
  269. tox -epy314 -- --cov-report=term-missing
  270. Updating Unicode Version
  271. ------------------------
  272. Regenerate python code tables from latest Unicode Specification data files::
  273. tox -e update
  274. The script is located at ``bin/update-tables.py``, requires Python 3.9 or
  275. later. It is recommended but not necessary to run this script with the newest
  276. Python, because the newest Python has the latest ``unicodedata`` for generating
  277. comments.
  278. Building Documentation
  279. ----------------------
  280. This project is using `sphinx`_ 4.5 to build documentation::
  281. tox -e sphinx
  282. The output will be in ``docs/_build/html/``.
  283. Updating Requirements
  284. ---------------------
  285. This project is using `pip-tools`_ to manage requirements.
  286. To upgrade requirements for updating unicode version, run::
  287. tox -e update_requirements_update
  288. To upgrade requirements for testing, run::
  289. tox -e update_requirements38,update_requirements39
  290. To upgrade requirements for building documentation, run::
  291. tox -e update_requirements_docs
  292. Utilities
  293. ---------
  294. Supplementary tools for browsing and testing terminals for wide unicode
  295. characters are found in the `bin/`_ of this project's source code. Just ensure
  296. to first ``pip install -r requirements-develop.txt`` from this projects main
  297. folder. For example, an interactive browser for testing::
  298. python ./bin/wcwidth-browser.py
  299. ====
  300. Uses
  301. ====
  302. This library is used in:
  303. - `jquast/blessed`_: a thin, practical wrapper around terminal capabilities in
  304. Python.
  305. - `prompt-toolkit/python-prompt-toolkit`_: a Library for building powerful
  306. interactive command lines in Python.
  307. - `dbcli/pgcli`_: Postgres CLI with autocompletion and syntax highlighting.
  308. - `thomasballinger/curtsies`_: a Curses-like terminal wrapper with a display
  309. based on compositing 2d arrays of text.
  310. - `selectel/pyte`_: Simple VTXXX-compatible linux terminal emulator.
  311. - `astanin/python-tabulate`_: Pretty-print tabular data in Python, a library
  312. and a command-line utility.
  313. - `rspeer/python-ftfy`_: Fixes mojibake and other glitches in Unicode
  314. text.
  315. - `nbedos/termtosvg`_: Terminal recorder that renders sessions as SVG
  316. animations.
  317. - `peterbrittain/asciimatics`_: Package to help people create full-screen text
  318. UIs.
  319. - `python-cmd2/cmd2`_: A tool for building interactive command line apps
  320. - `stratis-storage/stratis-cli`_: CLI for the Stratis project
  321. - `ihabunek/toot`_: A Mastodon CLI/TUI client
  322. - `saulpw/visidata`_: Terminal spreadsheet multitool for discovering and
  323. arranging data
  324. - `jquast/ucs-detect`_: Utility for unicode support detection.
  325. ===============
  326. Other Languages
  327. ===============
  328. There are similar implementations of the `wcwidth()`_ and `wcswidth()`_ functions in other
  329. languages.
  330. - `timoxley/wcwidth`_: JavaScript
  331. - `janlelis/unicode-display_width`_: Ruby
  332. - `alecrabbit/php-wcwidth`_: PHP
  333. - `Text::CharWidth`_: Perl
  334. - `bluebear94/Terminal-WCWidth`_: Perl 6
  335. - `mattn/go-runewidth`_: Go
  336. - `grepsuzette/wcwidth`_: Haxe
  337. - `aperezdc/lua-wcwidth`_: Lua
  338. - `joachimschmidt557/zig-wcwidth`_: Zig
  339. - `fumiyas/wcwidth-cjk`_: `LD_PRELOAD` override
  340. - `joshuarubin/wcwidth9`_: Unicode version 9 in C
  341. - `spectreconsole/wcwidth`_: C#
  342. =======
  343. History
  344. =======
  345. 0.6.0 *2026-02-06*
  346. * **New** Parameters ``expand_tabs``, ``replace_whitespace``, ``fix_sentence_endings``,
  347. ``drop_whitespace``, ``max_lines``, and ``placeholder`` for `wrap()`_, completing stdlib
  348. `textwrap.wrap()`_ compatibility.
  349. 0.5.3 *2026-01-30*
  350. * **Bugfix** Brahmic using Virama conjunct formation. `Issue #155`_, `PR #204`_.
  351. 0.5.2 *2026-01-29*
  352. * **Bugfix** Measurement of category ``Mc`` (`Spacing Combining Mark`_), approx. 443, has a more
  353. nuanced specification_, and may be categorized as either zero or wide. `PR #200`_.
  354. * **Bugfix** Measurement of "standalone" modifiers and regional indicators, `PR #202`_.
  355. * **Updated** Data files used in some automatic tests are no longer distributed. `PR #199`_
  356. 0.5.1 *2026-01-27*
  357. * **Updated** generated zero and wide code tables to length of 1 to complete the previously
  358. announced removal of historical wide and zero tables. `PR #196`_.
  359. 0.5.0 *2026-01-26*
  360. * **Drop Support** of many historical versions of wide and zero unicode tables. Only the latest
  361. Unicode version (17.0.0) is now shipped. The related ``unicode_version='auto'`` keyword of the
  362. `wcwidth()`_ family of functions are ignored. `list_versions()`_ always returns a tuple of only
  363. a single element of the only unicode version supported. `PR #195`_.
  364. * **Performance** improvement of most common call without version or ambiguous_width specified by
  365. 20%. `PR #195`_.
  366. * **New** Function `propagate_sgr()`_ for applying SGR state propagation to a list of lines.
  367. `PR #194`_.
  368. * **Improved** `wrap()`_ and `clip()`_ with ``propagate_sgr=True``. `PR #194`_.
  369. * **Bugfix** `clip()`_ zero-width characters at clipping boundaries. `PR #194`_.
  370. * **Bugfix** OSC Hyperlinks when broken mid-text by `wrap()`_. `PR #193`_.
  371. 0.4.0 *2026-01-25*
  372. * **New** Functions `iter_graphemes_reverse()`_, `grapheme_boundary_before()`_. `PR #192`_.
  373. * **Bugfix** OSC Hyperlinks should not be broken by `wrap()`_. `PR #191`_.
  374. 0.3.5 *2026-01-24*
  375. * **Bugfix** packaging of 0.3.4 contains a failing test.
  376. 0.3.4 *2026-01-24*
  377. * **Bugfix** `center()`_ should match the eccentric `parity padding`_.
  378. of `str.center()`_. `PR #188`_.
  379. 0.3.3 *2026-01-24*
  380. * **Performance** improvement in `width()`_. `PR #185`_.
  381. * **Bugfix** missing ``py.typed``, ``Typing :: Typed``. `PR #184`_.
  382. 0.3.2 *2026-01-23*
  383. * **Updated** type hinting for full ``mympy --strict`` compliance. `PR #183`_.
  384. 0.3.1 *2026-01-22*
  385. * **Performance** improvement up to 30% in `width()_`. `PR #181`_.
  386. 0.3.0 *2026-01-21*
  387. * **Drop Support** for Python 3.6 and 3.7. `PR #156`_.
  388. * **New** Function `iter_graphemes()`_. `PR #165`_.
  389. * **New** Functions `width()`_ and `iter_sequences()`_. `PR #166`_.
  390. * **New** Functions `ljust()`_, `rjust()`_, `center()`_. `PR #168`_.
  391. * **New** Function `wrap()`_. `PR #169`_.
  392. * **Performance** improvement in `wcswidth()`_. `PR #171`_.
  393. * **New** argument ``ambiguous_width`` to all functions. `PR #172`_.
  394. * **New** Functions `clip()`_ and `strip_sequences()`_. `PR #173`_.
  395. * **Bugfix** Characters with ``Default_Ignorable_Code_Point`` property now
  396. return width 0. `PR #174`_.
  397. * **Bugfix** Characters with ``Prepended_Concatenation_Mark`` property now
  398. return width 1. `PR #175`_.
  399. 0.2.14 *2025-09-22*
  400. * **Drop Support** for Python 2.7 and 3.5. `PR #117`_.
  401. * **Update** tables to include Unicode Specifications 16.0.0 and 17.0.0.
  402. `PR #146`_.
  403. * **Bugfix** U+00AD SOFT HYPHEN should measure as 1, versions 0.2.9 through
  404. 0.2.13 measured as 0. `PR #149`_.
  405. 0.2.13 *2024-01-06*
  406. * **Bugfix** zero-width support for Hangul Jamo (Korean)
  407. 0.2.12 *2023-11-21*
  408. * **Bugfix** Re-release to remove `.pyi` files misplaced in wheel `Issue #101`_.
  409. 0.2.11 *2023-11-20*
  410. * **Updated** Include tests files in the source distribution (`PR #98`_, `PR #100`_).
  411. 0.2.10 *2023-11-13*
  412. * **Bugfix** accounting of some kinds of emoji sequences using U+FE0F
  413. Variation Selector 16 (`PR #97`_).
  414. * **Updated** specification_.
  415. 0.2.9 *2023-10-30*
  416. * **Bugfix** zero-width characters used in Emoji ZWJ sequences, Balinese,
  417. Jamo, Devanagari, Tamil, Kannada and others (`PR #91`_).
  418. * **Updated** to include specification_ of character measurements.
  419. 0.2.8 *2023-09-30*
  420. * Include requirements files in the source distribution (`PR #82`_).
  421. 0.2.7 *2023-09-28*
  422. * **Updated** tables to include Unicode Specification 15.1.0.
  423. * Include ``bin``, ``docs``, and ``tox.ini`` in the source distribution
  424. 0.2.6 *2023-01-14*
  425. * **Updated** tables to include Unicode Specification 14.0.0 and 15.0.0.
  426. * **Changed** developer tools to use pip-compile, and to use jinja2 templates
  427. for code generation in `bin/update-tables.py` to prepare for possible
  428. compiler optimization release.
  429. 0.2.1 .. 0.2.5 *2020-06-23*
  430. * **Repository** changes to update tests and packaging issues, and
  431. begin tagging repository with matching release versions.
  432. 0.2.0 *2020-06-01*
  433. * **Enhancement**: Unicode version may be selected by exporting the
  434. Environment variable ``UNICODE_VERSION``, such as ``13.0``, or ``6.3.0``.
  435. See the `jquast/ucs-detect`_ CLI utility for automatic detection.
  436. * **Enhancement**:
  437. API Documentation is published to readthedocs.io.
  438. * **Updated** tables for *all* Unicode Specifications with files
  439. published in a programmatically consumable format, versions 4.1.0
  440. through 13.0
  441. 0.1.9 *2020-03-22*
  442. * **Performance** optimization by `Avram Lubkin`_, `PR #35`_.
  443. * **Updated** tables to Unicode Specification 13.0.0.
  444. 0.1.8 *2020-01-01*
  445. * **Updated** tables to Unicode Specification 12.0.0. (`PR #30`_).
  446. 0.1.7 *2016-07-01*
  447. * **Updated** tables to Unicode Specification 9.0.0. (`PR #18`_).
  448. 0.1.6 *2016-01-08 Production/Stable*
  449. * ``LICENSE`` file now included with distribution.
  450. 0.1.5 *2015-09-13 Alpha*
  451. * **Bugfix**:
  452. Resolution of "combining_ character width" issue, most especially
  453. those that previously returned -1 now often (correctly) return 0.
  454. resolved by `Philip Craig`_ via `PR #11`_.
  455. * **Deprecated**:
  456. The module path ``wcwidth.table_comb`` is no longer available,
  457. it has been superseded by module path ``wcwidth.table_zero``.
  458. 0.1.4 *2014-11-20 Pre-Alpha*
  459. * **Feature**: ``wcswidth()`` now determines printable length
  460. for (most) combining_ characters. The developer's tool
  461. `bin/wcwidth-browser.py`_ is improved to display combining_
  462. characters when provided the ``--combining`` option
  463. (`Thomas Ballinger`_ and `Leta Montopoli`_ `PR #5`_).
  464. * **Feature**: added static analysis (prospector_) to testing
  465. framework.
  466. 0.1.3 *2014-10-29 Pre-Alpha*
  467. * **Bugfix**: 2nd parameter of wcswidth was not honored.
  468. (`Thomas Ballinger`_, `PR #4`_).
  469. 0.1.2 *2014-10-28 Pre-Alpha*
  470. * **Updated** tables to Unicode Specification 7.0.0.
  471. (`Thomas Ballinger`_, `PR #3`_).
  472. 0.1.1 *2014-05-14 Pre-Alpha*
  473. * Initial release to pypi, Based on Unicode Specification 6.3.0
  474. This code was originally derived directly from C code of the same name,
  475. whose latest version is available at
  476. https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::
  477. * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
  478. *
  479. * Permission to use, copy, modify, and distribute this software
  480. * for any purpose and without fee is hereby granted. The author
  481. * disclaims all warranties with regard to this software.
  482. .. _`Spacing Combining Mark`: https://www.unicode.org/versions/latest/ch04.pdf#G134153
  483. .. _`specification`: https://wcwidth.readthedocs.io/en/latest/specs.html
  484. .. _`tox`: https://tox.wiki/en/latest/
  485. .. _`prospector`: https://github.com/landscapeio/prospector
  486. .. _`combining`: https://en.wikipedia.org/wiki/Combining_character
  487. .. _`bin/`: https://github.com/jquast/wcwidth/tree/master/bin
  488. .. _`bin/wcwidth-browser.py`: https://github.com/jquast/wcwidth/blob/master/bin/wcwidth-browser.py
  489. .. _`Thomas Ballinger`: https://github.com/thomasballinger
  490. .. _`Leta Montopoli`: https://github.com/lmontopo
  491. .. _`Philip Craig`: https://github.com/philipc
  492. .. _`PR #3`: https://github.com/jquast/wcwidth/pull/3
  493. .. _`PR #4`: https://github.com/jquast/wcwidth/pull/4
  494. .. _`PR #5`: https://github.com/jquast/wcwidth/pull/5
  495. .. _`PR #11`: https://github.com/jquast/wcwidth/pull/11
  496. .. _`PR #18`: https://github.com/jquast/wcwidth/pull/18
  497. .. _`PR #30`: https://github.com/jquast/wcwidth/pull/30
  498. .. _`PR #35`: https://github.com/jquast/wcwidth/pull/35
  499. .. _`PR #82`: https://github.com/jquast/wcwidth/pull/82
  500. .. _`PR #91`: https://github.com/jquast/wcwidth/pull/91
  501. .. _`PR #97`: https://github.com/jquast/wcwidth/pull/97
  502. .. _`PR #98`: https://github.com/jquast/wcwidth/pull/98
  503. .. _`PR #100`: https://github.com/jquast/wcwidth/pull/100
  504. .. _`PR #117`: https://github.com/jquast/wcwidth/pull/117
  505. .. _`PR #146`: https://github.com/jquast/wcwidth/pull/146
  506. .. _`PR #149`: https://github.com/jquast/wcwidth/pull/149
  507. .. _`PR #156`: https://github.com/jquast/wcwidth/pull/156
  508. .. _`PR #165`: https://github.com/jquast/wcwidth/pull/165
  509. .. _`PR #166`: https://github.com/jquast/wcwidth/pull/166
  510. .. _`PR #168`: https://github.com/jquast/wcwidth/pull/168
  511. .. _`PR #169`: https://github.com/jquast/wcwidth/pull/169
  512. .. _`PR #171`: https://github.com/jquast/wcwidth/pull/171
  513. .. _`PR #172`: https://github.com/jquast/wcwidth/pull/172
  514. .. _`PR #173`: https://github.com/jquast/wcwidth/pull/173
  515. .. _`PR #174`: https://github.com/jquast/wcwidth/pull/174
  516. .. _`PR #175`: https://github.com/jquast/wcwidth/pull/175
  517. .. _`PR #181`: https://github.com/jquast/wcwidth/pull/181
  518. .. _`PR #183`: https://github.com/jquast/wcwidth/pull/183
  519. .. _`PR #184`: https://github.com/jquast/wcwidth/pull/184
  520. .. _`PR #185`: https://github.com/jquast/wcwidth/pull/185
  521. .. _`PR #188`: https://github.com/jquast/wcwidth/pull/188
  522. .. _`PR #191`: https://github.com/jquast/wcwidth/pull/191
  523. .. _`PR #192`: https://github.com/jquast/wcwidth/pull/192
  524. .. _`PR #193`: https://github.com/jquast/wcwidth/pull/193
  525. .. _`PR #194`: https://github.com/jquast/wcwidth/pull/194
  526. .. _`PR #195`: https://github.com/jquast/wcwidth/pull/195
  527. .. _`PR #196`: https://github.com/jquast/wcwidth/pull/196
  528. .. _`PR #199`: https://github.com/jquast/wcwidth/pull/199
  529. .. _`PR #200`: https://github.com/jquast/wcwidth/pull/200
  530. .. _`PR #202`: https://github.com/jquast/wcwidth/pull/202
  531. .. _`PR #204`: https://github.com/jquast/wcwidth/pull/204
  532. .. _`Issue #101`: https://github.com/jquast/wcwidth/issues/101
  533. .. _`Issue #155`: https://github.com/jquast/wcwidth/issues/155
  534. .. _`Issue #190`: https://github.com/jquast/wcwidth/issues/190
  535. .. _`jquast/blessed`: https://github.com/jquast/blessed
  536. .. _`selectel/pyte`: https://github.com/selectel/pyte
  537. .. _`thomasballinger/curtsies`: https://github.com/thomasballinger/curtsies
  538. .. _`dbcli/pgcli`: https://github.com/dbcli/pgcli
  539. .. _`prompt-toolkit/python-prompt-toolkit`: https://github.com/prompt-toolkit/python-prompt-toolkit
  540. .. _`timoxley/wcwidth`: https://github.com/timoxley/wcwidth
  541. .. _`wcwidth(3)`: https://man7.org/linux/man-pages/man3/wcwidth.3.html
  542. .. _`wcswidth(3)`: https://man7.org/linux/man-pages/man3/wcswidth.3.html
  543. .. _`astanin/python-tabulate`: https://github.com/astanin/python-tabulate
  544. .. _`janlelis/unicode-display_width`: https://github.com/janlelis/unicode-display_width
  545. .. _`rspeer/python-ftfy`: https://github.com/rspeer/python-ftfy
  546. .. _`alecrabbit/php-wcwidth`: https://github.com/alecrabbit/php-wcwidth
  547. .. _`Text::CharWidth`: https://metacpan.org/pod/Text::CharWidth
  548. .. _`bluebear94/Terminal-WCWidth`: https://github.com/bluebear94/Terminal-WCWidth
  549. .. _`mattn/go-runewidth`: https://github.com/mattn/go-runewidth
  550. .. _`grepsuzette/wcwidth`: https://github.com/grepsuzette/wcwidth
  551. .. _`jquast/ucs-detect`: https://github.com/jquast/ucs-detect
  552. .. _`Avram Lubkin`: https://github.com/avylove
  553. .. _`nbedos/termtosvg`: https://github.com/nbedos/termtosvg
  554. .. _`peterbrittain/asciimatics`: https://github.com/peterbrittain/asciimatics
  555. .. _`aperezdc/lua-wcwidth`: https://github.com/aperezdc/lua-wcwidth
  556. .. _`joachimschmidt557/zig-wcwidth`: https://github.com/joachimschmidt557/zig-wcwidth
  557. .. _`fumiyas/wcwidth-cjk`: https://github.com/fumiyas/wcwidth-cjk
  558. .. _`joshuarubin/wcwidth9`: https://github.com/joshuarubin/wcwidth9
  559. .. _`spectreconsole/wcwidth`: https://github.com/spectreconsole/wcwidth
  560. .. _`python-cmd2/cmd2`: https://github.com/python-cmd2/cmd2
  561. .. _`stratis-storage/stratis-cli`: https://github.com/stratis-storage/stratis-cli
  562. .. _`ihabunek/toot`: https://github.com/ihabunek/toot
  563. .. _`saulpw/visidata`: https://github.com/saulpw/visidata
  564. .. _`pip-tools`: https://pip-tools.readthedocs.io/
  565. .. _`sphinx`: https://www.sphinx-doc.org/
  566. .. _`textwrap.wrap()`: https://docs.python.org/3/library/textwrap.html#textwrap.wrap
  567. .. _`str.ljust()`: https://docs.python.org/3/library/stdtypes.html#str.ljust
  568. .. _`str.rjust()`: https://docs.python.org/3/library/stdtypes.html#str.rjust
  569. .. _`str.center()`: https://docs.python.org/3/library/stdtypes.html#str.center
  570. .. _`str.expandtabs()`: https://docs.python.org/3/library/stdtypes.html#str.expandtabs
  571. .. _`General Tabulated Summary`: https://ucs-detect.readthedocs.io/results.html#tabulated-results
  572. .. _`wcwidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcwidth
  573. .. _`wcswidth()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wcswidth
  574. .. _`width()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.width
  575. .. _`iter_graphemes()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes
  576. .. _`iter_graphemes_reverse()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_graphemes_reverse
  577. .. _`grapheme_boundary_before()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.grapheme_boundary_before
  578. .. _`ljust()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.ljust
  579. .. _`rjust()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.rjust
  580. .. _`center()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.center
  581. .. _`wrap()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.wrap
  582. .. _`clip()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.clip
  583. .. _`strip_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.strip_sequences
  584. .. _`propagate_sgr()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.propagate_sgr
  585. .. _`iter_sequences()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.iter_sequences
  586. .. _`list_versions()`: https://wcwidth.readthedocs.io/en/latest/api.html#wcwidth.list_versions
  587. .. _`Unicode Standard Annex #29`: https://www.unicode.org/reports/tr29/
  588. .. _`Terminal.detect_ambiguous_width()`: https://blessed.readthedocs.io/en/latest/api/terminal.html#blessed.terminal.Terminal.detect_ambiguous_width
  589. .. _`parity padding`: https://jazcap53.github.io/pythons-eccentric-strcenter.html
  590. .. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi
  591. :alt: Downloads
  592. :target: https://pypi.org/project/wcwidth/
  593. .. |codecov| image:: https://codecov.io/gh/jquast/wcwidth/branch/master/graph/badge.svg
  594. :alt: codecov.io Code Coverage
  595. :target: https://app.codecov.io/gh/jquast/wcwidth/
  596. .. |license| image:: https://img.shields.io/pypi/l/wcwidth.svg
  597. :target: https://pypi.org/project/wcwidth/
  598. :alt: MIT License