mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-16 21:45:03 +02:00
A terminal input parse helper for the kittens
This commit is contained in:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user