Port OSC parsing

This commit is contained in:
Kovid Goyal
2016-11-23 17:25:38 +05:30
parent cdd58207a3
commit ce8db74154
4 changed files with 90 additions and 25 deletions

View File

@@ -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);

View File

@@ -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); }

View File

@@ -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(); }
}
// }}}

View File

@@ -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()