Add support for colons in SGR codes
This commit is contained in:
parent
c762f6199b
commit
e90aaa8470
126
kitty/parser.c
126
kitty/parser.c
@ -343,6 +343,7 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
// CSI mode {{{
|
// CSI mode {{{
|
||||||
#define CSI_SECONDARY \
|
#define CSI_SECONDARY \
|
||||||
case ';': \
|
case ';': \
|
||||||
|
case ':': \
|
||||||
case '"': \
|
case '"': \
|
||||||
case '*': \
|
case '*': \
|
||||||
case '\'': \
|
case '\'': \
|
||||||
@ -382,6 +383,119 @@ repr_csi_params(unsigned int *params, unsigned int num_params) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params, PyObject DUMP_UNUSED *dump_callback) {
|
||||||
|
enum State { START, NORMAL, MULTIPLE, COLOR, COLOR1, COLOR3 };
|
||||||
|
enum State state = START;
|
||||||
|
unsigned int num_params, num_start, i;
|
||||||
|
|
||||||
|
#define READ_PARAM { params[num_params++] = utoi(buf + num_start, i - num_start); }
|
||||||
|
#define SEND_SGR { REPORT_PARAMS(select_graphic_rendition, params, num_params); select_graphic_rendition(screen, params, num_params); state = START; num_params = 0; }
|
||||||
|
|
||||||
|
for (i=0, num_start=0, num_params=0; i < num && num_params < MAX_PARAMS; i++) {
|
||||||
|
switch(buf[i]) {
|
||||||
|
IS_DIGIT
|
||||||
|
switch(state) {
|
||||||
|
case START:
|
||||||
|
num_start = i;
|
||||||
|
state = NORMAL;
|
||||||
|
num_params = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
switch(state) {
|
||||||
|
case START:
|
||||||
|
params[num_params++] = 0;
|
||||||
|
SEND_SGR;
|
||||||
|
break;
|
||||||
|
case NORMAL:
|
||||||
|
READ_PARAM;
|
||||||
|
switch(params[0]) {
|
||||||
|
case 38:
|
||||||
|
case 48:
|
||||||
|
case 58:
|
||||||
|
state = COLOR;
|
||||||
|
num_start = i + 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SEND_SGR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MULTIPLE:
|
||||||
|
READ_PARAM;
|
||||||
|
SEND_SGR;
|
||||||
|
break;
|
||||||
|
case COLOR:
|
||||||
|
READ_PARAM;
|
||||||
|
switch(params[1]) {
|
||||||
|
case 2:
|
||||||
|
state = COLOR3;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
state = COLOR1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
REPORT_ERROR("Invalid SGR color code with unknown color type: %u", params[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
num_start = i + 1;
|
||||||
|
break;
|
||||||
|
case COLOR1:
|
||||||
|
READ_PARAM;
|
||||||
|
SEND_SGR;
|
||||||
|
break;
|
||||||
|
case COLOR3:
|
||||||
|
READ_PARAM;
|
||||||
|
if (num_params == 5) { SEND_SGR; }
|
||||||
|
else num_start = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
switch(state) {
|
||||||
|
case START:
|
||||||
|
REPORT_ERROR("Invalid SGR code containing ':' at an invalid location: %u", i);
|
||||||
|
return;
|
||||||
|
case NORMAL:
|
||||||
|
READ_PARAM;
|
||||||
|
state = MULTIPLE;
|
||||||
|
num_start = i + 1;
|
||||||
|
break;
|
||||||
|
case MULTIPLE:
|
||||||
|
READ_PARAM;
|
||||||
|
num_start = i + 1;
|
||||||
|
break;
|
||||||
|
case COLOR:
|
||||||
|
case COLOR1:
|
||||||
|
case COLOR3:
|
||||||
|
REPORT_ERROR("Invalid SGR code containing disallowed character: %s", utf8(buf[i]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
REPORT_ERROR("Invalid SGR code containing disallowed character: %s", utf8(buf[i]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(state) {
|
||||||
|
case COLOR1:
|
||||||
|
case COLOR3:
|
||||||
|
case NORMAL:
|
||||||
|
case MULTIPLE:
|
||||||
|
READ_PARAM;
|
||||||
|
SEND_SGR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef READ_PARAM
|
||||||
|
#undef SEND_SGR
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||||
#define CALL_CSI_HANDLER1(name, defval) \
|
#define CALL_CSI_HANDLER1(name, defval) \
|
||||||
@ -424,12 +538,6 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
} \
|
} \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#define CSI_HANDLER_MULTIPLE(name) \
|
|
||||||
REPORT_PARAMS(name, params, num_params); \
|
|
||||||
name(screen, params, num_params); \
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
char start_modifier = 0, end_modifier = 0;
|
char start_modifier = 0, end_modifier = 0;
|
||||||
uint32_t *buf = screen->parser_buf, code = screen->parser_buf[screen->parser_buf_pos];
|
uint32_t *buf = screen->parser_buf, code = screen->parser_buf[screen->parser_buf_pos];
|
||||||
unsigned int num = screen->parser_buf_pos, start, i, num_params=0, p1, p2;
|
unsigned int num = screen->parser_buf_pos, start, i, num_params=0, p1, p2;
|
||||||
@ -439,6 +547,10 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
start_modifier = (char)screen->parser_buf[0];
|
start_modifier = (char)screen->parser_buf[0];
|
||||||
buf++; num--;
|
buf++; num--;
|
||||||
}
|
}
|
||||||
|
if (code == SGR && !start_modifier) {
|
||||||
|
parse_sgr(screen, buf, num, params, dump_callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
switch(buf[num-1]) {
|
switch(buf[num-1]) {
|
||||||
CSI_SECONDARY
|
CSI_SECONDARY
|
||||||
@ -506,8 +618,6 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
SET_MODE(screen_set_mode);
|
SET_MODE(screen_set_mode);
|
||||||
case RM:
|
case RM:
|
||||||
SET_MODE(screen_reset_mode);
|
SET_MODE(screen_reset_mode);
|
||||||
case SGR:
|
|
||||||
CSI_HANDLER_MULTIPLE(select_graphic_rendition);
|
|
||||||
case DSR:
|
case DSR:
|
||||||
CALL_CSI_HANDLER1P(report_device_status, 0, '?');
|
CALL_CSI_HANDLER1P(report_device_status, 0, '?');
|
||||||
case SC:
|
case SC:
|
||||||
|
|||||||
@ -115,19 +115,30 @@ class TestParser(BaseTest):
|
|||||||
pb('\033[?1000;1004h', ('screen_set_mode', 1000, 1), ('screen_set_mode', 1004, 1))
|
pb('\033[?1000;1004h', ('screen_set_mode', 1000, 1), ('screen_set_mode', 1004, 1))
|
||||||
pb('\033[20;4;20l', ('screen_reset_mode', 20, 0), ('screen_reset_mode', 4, 0), ('screen_reset_mode', 20, 0))
|
pb('\033[20;4;20l', ('screen_reset_mode', 20, 0), ('screen_reset_mode', 4, 0), ('screen_reset_mode', 20, 0))
|
||||||
s.reset()
|
s.reset()
|
||||||
pb('\033[1;3;4;7;9;34;44m', ('select_graphic_rendition', '1 3 4 7 9 34 44 '))
|
|
||||||
|
def sgr(params):
|
||||||
|
return (('select_graphic_rendition', '{} '.format(x)) for x in params.split())
|
||||||
|
|
||||||
|
pb('\033[1;3;4;7;9;34;44m', *sgr('1 3 4 7 9 34 44'))
|
||||||
for attr in 'bold italic reverse strikethrough'.split():
|
for attr in 'bold italic reverse strikethrough'.split():
|
||||||
self.assertTrue(getattr(s.cursor, attr))
|
self.assertTrue(getattr(s.cursor, attr))
|
||||||
self.ae(s.cursor.decoration, 1)
|
self.ae(s.cursor.decoration, 1)
|
||||||
self.ae(s.cursor.fg, 4 << 8 | 1)
|
self.ae(s.cursor.fg, 4 << 8 | 1)
|
||||||
self.ae(s.cursor.bg, 4 << 8 | 1)
|
self.ae(s.cursor.bg, 4 << 8 | 1)
|
||||||
pb('\033[38;5;1;48;5;7m', ('select_graphic_rendition', '38 5 1 48 5 7 '))
|
pb('\033[38;5;1;48;5;7m', ('select_graphic_rendition', '38 5 1 '), ('select_graphic_rendition', '48 5 7 '))
|
||||||
self.ae(s.cursor.fg, 1 << 8 | 1)
|
self.ae(s.cursor.fg, 1 << 8 | 1)
|
||||||
self.ae(s.cursor.bg, 7 << 8 | 1)
|
self.ae(s.cursor.bg, 7 << 8 | 1)
|
||||||
pb('\033[38;2;1;2;3;48;2;7;8;9m', ('select_graphic_rendition', '38 2 1 2 3 48 2 7 8 9 '))
|
pb('\033[38;2;1;2;3;48;2;7;8;9m', ('select_graphic_rendition', '38 2 1 2 3 '), ('select_graphic_rendition', '48 2 7 8 9 '))
|
||||||
self.ae(s.cursor.fg, 1 << 24 | 2 << 16 | 3 << 8 | 2)
|
self.ae(s.cursor.fg, 1 << 24 | 2 << 16 | 3 << 8 | 2)
|
||||||
self.ae(s.cursor.bg, 7 << 24 | 8 << 16 | 9 << 8 | 2)
|
self.ae(s.cursor.bg, 7 << 24 | 8 << 16 | 9 << 8 | 2)
|
||||||
pb('\033[;2m', ('select_graphic_rendition', '0 2 '))
|
pb('\033[0;2m', *sgr('0 2'))
|
||||||
|
pb('\033[;2m', *sgr('0 2'))
|
||||||
|
pb('\033[1;;2m', *sgr('1 0 2'))
|
||||||
|
pb('\033[38;5;1m', ('select_graphic_rendition', '38 5 1 '))
|
||||||
|
pb('\033[38;2;1;2;3m', ('select_graphic_rendition', '38 2 1 2 3 '))
|
||||||
|
pb('\033[1001:2:1:2:3m', ('select_graphic_rendition', '1001 2 1 2 3 '))
|
||||||
|
pb('\033[38:2:1:2:3;48:5:9;58;5;7m', (
|
||||||
|
'select_graphic_rendition', '38 2 1 2 3 '), ('select_graphic_rendition', '48 5 9 '), ('select_graphic_rendition', '58 5 7 '))
|
||||||
c = s.callbacks
|
c = s.callbacks
|
||||||
pb('\033[5n', ('report_device_status', 5, 0))
|
pb('\033[5n', ('report_device_status', 5, 0))
|
||||||
self.ae(c.wtcbuf, b'\033[0n')
|
self.ae(c.wtcbuf, b'\033[0n')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user