├── .gitignore ├── .busted ├── wcwidth.lua ├── luarocks ├── wcwidth-0.1-1.rockspec ├── wcwidth-scm-1.rockspec ├── wcwidth-scm-2.rockspec ├── wcwidth-0.1-2.rockspec ├── wcwidth-0.2-1.rockspec ├── wcwidth-0.3-1.rockspec ├── wcwidth-0.4-1.rockspec └── wcwidth-0.5-1.rockspec ├── spec ├── unicodetables_spec.lua └── wcwidth_spec.lua ├── .travis.yml ├── CHANGELOG.md ├── wcwidth ├── init.lua ├── widetab.lua └── zerotab.lua ├── update-tables ├── README.md.in └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /DerivedGeneralCategory.txt 2 | /EastAsianWidth.txt 3 | -------------------------------------------------------------------------------- /.busted: -------------------------------------------------------------------------------- 1 | -- vim:set ft=lua: 2 | return { 3 | _all = { 4 | verbose = true, 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /wcwidth.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- wcwidth.lua 3 | -- Copyright (C) 2016 Adrian Perez 4 | -- 5 | -- Distributed under terms of the MIT license. 6 | -- 7 | 8 | return require "wcwidth.init" 9 | -------------------------------------------------------------------------------- /luarocks/wcwidth-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "0.1-1" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth", 5 | tag = "v0.1" 6 | } 7 | description = { 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11" 11 | } 12 | dependencies = { 13 | "lua >= 5.1" 14 | } 15 | build = { 16 | type = "builtin", 17 | modules = { 18 | wcwidth = "wcwidth.lua", 19 | ["wcwidth.init"] = "wcwidth/init.lua", 20 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 21 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /luarocks/wcwidth-scm-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "scm-1" 3 | description = { 4 | summary = "Pure Lua implementation of the wcwidth() function", 5 | homepage = "https://github.com/aperezdc/lua-wcwidth", 6 | license = "MIT/X11", 7 | } 8 | source = { 9 | url = "git://github.com/aperezdc/lua-wcwidth", 10 | } 11 | dependencies = { 12 | "lua >= 5.1", 13 | } 14 | build = { 15 | type = "builtin", 16 | modules = { 17 | ["wcwidth"] = "wcwidth.lua", 18 | ["wcwidth.init"] = "wcwidth/init.lua", 19 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua", 20 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /luarocks/wcwidth-scm-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "scm-2" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth" 5 | } 6 | description = { 7 | maintainer = "Adrián Pérez de Castro ", 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11" 11 | } 12 | dependencies = { 13 | "lua >= 5.1" 14 | } 15 | build = { 16 | type = "builtin", 17 | modules = { 18 | wcwidth = "wcwidth.lua", 19 | ["wcwidth.init"] = "wcwidth/init.lua", 20 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 21 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /luarocks/wcwidth-0.1-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "0.1-2" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth", 5 | tag = "v0.1" 6 | } 7 | description = { 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11", 11 | maintainer = "Adrián Pérez de Castro " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | wcwidth = "wcwidth.lua", 20 | ["wcwidth.init"] = "wcwidth/init.lua", 21 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 22 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /luarocks/wcwidth-0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "0.2-1" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth", 5 | tag = "v0.2" 6 | } 7 | description = { 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11", 11 | maintainer = "Adrián Pérez de Castro " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | wcwidth = "wcwidth.lua", 20 | ["wcwidth.init"] = "wcwidth/init.lua", 21 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 22 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /luarocks/wcwidth-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "0.3-1" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth", 5 | tag = "v0.3" 6 | } 7 | description = { 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11", 11 | maintainer = "Adrián Pérez de Castro " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | wcwidth = "wcwidth.lua", 20 | ["wcwidth.init"] = "wcwidth/init.lua", 21 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 22 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /luarocks/wcwidth-0.4-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "0.4-1" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth", 5 | tag = "v0.4" 6 | } 7 | description = { 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11", 11 | maintainer = "Adrián Pérez de Castro " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | wcwidth = "wcwidth.lua", 20 | ["wcwidth.init"] = "wcwidth/init.lua", 21 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 22 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /luarocks/wcwidth-0.5-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "wcwidth" 2 | version = "0.5-1" 3 | source = { 4 | url = "git://github.com/aperezdc/lua-wcwidth", 5 | tag = "v0.5" 6 | } 7 | description = { 8 | summary = "Pure Lua implementation of the wcwidth() function", 9 | homepage = "https://github.com/aperezdc/lua-wcwidth", 10 | license = "MIT/X11", 11 | maintainer = "Adrián Pérez de Castro " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | wcwidth = "wcwidth.lua", 20 | ["wcwidth.init"] = "wcwidth/init.lua", 21 | ["wcwidth.widetab"] = "wcwidth/widetab.lua", 22 | ["wcwidth.zerotab"] = "wcwidth/zerotab.lua" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spec/unicodetables_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- unicodetables_spec.lua 3 | -- Copyright (C) 2016 Adrian Perez 4 | -- 5 | -- Distributed under terms of the MIT license. 6 | -- 7 | 8 | local function check_table(t, step) 9 | for i = 1, #t - step, step do 10 | assert(t[i] <= t[i + step]) 11 | end 12 | end 13 | 14 | describe("wcwidth.zerotab", function () 15 | local zerotab = require "wcwidth.zerotab" 16 | it("is sorted", function () 17 | check_table(zerotab, 1) 18 | check_table(zerotab, 2) 19 | end) 20 | end) 21 | 22 | describe("wcwidth.widetab", function () 23 | local widetab = require "wcwidth.widetab" 24 | it("is sorted", function () 25 | check_table(widetab, 1) 26 | check_table(widetab, 2) 27 | end) 28 | end) 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: bionic 3 | language: python 4 | 5 | env: 6 | global: 7 | - LUACOV=cluacov 8 | jobs: 9 | - LUA="lua 5.1" 10 | - LUA="lua 5.2" 11 | - LUA="lua 5.3" 12 | - LUA="lua 5.4" LUACOV=luacov 13 | - LUA="luajit 2.0" 14 | - LUA="luajit 2.1" 15 | 16 | before_install: 17 | - pip install hererocks 18 | - hererocks here -rlatest --$LUA 19 | - export PATH=$PATH:$PWD/here/bin 20 | - eval `luarocks path --bin` 21 | - lua -v 22 | 23 | install: 24 | - echo 'Installing runtime dependencies...' 25 | - luarocks install --only-deps $(find luarocks -name '*-scm-*.rockspec' | sort -g | tail -1) 26 | - echo 'Installing additional testing dependencies...' 27 | - luarocks install dromozoa-utf8 28 | - luarocks install $LUACOV 29 | - luarocks install busted 30 | - luarocks install luacov-coveralls 31 | 32 | script: 33 | - timeout 120 busted -c 34 | 35 | after_success: 36 | - luacov-coveralls -i wcwidth/ -e spec/ -e here/ 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unreleased] 6 | 7 | ## [0.5] - 2020-03-29 8 | ### Changed 9 | - Updates to version 13 of the Unicode tables. 10 | 11 | ## [0.4] - 2020-01-14 12 | ### Changed 13 | - Updated to version 12 of the Unicode tables. 14 | 15 | ## [0.3] - 2019-02-15 16 | ### Changed 17 | - Updated to version 11 of the Unicode tables. 18 | 19 | ## [0.2] - 2016-07-13 20 | ### Added 21 | - Enable using the "bit" module where available. This in particular gives 22 | a speed improvement under LuaJIT. 23 | 24 | ## 0.1 25 | ### Added 26 | - Initial version. 27 | 28 | [Unreleased]: https://github.com/aperezdc/lua-wcwidth/compare/v0.5...HEAD 29 | [0.5]: https://github.com/aperezdc/lua-wcwidth/compare/v0.4...v0.5 30 | [0.4]: https://github.com/aperezdc/lua-wcwidth/compare/v0.3...v0.4 31 | [0.3]: https://github.com/aperezdc/lua-wcwidth/compare/v0.2...v0.3 32 | [0.2]: https://github.com/aperezdc/lua-wcwidth/compare/v0.1...v0.2 33 | -------------------------------------------------------------------------------- /wcwidth/init.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- wcwidth.lua 3 | -- Copyright (C) 2016 Adrian Perez 4 | -- 5 | -- Distributed under terms of the MIT license. 6 | -- 7 | 8 | -- 9 | -- Divides a number by two, and rounds it up to the next odd number. 10 | -- 11 | local halfodd = (function () 12 | -- Lua 5.3 has bit shift operators and integer division. 13 | local ok, f = pcall(function () 14 | return load("return function (x) return (x >> 1) | 1 end")() 15 | end) 16 | if ok then return f end 17 | -- Try using a bitwise manipulation module. 18 | for _, name in ipairs { "bit", "bit32" } do 19 | local ok, m = pcall(require, name) 20 | if ok then 21 | local rshift, bor = m.rshift, m.bor 22 | return function (x) return bor(rshift(x, 1), 1) end 23 | end 24 | end 25 | -- Fall-back using the math library. 26 | -- Lua 5.1 has math.mod() instead of the "%" operator. 27 | local floor = math.floor 28 | if (pcall(function () return load("return 10 % 3")() == 4 end)) then 29 | return function (x) 30 | local r = floor(x / 2) 31 | return (r % 2 == 0) and r + 1 or r 32 | end 33 | end 34 | local mod = math.mod or function (x, d) 35 | while x > d do x = x - d end 36 | return x 37 | end 38 | return function (x) 39 | local r = floor(x / 2) 40 | return mod(r, 2) == 0 and r + 1 or r 41 | end 42 | end)() 43 | 44 | local function _lookup(rune, table) 45 | local l, r = 1, #table 46 | while l <= r do 47 | local m = halfodd(l + r) 48 | -- Invariants: 49 | -- assert(l % 2 == 1, "lower bound index is not odd") 50 | -- assert(r % 2 == 0, "upper bound index is not even") 51 | -- assert(m % 2 == 1, "middle point index is not odd") 52 | if rune < table[m] then 53 | r = m - 1 54 | elseif rune > table[m + 1] then 55 | l = m + 2 56 | else 57 | return 1 58 | end 59 | end 60 | return 0 61 | end 62 | 63 | local _tab_zero = require "wcwidth.zerotab" 64 | local _tab_wide = require "wcwidth.widetab" 65 | 66 | local function wcwidth (rune) 67 | if rune == 0 or 68 | rune == 0x034F or 69 | rune == 0x2028 or 70 | rune == 0x2029 or 71 | (0x200B <= rune and rune <= 0x200F) or 72 | (0x202A <= rune and rune <= 0x202E) or 73 | (0x2060 <= rune and rune <= 0x2063) 74 | then 75 | return 0 76 | end 77 | 78 | -- C0/C1 control characters 79 | if rune < 32 or (0x07F <= rune and rune < 0x0A0) then 80 | return -1 81 | end 82 | 83 | -- Combining characters with zero width 84 | if _lookup(rune, _tab_zero) == 1 then 85 | return 0 86 | end 87 | 88 | return 1 + _lookup(rune, _tab_wide) 89 | end 90 | 91 | return wcwidth 92 | -------------------------------------------------------------------------------- /spec/wcwidth_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- wcwidth_spec.lua 3 | -- Copyright (C) 2016 Adrian Perez 4 | -- 5 | -- Distributed under terms of the MIT license. 6 | -- 7 | 8 | local wcwidth = require "wcwidth" 9 | local utf8 = require "dromozoa.utf8" 10 | 11 | local function test_phrase(input, expected_lengths, expected_total_length) 12 | local i = 1 13 | local total_length = 0 14 | for _, rune in utf8.codes(input) do 15 | local w = wcwidth(rune) 16 | assert.equal(expected_lengths[i], w) 17 | if w < 0 then 18 | total_length = -1 19 | elseif total_length >= 0 then 20 | total_length = total_length + w 21 | end 22 | i = i + 1 23 | end 24 | assert.equal(expected_total_length, total_length) 25 | end 26 | 27 | -- 28 | -- Many test cases are from: 29 | -- https://github.com/jquast/wcwidth/blob/master/wcwidth/tests/test_core.py 30 | -- 31 | describe("wcwidth()", function () 32 | it("handles a mix of Japanese and ASCII", function () 33 | -- Given a phrase of 5 and 3 Katakana ideographs, joined with 3 English 34 | -- ASCII punctuation characters, totaling 11, this phrase consumes 19 35 | -- cells of a terminal emulator. 36 | test_phrase("コンニチハ, セカイ!", 37 | { 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1 }, 19) 38 | end) 39 | it("reports 0 width for NULL", function () 40 | assert.equal(0, wcwidth(0x00)) 41 | test_phrase("abc\0def", { 1, 1, 1, 0, 1, 1, 1 }, 6) 42 | end) 43 | it("reports width -1 for CSI", function () 44 | assert.equal(-1, wcwidth(0x1B)) 45 | -- XXX: Using "\x1B[0m" does *not* work in Lua 5.1 because of the \xNN 46 | -- syntax, so use string.char() instead to build the input string. 47 | test_phrase(string.char(0x1B) .. "[0m", { -1, 1, 1, 1 }, -1) 48 | end) 49 | it("handles combining characters", function () 50 | -- Simple test combining reports total width of 4. 51 | test_phrase("--" .. utf8.char(0x05BF) .. "--", { 1, 1, 0, 1, 1 }, 4) 52 | end) 53 | it("handles a combining accent in 'café'", function () 54 | -- Phrase cafe + COMBINING ACUTE ACCENT is café of length 4. 55 | test_phrase("cafe" .. utf8.char(0x0301), { 1, 1, 1, 1, 0 }, 4) 56 | end) 57 | it("handles a combining enclosing", function () 58 | -- CYRILLIC CAPITAL LETTER A + COMBINING CYRILLIC HUNDRED THOUSANDS SIGN is А҈ of length 1. 59 | test_phrase(utf8.char(0x0410, 0x0488), { 1, 0 }, 1) 60 | end) 61 | it("handles combining spaces", function () 62 | -- Balinese kapal (ship) is ᬓᬨᬮ᭄ of length 4. 63 | test_phrase(utf8.char(0x1B13, 0x1B28, 0x1B2E, 0x1B44), { 1, 1, 1, 1 }, 4) 64 | end) 65 | it("handles a 👍 emoji", function () 66 | test_phrase("two 👍", { 1, 1, 1, 1, 2 }, 6) 67 | end) 68 | end) 69 | 70 | -------------------------------------------------------------------------------- /update-tables: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # update-tables 4 | # Copyright (C) 2016 Adrian Perez 5 | # 6 | # Distributed under terms of the MIT license. 7 | # 8 | set -e 9 | 10 | WIDE_URL='http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt' 11 | ZERO_URL='http://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt' 12 | 13 | # The version numbers of the files above are parsed from the files themselves. 14 | WIDE_VER='(unknown)' 15 | ZERO_VER='(unknown)' 16 | 17 | srcdir=$(dirname "$0") 18 | 19 | WIDE_FILE="${srcdir}/${WIDE_URL##*/}" 20 | ZERO_FILE="${srcdir}/${ZERO_URL##*/}" 21 | 22 | [[ -r ${WIDE_FILE} ]] || wget -c -O "${WIDE_FILE}" "${WIDE_URL}" 23 | [[ -r ${ZERO_FILE} ]] || wget -c -O "${ZERO_FILE}" "${ZERO_URL}" 24 | 25 | # Pad hex values to be 8 characters wide, and prepend "0x" to them. 26 | u32hex () { 27 | local -i len=${#1} 28 | local -i nzeros=$(( 8 - len )) 29 | echo -n '0x' 30 | for (( ; nzeros > 0 ; nzeros-- )) ; do 31 | echo -n '0' 32 | done 33 | echo -n "$1" 34 | } 35 | 36 | format_range () { 37 | if [[ $1 = *..* ]] ; then 38 | u32hex "${1%..*}" 39 | echo -n ',' 40 | u32hex "${1#*..}" 41 | echo ',' 42 | else 43 | u32hex "${1}" 44 | echo -n ',' 45 | u32hex "${1}" 46 | echo ',' 47 | fi 48 | } 49 | 50 | zero_table () { 51 | local tmpfile="${TMPDIR:-/tmp}/update-tables-$$-${RANDOM}" 52 | echo "-- Autogenerated from ${ZERO_FILE##*/}" 53 | echo 'return {' 54 | while read -r line ; do 55 | if [[ -z ${line} || ${line} = \#* ]] ; then 56 | read line rest <<< "${line}" 57 | if [[ ${rest} = *.txt ]] ; then 58 | ZERO_VER=${rest} 59 | elif [[ ${rest} = Date:\ 20* || ${rest} = ©\ 20* ]] ; then 60 | ZERO_VER="${ZERO_VER}, ${rest}" 61 | fi 62 | continue 63 | fi 64 | read -a items <<< "${line}" 65 | if [[ ${items[2]} == Mn || ${items[2]} == Me ]] ; then 66 | format_range "${items[0]}" 67 | fi 68 | done > "${tmpfile}" 69 | sort "${tmpfile}" 70 | rm "${tmpfile}" 71 | echo '}' 72 | } 73 | 74 | wide_table () { 75 | local tmpfile="${TMPDIR:-/tmp}/update-tables-$$-${RANDOM}" 76 | echo "-- Autogenerated from ${WIDE_FILE##*/}" 77 | echo 'return {' 78 | while read -r item rest ; do 79 | if [[ -z ${item} || ${item} = \#* ]] ; then 80 | if [[ ${rest} = *.txt ]] ; then 81 | WIDE_VER=${rest} 82 | elif [[ ${rest} = Date:\ 20* || ${rest} = ©\ 20* ]] ; then 83 | WIDE_VER="${WIDE_VER}, ${rest}" 84 | fi 85 | continue 86 | fi 87 | range=${item%;*} 88 | flags=${item#*;} 89 | if [[ ${flags} = W* || ${flags} = F* ]] ; then 90 | format_range "${range}" 91 | fi 92 | done > "${tmpfile}" 93 | sort "${tmpfile}" 94 | rm "${tmpfile}" 95 | echo '}' 96 | } 97 | 98 | make_readme () { 99 | # Pick newest LuaRocks version 100 | local V=$(find "${srcdir}/luarocks" -name 'wcwidth-[0-9]*.rockspec' \ 101 | | sed 's,^.*/wcwidth-\([0-9\.]\+\).*$,\1,' | sort -g | tail -1) 102 | sed -e "s+@@WIDE_FILE@@+${WIDE_FILE##*/}+g" \ 103 | -e "s+@@ZERO_FILE@@+${ZERO_FILE##*/}+g" \ 104 | -e "s+@@WIDE_URL@@+${WIDE_URL}+g" \ 105 | -e "s+@@ZERO_URL@@+${ZERO_URL}+g" \ 106 | -e "s+@@WIDE_VER@@+${WIDE_VER}+g" \ 107 | -e "s+@@ZERO_VER@@+${ZERO_VER}+g" \ 108 | -e "s+@@LUAROCKS_VER@@+${V}+g" 109 | } 110 | 111 | wide_table < "${WIDE_FILE}" > "${srcdir}/wcwidth/widetab.lua" 112 | zero_table < "${ZERO_FILE}" > "${srcdir}/wcwidth/zerotab.lua" 113 | make_readme < "${srcdir}/README.md.in" > "${srcdir}/README.md" 114 | -------------------------------------------------------------------------------- /README.md.in: -------------------------------------------------------------------------------- 1 | lua-wcwidth 2 | =========== 3 | 4 | [![Build Status](https://travis-ci.org/aperezdc/lua-wcwidth.svg?branch=master)](https://travis-ci.org/aperezdc/lua-wcwidth) 5 | [![Coverage Status](https://coveralls.io/repos/github/aperezdc/lua-wcwidth/badge.svg?branch=master)](https://coveralls.io/github/aperezdc/lua-wcwidth?branch=master) 6 | [![LuaRocks](https://img.shields.io/badge/luarocks-v@@LUAROCKS_VER@@-blue.png)](https://luarocks.org/modules/aperezdc/wcwidth) 7 | 8 | When writing output to a fixed-width output system (such as a terminal), the 9 | displayed length of a string does not always match the number of characters 10 | (also known as [runes](https://swtch.com/plan9port/unix/man/rune3.html), or 11 | code points) contained by the string. Some characters occupy two spaces 12 | (full-wide characters), and others occupy none. 13 | 14 | POSIX.1-2001 and POSIX.1-2008 specify the 15 | [wcwidth(3)](http://man7.org/linux/man-pages/man3/wcwidth.3.html) function 16 | which can be used to know how many spaces (or *cells*) must be used to display 17 | a Unicode code point. This [Lua](http://lua.org) contains a portable and 18 | standalone implementation based on the Unicode Standard release files. 19 | 20 | This module is useful mainly for implementing programs which must produce 21 | output to terminals, while handling proper alignment for double-width and 22 | zero-width Unicode code points. 23 | 24 | Usage 25 | ----- 26 | 27 | The following snippet defines a function which can determine the display width 28 | for a string: 29 | 30 | ```lua 31 | local wcwidth, utf8 = require "wcwidth", require "utf8" 32 | 33 | local function display_width(s) 34 | local len = 0 35 | for _, rune in utf8.codes(s) do 36 | local l = wcwidth(rune) 37 | if l >= 0 then 38 | len = len + l 39 | end 40 | end 41 | return len 42 | end 43 | ``` 44 | 45 | The function above can be used to print any UTF-8 string properly 46 | right-aligned to a terminal: 47 | 48 | ```lua 49 | local function alignright(s, cols) 50 | local numspaces = cols - display_width(s) 51 | local spaces = "" 52 | while numspaces > 0 do 53 | numspaces = numspaces - 1 54 | spaces = spaces .. " " 55 | end 56 | return spaces .. s 57 | end 58 | 59 | print(alignright("コンニチハ", 80)) 60 | ``` 61 | 62 | The `wcwidth()` function takes a Unicode code point as argument, and returns 63 | one of the following values: 64 | 65 | * `-1`: Width cannot be determined (the code point is not printable). 66 | * `0`: The code point does not advance the cursor (e.g. `NULL`, or a combining 67 | character). 68 | * `2`: The character is East Asian wide (`W`) or East Asian full-width (`F`), 69 | and is displayed using two spaces. 70 | * `1`: All the rest of characters, which take a single space. 71 | 72 | Note that the 73 | [wcswidth(3)](http://man7.org/linux/man-pages/man3/wcswidth.3.html) companion 74 | function is *deliberately not provided by this module*: while Lua 5.3 provides 75 | [utf8.codes()](http://www.lua.org/manual/5.3/manual.html#pdf-utf8.codes) and 76 | [utf8.codepoint()](http://www.lua.org/manual/5.3/manual.html#pdf-utf8.codepoint) 77 | to convert UTF8 byte sequences to code points, for other Lua versions it would 78 | be needed to depend on a third party module, and that would be against the 79 | goal of `wcwidth` being standalone. If needed be, `wcswidth()` can be 80 | implemented as follows using the Lua 5.3 `utf8` module (or any other 81 | implementation which provides a compatible implementation): 82 | 83 | ```lua 84 | -- Calculates the printable length of first "n" characters of string "s" 85 | -- on a terminal. Returns the number of cells or -1 if the string contains 86 | -- non-printable characters. Raises an error on invalid UTF8 input. 87 | function wcswidth(s, n) 88 | local cells = 0 89 | if n then 90 | local count = 0 91 | for _, rune in utf8.codes(s) do 92 | local w = wcwidth(rune) 93 | if w < 0 then return -1 end 94 | count = count + 1 95 | if count >= n then break end 96 | end 97 | else 98 | for _, rune in utf8.codes(s) do 99 | local w = wcwidth(rune) 100 | if w < 0 then return -1 end 101 | cells = cells + w 102 | end 103 | end 104 | return cells 105 | end 106 | ``` 107 | 108 | 109 | Installation 110 | ------------ 111 | 112 | [LuaRocks](https://luarocks.org) is recommended for installation. 113 | 114 | The stable version (recommended) can be installed with: 115 | 116 | ```sh 117 | luarocks install wcwidth 118 | ``` 119 | 120 | The development version can be installed with: 121 | 122 | ```sh 123 | luarocks install --server=https://luarocks.org/dev wcwidth 124 | ``` 125 | 126 | Unicode Tables 127 | -------------- 128 | 129 | The `update-tables` script downloads the following resources from the [Unicode 130 | Consortium website](http://unicode.org): 131 | 132 | * @@WIDE_URL@@ 133 | * @@ZERO_URL@@ 134 | 135 | With them, it generates the following files: 136 | 137 | * [wcwidth/widetab.lua](./wcwidth/widetab.lua) 138 | * [wcwidth/zerotab.lua](./wcwidth/zerotab.lua) 139 | 140 | The most current version of `wcwidth` uses the following versions of the above 141 | Unicode Standard release files: 142 | 143 | * `@@WIDE_VER@@` 144 | * `@@ZERO_VER@@` 145 | 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-wcwidth 2 | =========== 3 | 4 | [![Build Status](https://travis-ci.org/aperezdc/lua-wcwidth.svg?branch=master)](https://travis-ci.org/aperezdc/lua-wcwidth) 5 | [![Coverage Status](https://coveralls.io/repos/github/aperezdc/lua-wcwidth/badge.svg?branch=master)](https://coveralls.io/github/aperezdc/lua-wcwidth?branch=master) 6 | [![LuaRocks](https://img.shields.io/badge/luarocks-v0.5-blue.png)](https://luarocks.org/modules/aperezdc/wcwidth) 7 | 8 | When writing output to a fixed-width output system (such as a terminal), the 9 | displayed length of a string does not always match the number of characters 10 | (also known as [runes](https://swtch.com/plan9port/unix/man/rune3.html), or 11 | code points) contained by the string. Some characters occupy two spaces 12 | (full-wide characters), and others occupy none. 13 | 14 | POSIX.1-2001 and POSIX.1-2008 specify the 15 | [wcwidth(3)](http://man7.org/linux/man-pages/man3/wcwidth.3.html) function 16 | which can be used to know how many spaces (or *cells*) must be used to display 17 | a Unicode code point. This [Lua](http://lua.org) contains a portable and 18 | standalone implementation based on the Unicode Standard release files. 19 | 20 | This module is useful mainly for implementing programs which must produce 21 | output to terminals, while handling proper alignment for double-width and 22 | zero-width Unicode code points. 23 | 24 | Usage 25 | ----- 26 | 27 | The following snippet defines a function which can determine the display width 28 | for a string: 29 | 30 | ```lua 31 | local wcwidth, utf8 = require "wcwidth", require "utf8" 32 | 33 | local function display_width(s) 34 | local len = 0 35 | for _, rune in utf8.codes(s) do 36 | local l = wcwidth(rune) 37 | if l >= 0 then 38 | len = len + l 39 | end 40 | end 41 | return len 42 | end 43 | ``` 44 | 45 | The function above can be used to print any UTF-8 string properly 46 | right-aligned to a terminal: 47 | 48 | ```lua 49 | local function alignright(s, cols) 50 | local numspaces = cols - display_width(s) 51 | local spaces = "" 52 | while numspaces > 0 do 53 | numspaces = numspaces - 1 54 | spaces = spaces .. " " 55 | end 56 | return spaces .. s 57 | end 58 | 59 | print(alignright("コンニチハ", 80)) 60 | ``` 61 | 62 | The `wcwidth()` function takes a Unicode code point as argument, and returns 63 | one of the following values: 64 | 65 | * `-1`: Width cannot be determined (the code point is not printable). 66 | * `0`: The code point does not advance the cursor (e.g. `NULL`, or a combining 67 | character). 68 | * `2`: The character is East Asian wide (`W`) or East Asian full-width (`F`), 69 | and is displayed using two spaces. 70 | * `1`: All the rest of characters, which take a single space. 71 | 72 | Note that the 73 | [wcswidth(3)](http://man7.org/linux/man-pages/man3/wcswidth.3.html) companion 74 | function is *deliberately not provided by this module*: while Lua 5.3 provides 75 | [utf8.codes()](http://www.lua.org/manual/5.3/manual.html#pdf-utf8.codes) and 76 | [utf8.codepoint()](http://www.lua.org/manual/5.3/manual.html#pdf-utf8.codepoint) 77 | to convert UTF8 byte sequences to code points, for other Lua versions it would 78 | be needed to depend on a third party module, and that would be against the 79 | goal of `wcwidth` being standalone. If needed be, `wcswidth()` can be 80 | implemented as follows using the Lua 5.3 `utf8` module (or any other 81 | implementation which provides a compatible implementation): 82 | 83 | ```lua 84 | -- Calculates the printable length of first "n" characters of string "s" 85 | -- on a terminal. Returns the number of cells or -1 if the string contains 86 | -- non-printable characters. Raises an error on invalid UTF8 input. 87 | function wcswidth(s, n) 88 | local cells = 0 89 | if n then 90 | local count = 0 91 | for _, rune in utf8.codes(s) do 92 | local w = wcwidth(rune) 93 | if w < 0 then return -1 end 94 | count = count + 1 95 | if count >= n then break end 96 | end 97 | else 98 | for _, rune in utf8.codes(s) do 99 | local w = wcwidth(rune) 100 | if w < 0 then return -1 end 101 | cells = cells + w 102 | end 103 | end 104 | return cells 105 | end 106 | ``` 107 | 108 | 109 | Installation 110 | ------------ 111 | 112 | [LuaRocks](https://luarocks.org) is recommended for installation. 113 | 114 | The stable version (recommended) can be installed with: 115 | 116 | ```sh 117 | luarocks install wcwidth 118 | ``` 119 | 120 | The development version can be installed with: 121 | 122 | ```sh 123 | luarocks install --server=https://luarocks.org/dev wcwidth 124 | ``` 125 | 126 | Unicode Tables 127 | -------------- 128 | 129 | The `update-tables` script downloads the following resources from the [Unicode 130 | Consortium website](http://unicode.org): 131 | 132 | * http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt 133 | * http://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt 134 | 135 | With them, it generates the following files: 136 | 137 | * [wcwidth/widetab.lua](./wcwidth/widetab.lua) 138 | * [wcwidth/zerotab.lua](./wcwidth/zerotab.lua) 139 | 140 | The most current version of `wcwidth` uses the following versions of the above 141 | Unicode Standard release files: 142 | 143 | * `EastAsianWidth-13.0.0.txt, Date: 2029-01-21, 18:14:00 GMT [KW, LI], © 2020 Unicode®, Inc.` 144 | * `DerivedGeneralCategory-13.0.0.txt, Date: 2019-10-21, 14:30:32 GMT, © 2019 Unicode®, Inc.` 145 | 146 | -------------------------------------------------------------------------------- /wcwidth/widetab.lua: -------------------------------------------------------------------------------- 1 | -- Autogenerated from EastAsianWidth.txt 2 | return { 3 | 0x00001100,0x0000115F, 4 | 0x0000231A,0x0000231B, 5 | 0x00002329,0x00002329, 6 | 0x0000232A,0x0000232A, 7 | 0x000023E9,0x000023EC, 8 | 0x000023F0,0x000023F0, 9 | 0x000023F3,0x000023F3, 10 | 0x000025FD,0x000025FE, 11 | 0x00002614,0x00002615, 12 | 0x00002648,0x00002653, 13 | 0x0000267F,0x0000267F, 14 | 0x00002693,0x00002693, 15 | 0x000026A1,0x000026A1, 16 | 0x000026AA,0x000026AB, 17 | 0x000026BD,0x000026BE, 18 | 0x000026C4,0x000026C5, 19 | 0x000026CE,0x000026CE, 20 | 0x000026D4,0x000026D4, 21 | 0x000026EA,0x000026EA, 22 | 0x000026F2,0x000026F3, 23 | 0x000026F5,0x000026F5, 24 | 0x000026FA,0x000026FA, 25 | 0x000026FD,0x000026FD, 26 | 0x00002705,0x00002705, 27 | 0x0000270A,0x0000270B, 28 | 0x00002728,0x00002728, 29 | 0x0000274C,0x0000274C, 30 | 0x0000274E,0x0000274E, 31 | 0x00002753,0x00002755, 32 | 0x00002757,0x00002757, 33 | 0x00002795,0x00002797, 34 | 0x000027B0,0x000027B0, 35 | 0x000027BF,0x000027BF, 36 | 0x00002B1B,0x00002B1C, 37 | 0x00002B50,0x00002B50, 38 | 0x00002B55,0x00002B55, 39 | 0x00002E80,0x00002E99, 40 | 0x00002E9B,0x00002EF3, 41 | 0x00002F00,0x00002FD5, 42 | 0x00002FF0,0x00002FFB, 43 | 0x00003000,0x00003000, 44 | 0x00003001,0x00003003, 45 | 0x00003004,0x00003004, 46 | 0x00003005,0x00003005, 47 | 0x00003006,0x00003006, 48 | 0x00003007,0x00003007, 49 | 0x00003008,0x00003008, 50 | 0x00003009,0x00003009, 51 | 0x0000300A,0x0000300A, 52 | 0x0000300B,0x0000300B, 53 | 0x0000300C,0x0000300C, 54 | 0x0000300D,0x0000300D, 55 | 0x0000300E,0x0000300E, 56 | 0x0000300F,0x0000300F, 57 | 0x00003010,0x00003010, 58 | 0x00003011,0x00003011, 59 | 0x00003012,0x00003013, 60 | 0x00003014,0x00003014, 61 | 0x00003015,0x00003015, 62 | 0x00003016,0x00003016, 63 | 0x00003017,0x00003017, 64 | 0x00003018,0x00003018, 65 | 0x00003019,0x00003019, 66 | 0x0000301A,0x0000301A, 67 | 0x0000301B,0x0000301B, 68 | 0x0000301C,0x0000301C, 69 | 0x0000301D,0x0000301D, 70 | 0x0000301E,0x0000301F, 71 | 0x00003020,0x00003020, 72 | 0x00003021,0x00003029, 73 | 0x0000302A,0x0000302D, 74 | 0x0000302E,0x0000302F, 75 | 0x00003030,0x00003030, 76 | 0x00003031,0x00003035, 77 | 0x00003036,0x00003037, 78 | 0x00003038,0x0000303A, 79 | 0x0000303B,0x0000303B, 80 | 0x0000303C,0x0000303C, 81 | 0x0000303D,0x0000303D, 82 | 0x0000303E,0x0000303E, 83 | 0x00003041,0x00003096, 84 | 0x00003099,0x0000309A, 85 | 0x0000309B,0x0000309C, 86 | 0x0000309D,0x0000309E, 87 | 0x0000309F,0x0000309F, 88 | 0x000030A0,0x000030A0, 89 | 0x000030A1,0x000030FA, 90 | 0x000030FB,0x000030FB, 91 | 0x000030FC,0x000030FE, 92 | 0x000030FF,0x000030FF, 93 | 0x00003105,0x0000312F, 94 | 0x00003131,0x0000318E, 95 | 0x00003190,0x00003191, 96 | 0x00003192,0x00003195, 97 | 0x00003196,0x0000319F, 98 | 0x000031A0,0x000031BF, 99 | 0x000031C0,0x000031E3, 100 | 0x000031F0,0x000031FF, 101 | 0x00003200,0x0000321E, 102 | 0x00003220,0x00003229, 103 | 0x0000322A,0x00003247, 104 | 0x00003250,0x00003250, 105 | 0x00003251,0x0000325F, 106 | 0x00003260,0x0000327F, 107 | 0x00003280,0x00003289, 108 | 0x0000328A,0x000032B0, 109 | 0x000032B1,0x000032BF, 110 | 0x000032C0,0x000032FF, 111 | 0x00003300,0x000033FF, 112 | 0x00003400,0x00004DBF, 113 | 0x00004E00,0x00009FFC, 114 | 0x00009FFD,0x00009FFF, 115 | 0x0000A000,0x0000A014, 116 | 0x0000A015,0x0000A015, 117 | 0x0000A016,0x0000A48C, 118 | 0x0000A490,0x0000A4C6, 119 | 0x0000A960,0x0000A97C, 120 | 0x0000AC00,0x0000D7A3, 121 | 0x0000F900,0x0000FA6D, 122 | 0x0000FA6E,0x0000FA6F, 123 | 0x0000FA70,0x0000FAD9, 124 | 0x0000FADA,0x0000FAFF, 125 | 0x0000FE10,0x0000FE16, 126 | 0x0000FE17,0x0000FE17, 127 | 0x0000FE18,0x0000FE18, 128 | 0x0000FE19,0x0000FE19, 129 | 0x0000FE30,0x0000FE30, 130 | 0x0000FE31,0x0000FE32, 131 | 0x0000FE33,0x0000FE34, 132 | 0x0000FE35,0x0000FE35, 133 | 0x0000FE36,0x0000FE36, 134 | 0x0000FE37,0x0000FE37, 135 | 0x0000FE38,0x0000FE38, 136 | 0x0000FE39,0x0000FE39, 137 | 0x0000FE3A,0x0000FE3A, 138 | 0x0000FE3B,0x0000FE3B, 139 | 0x0000FE3C,0x0000FE3C, 140 | 0x0000FE3D,0x0000FE3D, 141 | 0x0000FE3E,0x0000FE3E, 142 | 0x0000FE3F,0x0000FE3F, 143 | 0x0000FE40,0x0000FE40, 144 | 0x0000FE41,0x0000FE41, 145 | 0x0000FE42,0x0000FE42, 146 | 0x0000FE43,0x0000FE43, 147 | 0x0000FE44,0x0000FE44, 148 | 0x0000FE45,0x0000FE46, 149 | 0x0000FE47,0x0000FE47, 150 | 0x0000FE48,0x0000FE48, 151 | 0x0000FE49,0x0000FE4C, 152 | 0x0000FE4D,0x0000FE4F, 153 | 0x0000FE50,0x0000FE52, 154 | 0x0000FE54,0x0000FE57, 155 | 0x0000FE58,0x0000FE58, 156 | 0x0000FE59,0x0000FE59, 157 | 0x0000FE5A,0x0000FE5A, 158 | 0x0000FE5B,0x0000FE5B, 159 | 0x0000FE5C,0x0000FE5C, 160 | 0x0000FE5D,0x0000FE5D, 161 | 0x0000FE5E,0x0000FE5E, 162 | 0x0000FE5F,0x0000FE61, 163 | 0x0000FE62,0x0000FE62, 164 | 0x0000FE63,0x0000FE63, 165 | 0x0000FE64,0x0000FE66, 166 | 0x0000FE68,0x0000FE68, 167 | 0x0000FE69,0x0000FE69, 168 | 0x0000FE6A,0x0000FE6B, 169 | 0x0000FF01,0x0000FF03, 170 | 0x0000FF04,0x0000FF04, 171 | 0x0000FF05,0x0000FF07, 172 | 0x0000FF08,0x0000FF08, 173 | 0x0000FF09,0x0000FF09, 174 | 0x0000FF0A,0x0000FF0A, 175 | 0x0000FF0B,0x0000FF0B, 176 | 0x0000FF0C,0x0000FF0C, 177 | 0x0000FF0D,0x0000FF0D, 178 | 0x0000FF0E,0x0000FF0F, 179 | 0x0000FF10,0x0000FF19, 180 | 0x0000FF1A,0x0000FF1B, 181 | 0x0000FF1C,0x0000FF1E, 182 | 0x0000FF1F,0x0000FF20, 183 | 0x0000FF21,0x0000FF3A, 184 | 0x0000FF3B,0x0000FF3B, 185 | 0x0000FF3C,0x0000FF3C, 186 | 0x0000FF3D,0x0000FF3D, 187 | 0x0000FF3E,0x0000FF3E, 188 | 0x0000FF3F,0x0000FF3F, 189 | 0x0000FF40,0x0000FF40, 190 | 0x0000FF41,0x0000FF5A, 191 | 0x0000FF5B,0x0000FF5B, 192 | 0x0000FF5C,0x0000FF5C, 193 | 0x0000FF5D,0x0000FF5D, 194 | 0x0000FF5E,0x0000FF5E, 195 | 0x0000FF5F,0x0000FF5F, 196 | 0x0000FF60,0x0000FF60, 197 | 0x0000FFE0,0x0000FFE1, 198 | 0x0000FFE2,0x0000FFE2, 199 | 0x0000FFE3,0x0000FFE3, 200 | 0x0000FFE4,0x0000FFE4, 201 | 0x0000FFE5,0x0000FFE6, 202 | 0x00016FE0,0x00016FE1, 203 | 0x00016FE2,0x00016FE2, 204 | 0x00016FE3,0x00016FE3, 205 | 0x00016FE4,0x00016FE4, 206 | 0x00016FF0,0x00016FF1, 207 | 0x00017000,0x000187F7, 208 | 0x00018800,0x00018AFF, 209 | 0x00018B00,0x00018CD5, 210 | 0x00018D00,0x00018D08, 211 | 0x0001B000,0x0001B0FF, 212 | 0x0001B100,0x0001B11E, 213 | 0x0001B150,0x0001B152, 214 | 0x0001B164,0x0001B167, 215 | 0x0001B170,0x0001B2FB, 216 | 0x0001F004,0x0001F004, 217 | 0x0001F0CF,0x0001F0CF, 218 | 0x0001F18E,0x0001F18E, 219 | 0x0001F191,0x0001F19A, 220 | 0x0001F200,0x0001F202, 221 | 0x0001F210,0x0001F23B, 222 | 0x0001F240,0x0001F248, 223 | 0x0001F250,0x0001F251, 224 | 0x0001F260,0x0001F265, 225 | 0x0001F300,0x0001F320, 226 | 0x0001F32D,0x0001F335, 227 | 0x0001F337,0x0001F37C, 228 | 0x0001F37E,0x0001F393, 229 | 0x0001F3A0,0x0001F3CA, 230 | 0x0001F3CF,0x0001F3D3, 231 | 0x0001F3E0,0x0001F3F0, 232 | 0x0001F3F4,0x0001F3F4, 233 | 0x0001F3F8,0x0001F3FA, 234 | 0x0001F3FB,0x0001F3FF, 235 | 0x0001F400,0x0001F43E, 236 | 0x0001F440,0x0001F440, 237 | 0x0001F442,0x0001F4FC, 238 | 0x0001F4FF,0x0001F53D, 239 | 0x0001F54B,0x0001F54E, 240 | 0x0001F550,0x0001F567, 241 | 0x0001F57A,0x0001F57A, 242 | 0x0001F595,0x0001F596, 243 | 0x0001F5A4,0x0001F5A4, 244 | 0x0001F5FB,0x0001F5FF, 245 | 0x0001F600,0x0001F64F, 246 | 0x0001F680,0x0001F6C5, 247 | 0x0001F6CC,0x0001F6CC, 248 | 0x0001F6D0,0x0001F6D2, 249 | 0x0001F6D5,0x0001F6D7, 250 | 0x0001F6EB,0x0001F6EC, 251 | 0x0001F6F4,0x0001F6FC, 252 | 0x0001F7E0,0x0001F7EB, 253 | 0x0001F90C,0x0001F93A, 254 | 0x0001F93C,0x0001F945, 255 | 0x0001F947,0x0001F978, 256 | 0x0001F97A,0x0001F9CB, 257 | 0x0001F9CD,0x0001F9FF, 258 | 0x0001FA70,0x0001FA74, 259 | 0x0001FA78,0x0001FA7A, 260 | 0x0001FA80,0x0001FA86, 261 | 0x0001FA90,0x0001FAA8, 262 | 0x0001FAB0,0x0001FAB6, 263 | 0x0001FAC0,0x0001FAC2, 264 | 0x0001FAD0,0x0001FAD6, 265 | 0x00020000,0x0002A6DD, 266 | 0x0002A6DE,0x0002A6FF, 267 | 0x0002A700,0x0002B734, 268 | 0x0002B735,0x0002B73F, 269 | 0x0002B740,0x0002B81D, 270 | 0x0002B81E,0x0002B81F, 271 | 0x0002B820,0x0002CEA1, 272 | 0x0002CEA2,0x0002CEAF, 273 | 0x0002CEB0,0x0002EBE0, 274 | 0x0002EBE1,0x0002F7FF, 275 | 0x0002F800,0x0002FA1D, 276 | 0x0002FA1E,0x0002FA1F, 277 | 0x0002FA20,0x0002FFFD, 278 | 0x00030000,0x0003134A, 279 | 0x0003134B,0x0003FFFD, 280 | } 281 | -------------------------------------------------------------------------------- /wcwidth/zerotab.lua: -------------------------------------------------------------------------------- 1 | -- Autogenerated from DerivedGeneralCategory.txt 2 | return { 3 | 0x00000300,0x0000036F, 4 | 0x00000483,0x00000487, 5 | 0x00000488,0x00000489, 6 | 0x00000591,0x000005BD, 7 | 0x000005BF,0x000005BF, 8 | 0x000005C1,0x000005C2, 9 | 0x000005C4,0x000005C5, 10 | 0x000005C7,0x000005C7, 11 | 0x00000610,0x0000061A, 12 | 0x0000064B,0x0000065F, 13 | 0x00000670,0x00000670, 14 | 0x000006D6,0x000006DC, 15 | 0x000006DF,0x000006E4, 16 | 0x000006E7,0x000006E8, 17 | 0x000006EA,0x000006ED, 18 | 0x00000711,0x00000711, 19 | 0x00000730,0x0000074A, 20 | 0x000007A6,0x000007B0, 21 | 0x000007EB,0x000007F3, 22 | 0x000007FD,0x000007FD, 23 | 0x00000816,0x00000819, 24 | 0x0000081B,0x00000823, 25 | 0x00000825,0x00000827, 26 | 0x00000829,0x0000082D, 27 | 0x00000859,0x0000085B, 28 | 0x000008D3,0x000008E1, 29 | 0x000008E3,0x00000902, 30 | 0x0000093A,0x0000093A, 31 | 0x0000093C,0x0000093C, 32 | 0x00000941,0x00000948, 33 | 0x0000094D,0x0000094D, 34 | 0x00000951,0x00000957, 35 | 0x00000962,0x00000963, 36 | 0x00000981,0x00000981, 37 | 0x000009BC,0x000009BC, 38 | 0x000009C1,0x000009C4, 39 | 0x000009CD,0x000009CD, 40 | 0x000009E2,0x000009E3, 41 | 0x000009FE,0x000009FE, 42 | 0x00000A01,0x00000A02, 43 | 0x00000A3C,0x00000A3C, 44 | 0x00000A41,0x00000A42, 45 | 0x00000A47,0x00000A48, 46 | 0x00000A4B,0x00000A4D, 47 | 0x00000A51,0x00000A51, 48 | 0x00000A70,0x00000A71, 49 | 0x00000A75,0x00000A75, 50 | 0x00000A81,0x00000A82, 51 | 0x00000ABC,0x00000ABC, 52 | 0x00000AC1,0x00000AC5, 53 | 0x00000AC7,0x00000AC8, 54 | 0x00000ACD,0x00000ACD, 55 | 0x00000AE2,0x00000AE3, 56 | 0x00000AFA,0x00000AFF, 57 | 0x00000B01,0x00000B01, 58 | 0x00000B3C,0x00000B3C, 59 | 0x00000B3F,0x00000B3F, 60 | 0x00000B41,0x00000B44, 61 | 0x00000B4D,0x00000B4D, 62 | 0x00000B55,0x00000B56, 63 | 0x00000B62,0x00000B63, 64 | 0x00000B82,0x00000B82, 65 | 0x00000BC0,0x00000BC0, 66 | 0x00000BCD,0x00000BCD, 67 | 0x00000C00,0x00000C00, 68 | 0x00000C04,0x00000C04, 69 | 0x00000C3E,0x00000C40, 70 | 0x00000C46,0x00000C48, 71 | 0x00000C4A,0x00000C4D, 72 | 0x00000C55,0x00000C56, 73 | 0x00000C62,0x00000C63, 74 | 0x00000C81,0x00000C81, 75 | 0x00000CBC,0x00000CBC, 76 | 0x00000CBF,0x00000CBF, 77 | 0x00000CC6,0x00000CC6, 78 | 0x00000CCC,0x00000CCD, 79 | 0x00000CE2,0x00000CE3, 80 | 0x00000D00,0x00000D01, 81 | 0x00000D3B,0x00000D3C, 82 | 0x00000D41,0x00000D44, 83 | 0x00000D4D,0x00000D4D, 84 | 0x00000D62,0x00000D63, 85 | 0x00000D81,0x00000D81, 86 | 0x00000DCA,0x00000DCA, 87 | 0x00000DD2,0x00000DD4, 88 | 0x00000DD6,0x00000DD6, 89 | 0x00000E31,0x00000E31, 90 | 0x00000E34,0x00000E3A, 91 | 0x00000E47,0x00000E4E, 92 | 0x00000EB1,0x00000EB1, 93 | 0x00000EB4,0x00000EBC, 94 | 0x00000EC8,0x00000ECD, 95 | 0x00000F18,0x00000F19, 96 | 0x00000F35,0x00000F35, 97 | 0x00000F37,0x00000F37, 98 | 0x00000F39,0x00000F39, 99 | 0x00000F71,0x00000F7E, 100 | 0x00000F80,0x00000F84, 101 | 0x00000F86,0x00000F87, 102 | 0x00000F8D,0x00000F97, 103 | 0x00000F99,0x00000FBC, 104 | 0x00000FC6,0x00000FC6, 105 | 0x0000102D,0x00001030, 106 | 0x00001032,0x00001037, 107 | 0x00001039,0x0000103A, 108 | 0x0000103D,0x0000103E, 109 | 0x00001058,0x00001059, 110 | 0x0000105E,0x00001060, 111 | 0x00001071,0x00001074, 112 | 0x00001082,0x00001082, 113 | 0x00001085,0x00001086, 114 | 0x0000108D,0x0000108D, 115 | 0x0000109D,0x0000109D, 116 | 0x0000135D,0x0000135F, 117 | 0x00001712,0x00001714, 118 | 0x00001732,0x00001734, 119 | 0x00001752,0x00001753, 120 | 0x00001772,0x00001773, 121 | 0x000017B4,0x000017B5, 122 | 0x000017B7,0x000017BD, 123 | 0x000017C6,0x000017C6, 124 | 0x000017C9,0x000017D3, 125 | 0x000017DD,0x000017DD, 126 | 0x0000180B,0x0000180D, 127 | 0x00001885,0x00001886, 128 | 0x000018A9,0x000018A9, 129 | 0x00001920,0x00001922, 130 | 0x00001927,0x00001928, 131 | 0x00001932,0x00001932, 132 | 0x00001939,0x0000193B, 133 | 0x00001A17,0x00001A18, 134 | 0x00001A1B,0x00001A1B, 135 | 0x00001A56,0x00001A56, 136 | 0x00001A58,0x00001A5E, 137 | 0x00001A60,0x00001A60, 138 | 0x00001A62,0x00001A62, 139 | 0x00001A65,0x00001A6C, 140 | 0x00001A73,0x00001A7C, 141 | 0x00001A7F,0x00001A7F, 142 | 0x00001AB0,0x00001ABD, 143 | 0x00001ABE,0x00001ABE, 144 | 0x00001ABF,0x00001AC0, 145 | 0x00001B00,0x00001B03, 146 | 0x00001B34,0x00001B34, 147 | 0x00001B36,0x00001B3A, 148 | 0x00001B3C,0x00001B3C, 149 | 0x00001B42,0x00001B42, 150 | 0x00001B6B,0x00001B73, 151 | 0x00001B80,0x00001B81, 152 | 0x00001BA2,0x00001BA5, 153 | 0x00001BA8,0x00001BA9, 154 | 0x00001BAB,0x00001BAD, 155 | 0x00001BE6,0x00001BE6, 156 | 0x00001BE8,0x00001BE9, 157 | 0x00001BED,0x00001BED, 158 | 0x00001BEF,0x00001BF1, 159 | 0x00001C2C,0x00001C33, 160 | 0x00001C36,0x00001C37, 161 | 0x00001CD0,0x00001CD2, 162 | 0x00001CD4,0x00001CE0, 163 | 0x00001CE2,0x00001CE8, 164 | 0x00001CED,0x00001CED, 165 | 0x00001CF4,0x00001CF4, 166 | 0x00001CF8,0x00001CF9, 167 | 0x00001DC0,0x00001DF9, 168 | 0x00001DFB,0x00001DFF, 169 | 0x000020D0,0x000020DC, 170 | 0x000020DD,0x000020E0, 171 | 0x000020E1,0x000020E1, 172 | 0x000020E2,0x000020E4, 173 | 0x000020E5,0x000020F0, 174 | 0x00002CEF,0x00002CF1, 175 | 0x00002D7F,0x00002D7F, 176 | 0x00002DE0,0x00002DFF, 177 | 0x0000302A,0x0000302D, 178 | 0x00003099,0x0000309A, 179 | 0x0000A66F,0x0000A66F, 180 | 0x0000A670,0x0000A672, 181 | 0x0000A674,0x0000A67D, 182 | 0x0000A69E,0x0000A69F, 183 | 0x0000A6F0,0x0000A6F1, 184 | 0x0000A802,0x0000A802, 185 | 0x0000A806,0x0000A806, 186 | 0x0000A80B,0x0000A80B, 187 | 0x0000A825,0x0000A826, 188 | 0x0000A82C,0x0000A82C, 189 | 0x0000A8C4,0x0000A8C5, 190 | 0x0000A8E0,0x0000A8F1, 191 | 0x0000A8FF,0x0000A8FF, 192 | 0x0000A926,0x0000A92D, 193 | 0x0000A947,0x0000A951, 194 | 0x0000A980,0x0000A982, 195 | 0x0000A9B3,0x0000A9B3, 196 | 0x0000A9B6,0x0000A9B9, 197 | 0x0000A9BC,0x0000A9BD, 198 | 0x0000A9E5,0x0000A9E5, 199 | 0x0000AA29,0x0000AA2E, 200 | 0x0000AA31,0x0000AA32, 201 | 0x0000AA35,0x0000AA36, 202 | 0x0000AA43,0x0000AA43, 203 | 0x0000AA4C,0x0000AA4C, 204 | 0x0000AA7C,0x0000AA7C, 205 | 0x0000AAB0,0x0000AAB0, 206 | 0x0000AAB2,0x0000AAB4, 207 | 0x0000AAB7,0x0000AAB8, 208 | 0x0000AABE,0x0000AABF, 209 | 0x0000AAC1,0x0000AAC1, 210 | 0x0000AAEC,0x0000AAED, 211 | 0x0000AAF6,0x0000AAF6, 212 | 0x0000ABE5,0x0000ABE5, 213 | 0x0000ABE8,0x0000ABE8, 214 | 0x0000ABED,0x0000ABED, 215 | 0x0000FB1E,0x0000FB1E, 216 | 0x0000FE00,0x0000FE0F, 217 | 0x0000FE20,0x0000FE2F, 218 | 0x000101FD,0x000101FD, 219 | 0x000102E0,0x000102E0, 220 | 0x00010376,0x0001037A, 221 | 0x00010A01,0x00010A03, 222 | 0x00010A05,0x00010A06, 223 | 0x00010A0C,0x00010A0F, 224 | 0x00010A38,0x00010A3A, 225 | 0x00010A3F,0x00010A3F, 226 | 0x00010AE5,0x00010AE6, 227 | 0x00010D24,0x00010D27, 228 | 0x00010EAB,0x00010EAC, 229 | 0x00010F46,0x00010F50, 230 | 0x00011001,0x00011001, 231 | 0x00011038,0x00011046, 232 | 0x0001107F,0x00011081, 233 | 0x000110B3,0x000110B6, 234 | 0x000110B9,0x000110BA, 235 | 0x00011100,0x00011102, 236 | 0x00011127,0x0001112B, 237 | 0x0001112D,0x00011134, 238 | 0x00011173,0x00011173, 239 | 0x00011180,0x00011181, 240 | 0x000111B6,0x000111BE, 241 | 0x000111C9,0x000111CC, 242 | 0x000111CF,0x000111CF, 243 | 0x0001122F,0x00011231, 244 | 0x00011234,0x00011234, 245 | 0x00011236,0x00011237, 246 | 0x0001123E,0x0001123E, 247 | 0x000112DF,0x000112DF, 248 | 0x000112E3,0x000112EA, 249 | 0x00011300,0x00011301, 250 | 0x0001133B,0x0001133C, 251 | 0x00011340,0x00011340, 252 | 0x00011366,0x0001136C, 253 | 0x00011370,0x00011374, 254 | 0x00011438,0x0001143F, 255 | 0x00011442,0x00011444, 256 | 0x00011446,0x00011446, 257 | 0x0001145E,0x0001145E, 258 | 0x000114B3,0x000114B8, 259 | 0x000114BA,0x000114BA, 260 | 0x000114BF,0x000114C0, 261 | 0x000114C2,0x000114C3, 262 | 0x000115B2,0x000115B5, 263 | 0x000115BC,0x000115BD, 264 | 0x000115BF,0x000115C0, 265 | 0x000115DC,0x000115DD, 266 | 0x00011633,0x0001163A, 267 | 0x0001163D,0x0001163D, 268 | 0x0001163F,0x00011640, 269 | 0x000116AB,0x000116AB, 270 | 0x000116AD,0x000116AD, 271 | 0x000116B0,0x000116B5, 272 | 0x000116B7,0x000116B7, 273 | 0x0001171D,0x0001171F, 274 | 0x00011722,0x00011725, 275 | 0x00011727,0x0001172B, 276 | 0x0001182F,0x00011837, 277 | 0x00011839,0x0001183A, 278 | 0x0001193B,0x0001193C, 279 | 0x0001193E,0x0001193E, 280 | 0x00011943,0x00011943, 281 | 0x000119D4,0x000119D7, 282 | 0x000119DA,0x000119DB, 283 | 0x000119E0,0x000119E0, 284 | 0x00011A01,0x00011A0A, 285 | 0x00011A33,0x00011A38, 286 | 0x00011A3B,0x00011A3E, 287 | 0x00011A47,0x00011A47, 288 | 0x00011A51,0x00011A56, 289 | 0x00011A59,0x00011A5B, 290 | 0x00011A8A,0x00011A96, 291 | 0x00011A98,0x00011A99, 292 | 0x00011C30,0x00011C36, 293 | 0x00011C38,0x00011C3D, 294 | 0x00011C3F,0x00011C3F, 295 | 0x00011C92,0x00011CA7, 296 | 0x00011CAA,0x00011CB0, 297 | 0x00011CB2,0x00011CB3, 298 | 0x00011CB5,0x00011CB6, 299 | 0x00011D31,0x00011D36, 300 | 0x00011D3A,0x00011D3A, 301 | 0x00011D3C,0x00011D3D, 302 | 0x00011D3F,0x00011D45, 303 | 0x00011D47,0x00011D47, 304 | 0x00011D90,0x00011D91, 305 | 0x00011D95,0x00011D95, 306 | 0x00011D97,0x00011D97, 307 | 0x00011EF3,0x00011EF4, 308 | 0x00016AF0,0x00016AF4, 309 | 0x00016B30,0x00016B36, 310 | 0x00016F4F,0x00016F4F, 311 | 0x00016F8F,0x00016F92, 312 | 0x00016FE4,0x00016FE4, 313 | 0x0001BC9D,0x0001BC9E, 314 | 0x0001D167,0x0001D169, 315 | 0x0001D17B,0x0001D182, 316 | 0x0001D185,0x0001D18B, 317 | 0x0001D1AA,0x0001D1AD, 318 | 0x0001D242,0x0001D244, 319 | 0x0001DA00,0x0001DA36, 320 | 0x0001DA3B,0x0001DA6C, 321 | 0x0001DA75,0x0001DA75, 322 | 0x0001DA84,0x0001DA84, 323 | 0x0001DA9B,0x0001DA9F, 324 | 0x0001DAA1,0x0001DAAF, 325 | 0x0001E000,0x0001E006, 326 | 0x0001E008,0x0001E018, 327 | 0x0001E01B,0x0001E021, 328 | 0x0001E023,0x0001E024, 329 | 0x0001E026,0x0001E02A, 330 | 0x0001E130,0x0001E136, 331 | 0x0001E2EC,0x0001E2EF, 332 | 0x0001E8D0,0x0001E8D6, 333 | 0x0001E944,0x0001E94A, 334 | 0x000E0100,0x000E01EF, 335 | } 336 | --------------------------------------------------------------------------------