Display wide characters correctly.
- Made termstr's length match the on-screen width.
- Achieved by adding a zero width character after each wide
character.
- This fixes ljust and rjust, so that there is correct padding,
otherwise Portal appearances aren't the correct width.
- When getting a sub-string containing half a wide character,
the half character is a space.
- Some wide characters are still broken. e.g. country flags
This commit is contained in:
parent
c4fb3fdfe3
commit
c91beda9b4
3 changed files with 34 additions and 7 deletions
|
|
@ -8,6 +8,7 @@ import os
|
|||
import weakref
|
||||
|
||||
import pygments.formatters.terminal256
|
||||
import cwcwidth
|
||||
|
||||
import eris.ColorMap
|
||||
import eris.terminal as terminal
|
||||
|
|
@ -130,15 +131,26 @@ def _join_lists(lists):
|
|||
return list(itertools.chain.from_iterable(lists))
|
||||
|
||||
|
||||
_ZERO_WIDTH_SPACE = chr(0x00ad)
|
||||
|
||||
|
||||
def _pad_wide_chars(str_):
|
||||
return "".join(f"{char}{_ZERO_WIDTH_SPACE}"
|
||||
if cwcwidth.wcwidth(char) == 2 else char for char in str_)
|
||||
|
||||
|
||||
class TermStr(collections.UserString):
|
||||
|
||||
def __init__(self, data, style=CharStyle()):
|
||||
try:
|
||||
self.data, self.style = data.data, data.style
|
||||
except AttributeError:
|
||||
if isinstance(style, tuple):
|
||||
self.data = data
|
||||
self.style = (style if isinstance(style, tuple)
|
||||
else (style,) * len(data))
|
||||
self.style = style
|
||||
else:
|
||||
try:
|
||||
self.data, self.style = data.data, data.style
|
||||
except AttributeError:
|
||||
self.data = _pad_wide_chars(data)
|
||||
self.style = (style,) * len(self.data)
|
||||
|
||||
@classmethod
|
||||
def from_term(cls, data):
|
||||
|
|
@ -249,7 +261,17 @@ class TermStr(collections.UserString):
|
|||
__rmul__ = __mul__
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.__class__(self.data[index], self.style[index])
|
||||
data = self.data[index]
|
||||
if len(data) == 0:
|
||||
result = ""
|
||||
else:
|
||||
first_char = " " if data[0] == _ZERO_WIDTH_SPACE else data[0]
|
||||
if len(data) == 1:
|
||||
result = first_char
|
||||
else:
|
||||
end_char = " " if cwcwidth.wcwidth(data[-1]) == 2 else data[-1]
|
||||
result = first_char + data[1:-1] + end_char
|
||||
return self.__class__(result, self.style[index])
|
||||
|
||||
def join(self, parts):
|
||||
parts = [TermStr(part) if isinstance(part, str) else part
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ if [ $DIST_ID != "ubuntu" ]; then
|
|||
exit 1
|
||||
fi
|
||||
echo "Installing the dependencies of the eris script…"
|
||||
sudo apt --yes install python3-pip python3.9 util-linux
|
||||
sudo apt --yes install python3-pip python3.9 util-linux python3-cwcwidth
|
||||
python3.9 -m pip install pyinotify pygments docopt pillow toml
|
||||
echo
|
||||
echo "Installing all the tools eris may need…"
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ class TermStrTests(unittest.TestCase):
|
|||
self.assertEqual(foo_bold.ljust(5), foo_bold + TermStr(" "))
|
||||
self.assertEqual(foo_bold.rjust(0), foo_bold)
|
||||
self.assertEqual(foo_bold.rjust(5), TermStr(" ") + foo_bold)
|
||||
baz = TermStr("b👋z")
|
||||
self.assertEqual(len(baz), 4)
|
||||
self.assertEqual(baz[3:], TermStr("z"))
|
||||
self.assertEqual(baz[:2], TermStr("b "))
|
||||
self.assertEqual(baz[2:], TermStr(" z"))
|
||||
|
||||
def test_from_term(self):
|
||||
def test_round_trip(term_str):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue