A terminal input parse helper for the kittens
This commit is contained in:
parent
ff2e5b3966
commit
fa87ce72a8
@ -173,6 +173,7 @@ extern bool init_keys(PyObject *module);
|
|||||||
extern bool init_graphics(PyObject *module);
|
extern bool init_graphics(PyObject *module);
|
||||||
extern bool init_shaders(PyObject *module);
|
extern bool init_shaders(PyObject *module);
|
||||||
extern bool init_mouse(PyObject *module);
|
extern bool init_mouse(PyObject *module);
|
||||||
|
extern bool init_kittens(PyObject *module);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
extern int init_CoreText(PyObject *);
|
extern int init_CoreText(PyObject *);
|
||||||
extern bool init_cocoa(PyObject *module);
|
extern bool init_cocoa(PyObject *module);
|
||||||
@ -206,6 +207,7 @@ PyInit_fast_data_types(void) {
|
|||||||
if (!init_graphics(m)) return NULL;
|
if (!init_graphics(m)) return NULL;
|
||||||
if (!init_shaders(m)) return NULL;
|
if (!init_shaders(m)) return NULL;
|
||||||
if (!init_mouse(m)) return NULL;
|
if (!init_mouse(m)) return NULL;
|
||||||
|
if (!init_kittens(m)) return NULL;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (!init_CoreText(m)) return NULL;
|
if (!init_CoreText(m)) return NULL;
|
||||||
if (!init_cocoa(m)) return NULL;
|
if (!init_cocoa(m)) return NULL;
|
||||||
|
|||||||
93
kitty/kittens.c
Normal file
93
kitty/kittens.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* kittens.c
|
||||||
|
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "data-types.h"
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
parse_input_from_terminal(PyObject *self UNUSED, PyObject *args) {
|
||||||
|
enum State { NORMAL, ESC, CSI, ST, ESC_ST };
|
||||||
|
enum State state = NORMAL;
|
||||||
|
PyObject *uo, *text_callback, *dcs_callback, *csi_callback, *osc_callback, *pm_callback, *apc_callback, *callback;
|
||||||
|
if (!PyArg_ParseTuple(args, "UOOOOOO", &uo, &text_callback, &dcs_callback, &csi_callback, &osc_callback, &pm_callback, &apc_callback)) return NULL;
|
||||||
|
Py_ssize_t sz = PyUnicode_GET_LENGTH(uo), pos = 0, start = 0, count = 0, consumed = 0;
|
||||||
|
callback = text_callback;
|
||||||
|
int kind = PyUnicode_KIND(uo);
|
||||||
|
void *data = PyUnicode_DATA(uo);
|
||||||
|
#define CALL(cb, s, num) {\
|
||||||
|
if (num > 0) PyObject_CallFunction(cb, "N", PyUnicode_Substring(uo, s, s + num)); \
|
||||||
|
consumed = s + num; \
|
||||||
|
count = 0; \
|
||||||
|
}
|
||||||
|
START_ALLOW_CASE_RANGE;
|
||||||
|
while (pos < sz) {
|
||||||
|
Py_UCS4 ch = PyUnicode_READ(kind, data, pos);
|
||||||
|
switch(state) {
|
||||||
|
case NORMAL:
|
||||||
|
if (ch == 0x1b) {
|
||||||
|
state = ESC;
|
||||||
|
CALL(text_callback, start, count);
|
||||||
|
} else count++;
|
||||||
|
break;
|
||||||
|
case ESC:
|
||||||
|
start = pos;
|
||||||
|
count = 0;
|
||||||
|
switch(ch) {
|
||||||
|
case 'P':
|
||||||
|
state = ST; callback = dcs_callback; break;
|
||||||
|
case '[':
|
||||||
|
state = CSI; callback = csi_callback; break;
|
||||||
|
case ']':
|
||||||
|
state = ST; callback = osc_callback; break;
|
||||||
|
case '^':
|
||||||
|
state = ST; callback = pm_callback; break;
|
||||||
|
case '_':
|
||||||
|
state = ST; callback = apc_callback; break;
|
||||||
|
default:
|
||||||
|
state = NORMAL; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CSI:
|
||||||
|
count++;
|
||||||
|
switch (ch) {
|
||||||
|
case 'a' ... 'z':
|
||||||
|
case 'A' ... 'Z':
|
||||||
|
CALL(callback, start + 1, count);
|
||||||
|
state = NORMAL;
|
||||||
|
start = pos + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ESC_ST:
|
||||||
|
if (ch == '\\') {
|
||||||
|
CALL(callback, start + 1, count);
|
||||||
|
state = NORMAL; start = pos + 1;
|
||||||
|
consumed += 2;
|
||||||
|
} else count += 2;
|
||||||
|
break;
|
||||||
|
case ST:
|
||||||
|
if (ch == 0x1b) { state = ESC_ST; }
|
||||||
|
else count++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
if (state == NORMAL && count > 0) CALL(text_callback, start, count);
|
||||||
|
return PyUnicode_Substring(uo, consumed, sz);
|
||||||
|
END_ALLOW_CASE_RANGE;
|
||||||
|
#undef CALL
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef module_methods[] = {
|
||||||
|
METHODB(parse_input_from_terminal, METH_VARARGS),
|
||||||
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
init_kittens(PyObject *module) {
|
||||||
|
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
from kitty.config import build_ansi_color_table, defaults
|
from kitty.config import build_ansi_color_table, defaults
|
||||||
from kitty.fast_data_types import (
|
from kitty.fast_data_types import (
|
||||||
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf, wcswidth, wcwidth
|
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf,
|
||||||
|
parse_input_from_terminal, wcswidth, wcwidth
|
||||||
)
|
)
|
||||||
from kitty.rgb import to_color
|
from kitty.rgb import to_color
|
||||||
from kitty.utils import sanitize_title
|
from kitty.utils import sanitize_title
|
||||||
@ -338,6 +339,25 @@ class TestDataTypes(BaseTest):
|
|||||||
self.ae(wcswidth('\u2716\u2716\ufe0f\U0001f337'), 5)
|
self.ae(wcswidth('\u2716\u2716\ufe0f\U0001f337'), 5)
|
||||||
self.ae(sanitize_title('a\0\01 \t\n\f\rb'), 'a b')
|
self.ae(sanitize_title('a\0\01 \t\n\f\rb'), 'a b')
|
||||||
|
|
||||||
|
def tp(*data, leftover='', text='', csi='', apc=''):
|
||||||
|
text_r, csi_r, apc_r, rest = [], [], [], []
|
||||||
|
left = ''
|
||||||
|
for d in data:
|
||||||
|
left = parse_input_from_terminal(left + d, text_r.append, rest.append, csi_r.append, rest.append, rest.append, apc_r.append)
|
||||||
|
self.ae(left, leftover)
|
||||||
|
self.ae(text, ' '.join(text_r))
|
||||||
|
self.ae(csi, ' '.join(csi_r))
|
||||||
|
self.ae(apc, ' '.join(apc_r))
|
||||||
|
self.assertFalse(rest)
|
||||||
|
|
||||||
|
tp('abc', text='abc')
|
||||||
|
tp('a\033[38:5:12:32mb', text='a b', csi='38:5:12:32m')
|
||||||
|
tp('a\033_x,;(\033\\b', text='a b', apc='x,;(')
|
||||||
|
tp('a\033', '[', 'mb', text='a b', csi='m')
|
||||||
|
tp('a\033[', 'mb', text='a b', csi='m')
|
||||||
|
tp('a\033', '_', 'x\033', '\\b', text='a b', apc='x')
|
||||||
|
tp('a\033_', 'x', '\033', '\\', 'b', text='a b', apc='x')
|
||||||
|
|
||||||
def test_color_profile(self):
|
def test_color_profile(self):
|
||||||
c = ColorProfile()
|
c = ColorProfile()
|
||||||
c.update_ansi_color_table(build_ansi_color_table())
|
c.update_ansi_color_table(build_ansi_color_table())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user