mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-06 09:15:57 +02:00
Port OSC parsing
This commit is contained in:
@@ -358,9 +358,9 @@ void screen_delete_lines(Screen *self, unsigned int count/*=1*/);
|
||||
void screen_delete_characters(Screen *self, unsigned int count);
|
||||
void screen_erase_characters(Screen *self, unsigned int count);
|
||||
void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom);
|
||||
void set_title(Screen *self, const char *buf, unsigned int sz);
|
||||
void set_icon(Screen *self, const char *buf, unsigned int sz);
|
||||
void set_dynamic_color(Screen *self, unsigned int code, const char *buf, unsigned int sz);
|
||||
void set_title(Screen *self, PyObject*);
|
||||
void set_icon(Screen *self, PyObject*);
|
||||
void set_dynamic_color(Screen *self, unsigned int code, PyObject*);
|
||||
void report_device_attributes(Screen *self, unsigned int UNUSED mode, bool UNUSED secondary);
|
||||
void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count);
|
||||
void report_device_status(Screen *self, unsigned int which, bool UNUSED);
|
||||
|
||||
@@ -7,7 +7,33 @@
|
||||
#include "data-types.h"
|
||||
#include "control-codes.h"
|
||||
|
||||
static unsigned int pow10[10] = {
|
||||
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
|
||||
};
|
||||
|
||||
static inline unsigned int
|
||||
utoi(uint32_t *buf, unsigned int sz) {
|
||||
unsigned int ans = 0;
|
||||
for (int i = sz-1, j=0; i >=0; i--, j++) {
|
||||
ans += (buf[i] - '0') * pow10[j];
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
// Macros {{{
|
||||
#define IS_DIGIT \
|
||||
case '0': \
|
||||
case '1': \
|
||||
case '2': \
|
||||
case '3': \
|
||||
case '4': \
|
||||
case '5': \
|
||||
case '6': \
|
||||
case '7': \
|
||||
case '8': \
|
||||
case '9':
|
||||
|
||||
|
||||
#ifdef DUMP_COMMANDS
|
||||
static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
@@ -39,6 +65,9 @@ static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
#define REPORT_DRAW(ch) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sC", "draw", ch)); PyErr_Clear();
|
||||
|
||||
#define REPORT_OSC(name, string) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sO", #name, string)); PyErr_Clear();
|
||||
|
||||
#else
|
||||
|
||||
#define DUMP_UNUSED UNUSED
|
||||
@@ -47,6 +76,7 @@ static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
|
||||
#define REPORT_COMMAND(...)
|
||||
#define REPORT_DRAW(ch)
|
||||
#define REPORT_OSC(name, string)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -157,8 +187,41 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal
|
||||
|
||||
// OSC mode {{{
|
||||
static inline void
|
||||
dispatch_osc(Screen *screen) {
|
||||
screen->parser_buf_pos++;
|
||||
dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define DISPATCH_OSC(name) REPORT_OSC(name, string); name(screen, string);
|
||||
const unsigned int limit = screen->parser_buf_pos;
|
||||
unsigned int code=0, i;
|
||||
for (i = 0; i < MIN(limit, 5); i++) {
|
||||
if (screen->parser_buf[i] < '0' || screen->parser_buf[i] > '9') break;
|
||||
}
|
||||
if (i > 0) {
|
||||
code = utoi(screen->parser_buf, i);
|
||||
if (i < limit - 1 && screen->parser_buf[i] == ';') i++;
|
||||
}
|
||||
PyObject *string = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, screen->parser_buf + i, limit - i);
|
||||
switch(code) {
|
||||
case 0:
|
||||
DISPATCH_OSC(set_title);
|
||||
DISPATCH_OSC(set_icon);
|
||||
break;
|
||||
case 1:
|
||||
DISPATCH_OSC(set_icon);
|
||||
break;
|
||||
case 2:
|
||||
DISPATCH_OSC(set_title);
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 110:
|
||||
case 111:
|
||||
REPORT_OSC(set_dynamic_color, string);
|
||||
set_dynamic_color(screen, code, string);
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Unknown OSC code: %u", code);
|
||||
}
|
||||
Py_CLEAR(string);
|
||||
#undef DISPATCH_OSC
|
||||
}
|
||||
// }}}
|
||||
|
||||
@@ -239,7 +302,7 @@ _parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED
|
||||
/* case CSI_STATE: */
|
||||
/* CALL_HANDLER(csi); */
|
||||
case OSC:
|
||||
if (accumulate_osc(screen, codepoint, dump_callback)) { dispatch_osc(screen); SET_STATE(0); }
|
||||
if (accumulate_osc(screen, codepoint, dump_callback)) { dispatch_osc(screen, dump_callback); SET_STATE(0); }
|
||||
break;
|
||||
case DCS:
|
||||
if (accumulate_dcs(screen, codepoint, dump_callback)) { dispatch_dcs(screen); SET_STATE(0); }
|
||||
|
||||
@@ -795,18 +795,19 @@ void screen_set_cursor(Screen *self, unsigned int mode, uint8_t secondary) {
|
||||
}
|
||||
}
|
||||
|
||||
void set_title(Screen *self, const char *buf, unsigned int sz) {
|
||||
callback("title_changed", self, buf, sz);
|
||||
void set_title(Screen *self, PyObject *title) {
|
||||
PyObject_CallMethod(self->callbacks, "title_changed", "O", title);
|
||||
if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
||||
}
|
||||
|
||||
void set_icon(Screen *self, const char *buf, unsigned int sz) {
|
||||
callback("icon_changed", self, buf, sz);
|
||||
void set_icon(Screen *self, PyObject *icon) {
|
||||
PyObject_CallMethod(self->callbacks, "icon_changed", "O", icon);
|
||||
if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
||||
}
|
||||
|
||||
void set_dynamic_color(Screen *self, unsigned int code, const char *buf, unsigned int sz) {
|
||||
PyObject_CallMethod(self->callbacks, "set_dynamic_color", "Iy#", code, buf, sz);
|
||||
if (PyErr_Occurred()) PyErr_Print();
|
||||
PyErr_Clear();
|
||||
void set_dynamic_color(Screen *self, unsigned int code, PyObject *color) {
|
||||
PyObject_CallMethod(self->callbacks, "set_dynamic_color", "IO", code, color);
|
||||
if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
@@ -33,7 +33,8 @@ class Callbacks:
|
||||
self.colorbuf += data
|
||||
|
||||
def clear(self):
|
||||
self.wtcbuf = self.iconbuf = self.titlebuf = self.colorbuf = b''
|
||||
self.wtcbuf = b''
|
||||
self.iconbuf = self.titlebuf = self.colorbuf = ''
|
||||
|
||||
|
||||
class TestParser(BaseTest):
|
||||
@@ -150,19 +151,19 @@ class TestParser(BaseTest):
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
c = Callbacks()
|
||||
s.callbacks = c
|
||||
pb(b'a\033]2;xyz\x07bcde', 'a', ('set_title', 3), 'bcde')
|
||||
pb(b'a\033]2;xyz\x07bcde', 'a', ('set_title', 'xyz'), 'bcde')
|
||||
self.ae(str(s.line(0)), 'abcde')
|
||||
self.ae(c.titlebuf, b'xyz')
|
||||
self.ae(c.titlebuf, 'xyz')
|
||||
c.clear()
|
||||
pb('\033]\x07', ('set_title', 0), ('set_icon', 0))
|
||||
self.ae(c.titlebuf, b''), self.ae(c.iconbuf, b'')
|
||||
pb('\033]ab\x07', ('set_title', 2), ('set_icon', 2))
|
||||
self.ae(c.titlebuf, b'ab'), self.ae(c.iconbuf, b'ab')
|
||||
pb('\033]\x07', ('set_title', ''), ('set_icon', ''))
|
||||
self.ae(c.titlebuf, ''), self.ae(c.iconbuf, '')
|
||||
pb('\033]ab\x07', ('set_title', 'ab'), ('set_icon', 'ab'))
|
||||
self.ae(c.titlebuf, 'ab'), self.ae(c.iconbuf, 'ab')
|
||||
c.clear()
|
||||
pb('\033]2;;;;\x07', ('set_title', 3))
|
||||
self.ae(c.titlebuf, b';;;')
|
||||
pb('\033]110\x07', ('set_dynamic_color', 110, 0))
|
||||
self.ae(c.colorbuf, b'')
|
||||
pb('\033]2;;;;\x07', ('set_title', ';;;'))
|
||||
self.ae(c.titlebuf, ';;;')
|
||||
pb('\033]110\x07', ('set_dynamic_color', ''))
|
||||
self.ae(c.colorbuf, '')
|
||||
|
||||
# def test_dcs_codes(self):
|
||||
# s = self.create_screen()
|
||||
|
||||
Reference in New Issue
Block a user