Move the wcswidth functions out of screen.c

They have nothing to do with screens
This commit is contained in:
Kovid Goyal 2020-09-17 21:24:52 +05:30
parent 6461dccbdc
commit f8a80ccf5f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 119 additions and 111 deletions

View File

@ -13,6 +13,8 @@
#endif #endif
#include "data-types.h" #include "data-types.h"
#include "control-codes.h" #include "control-codes.h"
#include "unicode-data.h"
#include "wcwidth-std.h"
#include "modes.h" #include "modes.h"
#include <stddef.h> #include <stddef.h>
#include <termios.h> #include <termios.h>
@ -148,7 +150,124 @@ close_tty(PyObject *self UNUSED, PyObject *args) {
#undef TTY_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[] = { static PyMethodDef module_methods[] = {
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
{"wcswidth", (PyCFunction)wcswidth_impl, METH_O, ""},
{"open_tty", open_tty, METH_VARARGS, ""}, {"open_tty", open_tty, METH_VARARGS, ""},
{"normal_tty", normal_tty, METH_VARARGS, ""}, {"normal_tty", normal_tty, METH_VARARGS, ""},
{"raw_tty", raw_tty, METH_VARARGS, ""}, {"raw_tty", raw_tty, METH_VARARGS, ""},

View File

@ -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* static PyObject*
screen_truncate_point_for_length(PyObject UNUSED *self, PyObject *args) { 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_down1)
COUNT_WRAP(cursor_forward) COUNT_WRAP(cursor_forward)
static PyObject*
wcwidth_wrap(PyObject UNUSED *self, PyObject *chr) {
return PyLong_FromLong(wcwidth_std(PyLong_AsLong(chr)));
}
static PyObject* static PyObject*
screen_is_emoji_presentation_base(PyObject UNUSED *self, PyObject *code_) { screen_is_emoji_presentation_base(PyObject UNUSED *self, PyObject *code_) {
unsigned long code = PyLong_AsUnsignedLong(code_); unsigned long code = PyLong_AsUnsignedLong(code_);
@ -3003,8 +2894,6 @@ PyTypeObject Screen_Type = {
}; };
static PyMethodDef module_methods[] = { 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, ""}, {"is_emoji_presentation_base", (PyCFunction)screen_is_emoji_presentation_base, METH_O, ""},
{"truncate_point_for_length", (PyCFunction)screen_truncate_point_for_length, METH_VARARGS, ""}, {"truncate_point_for_length", (PyCFunction)screen_truncate_point_for_length, METH_VARARGS, ""},
{NULL} /* Sentinel */ {NULL} /* Sentinel */