From 8e64895c23daf69f4f28855fae691bc26a001c52 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 25 Sep 2017 20:54:36 +0530 Subject: [PATCH] Framework for testing graphics command parsing --- kitty/data-types.c | 2 ++ kitty/graphics.c | 15 +++++++++++++++ kitty/graphics.h | 2 ++ kitty/parser.c | 18 ++++++++++++++++-- kitty_tests/__init__.py | 1 + kitty_tests/parser.py | 20 ++++++++++++++++++++ 6 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 kitty/graphics.c diff --git a/kitty/data-types.c b/kitty/data-types.c index 26ee8e585..2bc538c09 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -136,6 +136,7 @@ extern bool init_glfw(PyObject *m); extern bool init_sprites(PyObject *module); extern bool init_state(PyObject *module); extern bool init_keys(PyObject *module); +extern bool init_graphics(PyObject *module); extern bool init_shaders(PyObject *module); extern bool init_shaders_debug(PyObject *module); #ifdef __APPLE__ @@ -166,6 +167,7 @@ PyInit_fast_data_types(void) { if (!init_sprites(m)) return NULL; if (!init_state(m)) return NULL; if (!init_keys(m)) return NULL; + if (!init_graphics(m)) return NULL; if (PySys_GetObject("debug_gl") == Py_True) { if (!init_shaders_debug(m)) return NULL; } else { diff --git a/kitty/graphics.c b/kitty/graphics.c new file mode 100644 index 000000000..538544c82 --- /dev/null +++ b/kitty/graphics.c @@ -0,0 +1,15 @@ +/* + * graphics.c + * Copyright (C) 2017 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "graphics.h" +#include "state.h" + + +bool +init_graphics(PyObject UNUSED *m) { + return true; +} diff --git a/kitty/graphics.h b/kitty/graphics.h index e540cc903..5eb62e2af 100644 --- a/kitty/graphics.h +++ b/kitty/graphics.h @@ -5,6 +5,8 @@ */ #pragma once +#include +#include typedef struct { unsigned char action, transmission_type; diff --git a/kitty/parser.c b/kitty/parser.c index c5d7bd3ce..94b358fd2 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -87,6 +87,7 @@ _report_params(PyObject *dump_callback, const char *name, unsigned int *params, #define GET_MACRO(_1,_2,_3,NAME,...) NAME #define REPORT_COMMAND(...) GET_MACRO(__VA_ARGS__, REPORT_COMMAND3, REPORT_COMMAND2, REPORT_COMMAND1, SENTINEL)(__VA_ARGS__) +#define REPORT_VA_COMMAND(...) Py_XDECREF(PyObject_CallFunction(dump_callback, __VA_ARGS__)); PyErr_Clear(); #define REPORT_DRAW(ch) \ Py_XDECREF(PyObject_CallFunction(dump_callback, "sC", "draw", ch)); PyErr_Clear(); @@ -109,6 +110,7 @@ _report_params(PyObject *dump_callback, const char *name, unsigned int *params, #define REPORT_ERROR(...) fprintf(stderr, "%s ", ERROR_PREFIX); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); #define REPORT_COMMAND(...) +#define REPORT_VA_COMMAND(...) #define REPORT_DRAW(ch) #define REPORT_PARAMS(...) #define FLUSH_DRAW @@ -603,7 +605,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) { 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"); return; } \ - code = utoi(screen->parser_buf + pos, i - pos); + code = utoi(screen->parser_buf + pos, i - pos); pos = i; case INT: is_negative = false; @@ -638,7 +640,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) { state = PAYLOAD; break; default: - REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value"); + REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value, found: 0x%x", screen->parser_buf[screen->parser_buf_pos - 1]); return; } break; @@ -651,6 +653,18 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) { 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 sI sI sI sI sI sI sI sI sI sI sI sI si}", "graphics_command", + A(action), A(transmission_type), + U(format), U(more), U(id), + U(width), U(height), U(x_offset), U(y_offset), U(data_height), U(data_width), U(num_cells), U(num_lines), + U(payload_sz), I(z_index) + ); +#undef U +#undef A +#undef I } static inline void diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 4ee48ee80..30224b52f 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -68,6 +68,7 @@ def filled_history_buf(ynum=5, xnum=5, cursor=Cursor()): class BaseTest(TestCase): ae = TestCase.assertEqual + maxDiff = 2000 def create_screen(self, cols=5, lines=5, scrollback=5): c = Callbacks() diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 76c592433..89bce6729 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -191,3 +191,23 @@ class TestParser(BaseTest): for prefix in '\033^', '\u009e': for suffix in '\u009c', '\033\\': pb('a{}+\\++{}bcde'.format(prefix, suffix), ('draw', 'a'), ('Unrecognized PM code: 0x2b',), ('draw', 'bcde')) + + def test_graphics_command(self): + from base64 import standard_b64encode + + def e(x): + return standard_b64encode(x.encode('utf-8') if isinstance(x, str) else x).decode('ascii') + + def c(**k): + for p, v in tuple(k.items()): + if isinstance(v, str): + k[p] = v.encode('ascii') + for f in 'action transmission_type'.split(): + k.setdefault(f, b'\0') + for f in 'format more id width height x_offset y_offset data_height data_width num_cells num_lines z_index payload_sz'.split(): + k.setdefault(f, 0) + return ('graphics_command', k) + + s = self.create_screen() + pb = partial(self.parse_bytes_dump, s) + pb('\033_Ga=t,t=f,s=100,v=99;{}\033\\'.format(e('a')), c(action='t', transmission_type='f', data_width=100, data_height=99, payload_sz=1))