From fb576536657c3d44509bfdad18bbb7830f511071 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 19 May 2018 16:32:08 +0530 Subject: [PATCH] Make debugging kittens a little nicer Now debug() writes to the stderr of the parent kitty process instead of a temp file. --- kittens/runner.py | 2 -- kittens/tui/handler.py | 7 +++++-- kittens/tui/loop.py | 18 +++++++++++------- kitty/parser.c | 13 ++++++++++++- kitty/screen.c | 5 +++++ kitty/screen.h | 1 + kitty/window.py | 6 ++++++ 7 files changed, 40 insertions(+), 12 deletions(-) diff --git a/kittens/runner.py b/kittens/runner.py index 42b89b18d..53384149c 100644 --- a/kittens/runner.py +++ b/kittens/runner.py @@ -46,8 +46,6 @@ def create_kitten_handler(kitten, orig_args): def set_debug(kitten): from kittens.tui.loop import debug - path = os.path.join('/tmp', 'kitten-' + kitten) - debug.fd = open(path, 'w') import builtins builtins.debug = debug diff --git a/kittens/tui/handler.py b/kittens/tui/handler.py index a32b9e430..3c71cf9c1 100644 --- a/kittens/tui/handler.py +++ b/kittens/tui/handler.py @@ -3,16 +3,17 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal -from kittens.tui.operations import commander +from .operations import commander class Handler: image_manager_class = None - def _initialize(self, screen_size, quit_loop, wakeup, start_job, image_manager=None): + def _initialize(self, screen_size, quit_loop, wakeup, start_job, debug, image_manager=None): self.screen_size, self.quit_loop = screen_size, quit_loop self.wakeup = wakeup + self.debug = debug self.start_job = start_job self.cmd = commander(self) self.image_manager = image_manager @@ -20,10 +21,12 @@ class Handler: def __enter__(self): if self.image_manager is not None: self.image_manager.__enter__() + self.debug.fobj = self self.initialize() def __exit__(self, *a): del self.write_buf[:] + del self.debug.fobj self.finalize() if self.image_manager is not None: self.image_manager.__exit__(*a) diff --git a/kittens/tui/loop.py b/kittens/tui/loop.py index e77e43850..d56739d93 100644 --- a/kittens/tui/loop.py +++ b/kittens/tui/loop.py @@ -31,12 +31,16 @@ screen_size = screen_size_function() def debug(*a, **kw): - fd = getattr(debug, 'fd', None) - if fd is None: - fd = debug.fd = open('/tmp/kitten-debug', 'w') - kw['file'] = fd + from base64 import standard_b64encode + buf = io.StringIO() + kw['file'] = buf print(*a, **kw) - fd.flush() + text = buf.getvalue() + text = b'\x1bP@kitty-print|' + standard_b64encode(text.encode('utf-8')) + b'\x1b\\' + fobj = getattr(debug, 'fobj', sys.stdout.buffer) + fobj.write(text) + if hasattr(fobj, 'flush'): + fobj.flush() def write_all(fd, data): @@ -374,7 +378,7 @@ class Loop: image_manager = handler.image_manager_class(handler) keep_going = True try: - handler._initialize(screen_size(), self.quit, self.wakeup, self.start_job, image_manager) + handler._initialize(screen_size(), self.quit, self.wakeup, self.start_job, debug, image_manager) with handler: while keep_going: has_data_to_write = bool(handler.write_buf) @@ -403,7 +407,7 @@ class Loop: handler = UnhandledException(tb) handler.write_buf = [] handler._term_manager = term_manager - handler._initialize(screen_size(), self.quit, self.wakeup, self.start_job) + handler._initialize(screen_size(), self.quit, self.wakeup, self.start_job, debug) with handler: while True: has_data_to_write = bool(handler.write_buf) diff --git a/kitty/parser.c b/kitty/parser.c index 43fb2e9a1..aa334d4ea 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -769,17 +769,28 @@ dispatch_dcs(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { } break; case '@': - if (startswith(screen->parser_buf + 1, screen->parser_buf_pos - 2, "kitty-cmd{")) { +#define CMD_PREFIX "kitty-cmd{" + if (startswith(screen->parser_buf + 1, screen->parser_buf_pos - 2, CMD_PREFIX)) { PyObject *cmd = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, screen->parser_buf + 10, screen->parser_buf_pos - 10); if (cmd != NULL) { REPORT_OSC2(screen_handle_cmd, (char)screen->parser_buf[0], cmd); screen_handle_cmd(screen, cmd); Py_DECREF(cmd); } else PyErr_Clear(); +#undef CMD_PREFIX +#define PRINT_PREFIX "kitty-print|" + } else if (startswith(screen->parser_buf + 1, screen->parser_buf_pos - 1, PRINT_PREFIX)) { + PyObject *msg = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, screen->parser_buf + sizeof(PRINT_PREFIX), screen->parser_buf_pos - sizeof(PRINT_PREFIX)); + if (msg != NULL) { + REPORT_OSC2(screen_handle_print, (char)screen->parser_buf[0], msg); + screen_handle_print(screen, msg); + Py_DECREF(msg); + } else PyErr_Clear(); } else { REPORT_ERROR("Unrecognized DCS @ code: 0x%x", screen->parser_buf[1]); } break; +#undef PRINT_PREFIX default: REPORT_ERROR("Unrecognized DCS code: 0x%x", screen->parser_buf[0]); break; diff --git a/kitty/screen.c b/kitty/screen.c index 861cb57c4..f8fdaf58b 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1219,6 +1219,11 @@ screen_handle_cmd(Screen *self, PyObject *cmd) { CALLBACK("handle_remote_cmd", "O", cmd); } +void +screen_handle_print(Screen *self, PyObject *msg) { + CALLBACK("handle_remote_print", "O", msg); +} + void screen_request_capabilities(Screen *self, char c, PyObject *q) { static char buf[128]; diff --git a/kitty/screen.h b/kitty/screen.h index e0a711e23..9386c8d97 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -138,6 +138,7 @@ void screen_erase_characters(Screen *self, unsigned int count); void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom); void screen_change_charset(Screen *, uint32_t to); void screen_handle_cmd(Screen *, PyObject *cmd); +void screen_handle_print(Screen *, PyObject *cmd); void screen_designate_charset(Screen *, uint32_t which, uint32_t as); void screen_use_latin1(Screen *, bool); void set_title(Screen *self, PyObject*); diff --git a/kitty/window.py b/kitty/window.py index 864c00e81..a6a00995e 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -328,6 +328,12 @@ class Window: def handle_remote_cmd(self, cmd): get_boss().handle_remote_cmd(cmd, self) + def handle_remote_print(self, msg): + from base64 import standard_b64decode + msg = standard_b64decode(msg).decode('utf-8') + print(msg, end='', file=sys.stderr) + sys.stderr.flush() + def send_cmd_response(self, response): self.screen.send_escape_code_to_child(DCS, '@kitty-cmd' + json.dumps(response))