From f8a80ccf5fe8e4420d09d9fdaffa824c5b0720be Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Sep 2020 21:24:52 +0530 Subject: [PATCH] Move the wcswidth functions out of screen.c They have nothing to do with screens --- kitty/data-types.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ kitty/screen.c | 111 ------------------------------------------ 2 files changed, 119 insertions(+), 111 deletions(-) diff --git a/kitty/data-types.c b/kitty/data-types.c index acc2bea2c..8829b7fc7 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -13,6 +13,8 @@ #endif #include "data-types.h" #include "control-codes.h" +#include "unicode-data.h" +#include "wcwidth-std.h" #include "modes.h" #include #include @@ -148,7 +150,124 @@ close_tty(PyObject *self UNUSED, PyObject *args) { #undef TTY_ARGS +static inline bool is_flag_pair(char_type a, char_type b) { + return is_flag_codepoint(a) && is_flag_codepoint(b); +} + + +static PyObject* +wcswidth_impl(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; + typedef enum {NORMAL, IN_CSI, FLAG_PAIR_STARTED, IN_ST_TERMINATED} WCSState; + WCSState state = NORMAL; + for (i = 0; i < len; i++) { + char_type ch = PyUnicode_READ(kind, data, i); + switch(state) { + case IN_CSI: { + if (0x40 <= ch && ch <= 0x7e) state = NORMAL; + } continue; + case IN_ST_TERMINATED: { + if (ch == 0x9c) state = NORMAL; + else if (ch == 0x1b && i + 1 < len && PyUnicode_READ(kind, data, i + 1) == '\\') { i++; state = NORMAL; } + } continue; + + case FLAG_PAIR_STARTED: { + state = NORMAL; + if (is_flag_pair(prev_ch, ch)) break; + } /* fallthrough */ + + case NORMAL: { + switch(ch) { + case 0x1b: { + prev_width = 0; + if (i + 1 < len) { + switch (PyUnicode_READ(kind, data, i + 1)) { + case '[': + state = IN_CSI; i++; continue; + case 'P': + case ']': + case 'X': + case '^': + case '_': + state = IN_ST_TERMINATED; i++; continue; + case 'D': + case 'E': + case 'H': + case 'M': + case 'N': + case 'O': + case 'Z': + case '6': + case '7': + case '8': + case '9': + case '=': + case '>': + case 'F': + case 'c': + case 'l': + case 'm': + case 'n': + case 'o': + case '|': + case '}': + case '~': + i++; continue; + } + } + } break; + + case 0xfe0f: { + if (is_emoji_presentation_base(prev_ch) && prev_width == 1) { + ans += 1; + prev_width = 2; + } else prev_width = 0; + } break; + + case 0xfe0e: { + if (is_emoji_presentation_base(prev_ch) && prev_width == 2) { + ans -= 1; + prev_width = 1; + } else prev_width = 0; + } break; + + default: { + if (is_flag_codepoint(ch)) state = FLAG_PAIR_STARTED; + int w = wcwidth_std(ch); + switch(w) { + case -1: + case 0: + prev_width = 0; break; + case 2: + prev_width = 2; break; + default: + prev_width = 1; break; + } + ans += prev_width; + } break; + } break; // switch(ch) + } break; // case NORMAL + } // switch(state) + prev_ch = ch; + } + return PyLong_FromUnsignedLong(ans); +} + +static PyObject* +wcwidth_wrap(PyObject UNUSED *self, PyObject *chr) { + return PyLong_FromLong(wcwidth_std(PyLong_AsLong(chr))); +} + + static PyMethodDef module_methods[] = { + {"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""}, + {"wcswidth", (PyCFunction)wcswidth_impl, METH_O, ""}, {"open_tty", open_tty, METH_VARARGS, ""}, {"normal_tty", normal_tty, METH_VARARGS, ""}, {"raw_tty", raw_tty, METH_VARARGS, ""}, diff --git a/kitty/screen.c b/kitty/screen.c index e0a470747..d9bc47631 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -2052,110 +2052,6 @@ as_text_alternate(Screen *self, PyObject *args) { } -static PyObject* -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; - typedef enum {NORMAL, IN_CSI, FLAG_PAIR_STARTED, IN_ST_TERMINATED} WCSState; - WCSState state = NORMAL; - for (i = 0; i < len; i++) { - char_type ch = PyUnicode_READ(kind, data, i); - switch(state) { - case IN_CSI: { - if (0x40 <= ch && ch <= 0x7e) state = NORMAL; - } continue; - case IN_ST_TERMINATED: { - if (ch == 0x9c) state = NORMAL; - else if (ch == 0x1b && i + 1 < len && PyUnicode_READ(kind, data, i + 1) == '\\') { i++; state = NORMAL; } - } continue; - - case FLAG_PAIR_STARTED: { - state = NORMAL; - if (is_flag_pair(prev_ch, ch)) break; - } /* fallthrough */ - - case NORMAL: { - switch(ch) { - case 0x1b: { - prev_width = 0; - if (i + 1 < len) { - switch (PyUnicode_READ(kind, data, i + 1)) { - case '[': - state = IN_CSI; i++; continue; - case 'P': - case ']': - case 'X': - case '^': - case '_': - state = IN_ST_TERMINATED; i++; continue; - case 'D': - case 'E': - case 'H': - case 'M': - case 'N': - case 'O': - case 'Z': - case '6': - case '7': - case '8': - case '9': - case '=': - case '>': - case 'F': - case 'c': - case 'l': - case 'm': - case 'n': - case 'o': - case '|': - case '}': - case '~': - i++; continue; - } - } - } break; - - case 0xfe0f: { - if (is_emoji_presentation_base(prev_ch) && prev_width == 1) { - ans += 1; - prev_width = 2; - } else prev_width = 0; - } break; - - case 0xfe0e: { - if (is_emoji_presentation_base(prev_ch) && prev_width == 2) { - ans -= 1; - prev_width = 1; - } else prev_width = 0; - } break; - - default: { - if (is_flag_codepoint(ch)) state = FLAG_PAIR_STARTED; - int w = wcwidth_std(ch); - switch(w) { - case -1: - case 0: - prev_width = 0; break; - case 2: - prev_width = 2; break; - default: - prev_width = 1; break; - } - ans += prev_width; - } break; - } break; // switch(ch) - } break; // case NORMAL - } // switch(state) - prev_ch = ch; - } - return PyLong_FromUnsignedLong(ans); -} - static PyObject* screen_truncate_point_for_length(PyObject UNUSED *self, PyObject *args) { @@ -2856,11 +2752,6 @@ COUNT_WRAP(cursor_down) COUNT_WRAP(cursor_down1) COUNT_WRAP(cursor_forward) -static PyObject* -wcwidth_wrap(PyObject UNUSED *self, PyObject *chr) { - return PyLong_FromLong(wcwidth_std(PyLong_AsLong(chr))); -} - static PyObject* screen_is_emoji_presentation_base(PyObject UNUSED *self, PyObject *code_) { unsigned long code = PyLong_AsUnsignedLong(code_); @@ -3003,8 +2894,6 @@ PyTypeObject Screen_Type = { }; static PyMethodDef module_methods[] = { - {"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""}, - {"wcswidth", (PyCFunction)screen_wcswidth, METH_O, ""}, {"is_emoji_presentation_base", (PyCFunction)screen_is_emoji_presentation_base, METH_O, ""}, {"truncate_point_for_length", (PyCFunction)screen_truncate_point_for_length, METH_VARARGS, ""}, {NULL} /* Sentinel */