diff --git a/kitty/screen.c b/kitty/screen.c index c6ce96074..7d9aafe43 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1462,17 +1462,27 @@ refresh_sprite_positions(Screen *self) { } static PyObject* -screen_wcswidth(Screen UNUSED *self, PyObject *str) { +screen_wcswidth(PyObject UNUSED *self, PyObject *str) { if (PyUnicode_READY(str) != 0) return NULL; int kind = PyUnicode_KIND(str); void *data = PyUnicode_DATA(str); Py_ssize_t len = PyUnicode_GET_LENGTH(str), i; unsigned long ans = 0; + char_type prev_ch = 0; + int prev_width = 0; for (i = 0; i < len; i++) { char_type ch = PyUnicode_READ(kind, data, i); - int cw = wcwidth_std(ch); - if (cw < 1) cw = 1; - ans += cw; + if (ch == 0xfe0f) { + if (is_emoji_presentation_base(prev_ch) && prev_width == 1) { + ans += 1; + prev_width = 2; + } else prev_width = 0; + } else { + prev_width = wcwidth_std(ch); + if (prev_width < 1) prev_width = 1; + ans += prev_width; + } + prev_ch = ch; } return PyLong_FromUnsignedLong(ans); } diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 1be51129e..19ea0d4c8 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -4,7 +4,7 @@ from kitty.config import build_ansi_color_table, defaults from kitty.fast_data_types import ( - REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf, wcwidth + REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf, wcswidth, wcwidth ) from kitty.rgb import to_color from kitty.utils import sanitize_title @@ -335,7 +335,8 @@ class TestDataTypes(BaseTest): def w(x): return wcwidth(ord(x)) self.ae(tuple(map(w, 'a1\0コニチ ✔')), (1, 1, 0, 2, 2, 2, 1, 1)) - self.assertEqual(sanitize_title('a\0\01 \t\n\f\rb'), 'a b') + self.ae(wcswidth('\u2716\u2716\ufe0f\U0001f337'), 5) + self.ae(sanitize_title('a\0\01 \t\n\f\rb'), 'a b') def test_color_profile(self): c = ColorProfile()