mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-11 02:59:40 +02:00
Generate the code to parse APC escape codes
Allows it to be re-used for other APC codes if needed.
This commit is contained in:
156
kitty/parser.c
156
kitty/parser.c
@@ -824,161 +824,7 @@ dispatch_dcs(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
|
||||
// APC mode {{{
|
||||
|
||||
static inline void
|
||||
parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
unsigned int pos = 1;
|
||||
enum GR_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD };
|
||||
enum GR_STATES state = KEY, value_state = FLAG;
|
||||
enum KEYS {
|
||||
action='a',
|
||||
delete_action='d',
|
||||
transmission_type='t',
|
||||
compressed='o',
|
||||
format = 'f',
|
||||
more = 'm',
|
||||
id = 'i',
|
||||
width = 'w',
|
||||
height = 'h',
|
||||
x_offset = 'x',
|
||||
y_offset = 'y',
|
||||
data_height = 'v',
|
||||
data_width = 's',
|
||||
data_sz = 'S',
|
||||
data_offset = 'O',
|
||||
num_cells = 'c',
|
||||
num_lines = 'r',
|
||||
cell_x_offset = 'X',
|
||||
cell_y_offset = 'Y',
|
||||
z_index = 'z'
|
||||
};
|
||||
enum KEYS key = 'a';
|
||||
static GraphicsCommand g;
|
||||
unsigned int i, code;
|
||||
uint64_t lcode;
|
||||
bool is_negative;
|
||||
memset(&g, 0, sizeof(g));
|
||||
static uint8_t payload[4096];
|
||||
size_t sz;
|
||||
const char *err;
|
||||
|
||||
while (pos < screen->parser_buf_pos) {
|
||||
switch(state) {
|
||||
|
||||
case KEY:
|
||||
key = screen->parser_buf[pos++];
|
||||
switch(key) {
|
||||
#define KS(n, vs) case n: state = EQUAL; value_state = vs; break
|
||||
#define U(x) KS(x, UINT)
|
||||
KS(action, FLAG); KS(delete_action, FLAG); KS(transmission_type, FLAG); KS(compressed, FLAG); KS(z_index, INT);
|
||||
U(format); U(more); U(id); U(data_sz); U(data_offset); U(width); U(height); U(x_offset); U(y_offset); U(data_height); U(data_width); U(num_cells); U(num_lines); U(cell_x_offset); U(cell_y_offset);
|
||||
#undef U
|
||||
#undef KS
|
||||
default:
|
||||
REPORT_ERROR("Malformed graphics control block, invalid key character: 0x%x", key);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EQUAL:
|
||||
if (screen->parser_buf[pos++] != '=') {
|
||||
REPORT_ERROR("Malformed graphics control block, no = after key, found: 0x%x instead", screen->parser_buf[pos-1]);
|
||||
return;
|
||||
}
|
||||
state = value_state;
|
||||
break;
|
||||
|
||||
case FLAG:
|
||||
switch(key) {
|
||||
#define F(a) case a: g.a = screen->parser_buf[pos++] & 0xff; break
|
||||
F(action); F(delete_action); F(transmission_type); F(compressed);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef F
|
||||
|
||||
case INT:
|
||||
#define READ_UINT \
|
||||
for (i = pos; i < MIN(screen->parser_buf_pos, pos + 10); i++) { \
|
||||
if (screen->parser_buf[i] < '0' || screen->parser_buf[i] > '9') break; \
|
||||
} \
|
||||
if (i == pos) { REPORT_ERROR("Malformed graphics control block, expecting an integer value for key: %c", key & 0xFF); return; } \
|
||||
lcode = utoi(screen->parser_buf + pos, i - pos); pos = i; \
|
||||
if (lcode > UINT32_MAX) { REPORT_ERROR("id is too large"); return; } \
|
||||
code = lcode;
|
||||
|
||||
is_negative = false;
|
||||
if(screen->parser_buf[pos] == '-') { is_negative = true; pos++; }
|
||||
#define U(x) case x: g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; break
|
||||
READ_UINT;
|
||||
switch(key) {
|
||||
U(z_index);
|
||||
default: break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef U
|
||||
case UINT:
|
||||
READ_UINT;
|
||||
#define U(x) case x: g.x = code; break
|
||||
switch(key) {
|
||||
U(format); U(more); U(id); U(data_sz); U(data_offset); U(width); U(height); U(x_offset); U(y_offset); U(data_height); U(data_width); U(num_cells); U(num_lines); U(cell_x_offset); U(cell_y_offset);
|
||||
default: break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef U
|
||||
#undef SET_ATTR
|
||||
#undef READ_UINT
|
||||
case AFTER_VALUE:
|
||||
switch (screen->parser_buf[pos++]) {
|
||||
case ',':
|
||||
state = KEY;
|
||||
break;
|
||||
case ';':
|
||||
state = PAYLOAD;
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value, found: 0x%x", screen->parser_buf[pos - 1]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAYLOAD:
|
||||
sz = screen->parser_buf_pos - pos;
|
||||
err = base64_decode(screen->parser_buf + pos, sz, payload, sizeof(payload), &g.payload_sz);
|
||||
if (err != NULL) { REPORT_ERROR("Failed to parse graphics command payload with error: %s", err); return; }
|
||||
pos = screen->parser_buf_pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(state) {
|
||||
case EQUAL:
|
||||
REPORT_ERROR("Malformed graphics control block, no = after key"); return;
|
||||
case INT:
|
||||
case UINT:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting an integer value"); return;
|
||||
case FLAG:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a flag value"); return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#define A(x) #x, g.x
|
||||
#define U(x) #x, (unsigned int)(g.x)
|
||||
#define I(x) #x, (int)(g.x)
|
||||
REPORT_VA_COMMAND("s {sc sc sc sc sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI si} y#", "graphics_command",
|
||||
A(action), A(delete_action), A(transmission_type), A(compressed),
|
||||
U(format), U(more), U(id), U(data_sz), U(data_offset),
|
||||
U(width), U(height), U(x_offset), U(y_offset), U(data_height), U(data_width), U(num_cells), U(num_lines), U(cell_x_offset), U(cell_y_offset),
|
||||
U(payload_sz), I(z_index),
|
||||
payload, g.payload_sz
|
||||
);
|
||||
#undef U
|
||||
#undef A
|
||||
#undef I
|
||||
screen_handle_graphics_command(screen, &g, payload);
|
||||
}
|
||||
#include "parse-graphics-command.h"
|
||||
|
||||
static inline void
|
||||
dispatch_apc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
|
||||
Reference in New Issue
Block a user