From c257adb56adf521cee55ceaa1b4002c3d5492e22 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 14 Aug 2021 10:26:59 +0530 Subject: [PATCH] Add a debug action to dump current lines with their attributes --- kitty/actions.py | 1 + kitty/boss.py | 4 +-- kitty/fast_data_types.pyi | 3 +++ kitty/screen.c | 52 +++++++++++++++++++++++++++++---------- kitty/types.py | 2 +- kitty/window.py | 7 ++++++ 6 files changed, 53 insertions(+), 16 deletions(-) diff --git a/kitty/actions.py b/kitty/actions.py index 0bb992a52..b36d31432 100644 --- a/kitty/actions.py +++ b/kitty/actions.py @@ -27,6 +27,7 @@ groups: Dict[ActionGroup, str] = { 'mk': 'Marks', 'lay': 'Layouts', 'misc': 'Miscellaneous', + 'debug': 'Debugging', } group_title = groups.__getitem__ diff --git a/kitty/boss.py b/kitty/boss.py index 57a07b6cf..a6897dcd1 100755 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -1930,7 +1930,7 @@ class Boss: if report: w.report_notification_activated(identifier) - @ac('misc', 'Show the environment variables that the kitty process sees') + @ac('debug', 'Show the environment variables that the kitty process sees') def show_kitty_env_vars(self) -> None: w = self.active_window if w: @@ -1955,7 +1955,7 @@ class Boss: if w is not None: tab.remove_window(w) - @ac('misc', 'Show the effective configuration kitty is running with') + @ac('debug', 'Show the effective configuration kitty is running with') def debug_config(self) -> None: from .debug_config import debug_config w = self.active_window diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 9b38198f2..d8909b667 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -974,6 +974,9 @@ class Screen: def draw(self, text: str) -> None: pass + def dump_lines_with_attrs(self, acc: Callable[[str], None]) -> None: + pass + def apply_sgr(self, text: str) -> None: pass diff --git a/kitty/screen.c b/kitty/screen.c index 8d221618f..d9855a804 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -279,7 +279,7 @@ index_selection(const Screen *self, Selections *selections, bool up) { static void -prevent_current_prompt_from_rewrapping(Screen *self, index_type columns) { +prevent_current_prompt_from_rewrapping(Screen *self) { int y = self->cursor->y; while (y >= 0) { linebuf_init_line(self->main_linebuf, y); @@ -293,19 +293,17 @@ prevent_current_prompt_from_rewrapping(Screen *self, index_type columns) { // will redraw this prompt. However when doing so it gets confused if the // cursor vertical position relative to the first prompt line changes. This // can easily be seen for instance in zsh when a right side prompt is used - // so when resizing to smaller sizes, simply blank all lines after the current - // prompt and trust the shell to redraw them + // so when resizing, simply blank all lines after the current + // prompt and trust the shell to redraw them. for (; y < (int)self->main_linebuf->ynum; y++) { linebuf_mark_line_as_not_continued(self->main_linebuf, y); - if (columns < self->columns) { - linebuf_clear_line(self->main_linebuf, y, false); - linebuf_init_line(self->main_linebuf, y); - if (y <= (int)self->cursor->y) { - // this is needed because screen_resize() checks to see if the cursor is beyond the content, - // so insert some fake content - Line *line = self->linebuf->line; - line->cpu_cells[0].ch = '>'; - } + linebuf_clear_line(self->main_linebuf, y, false); + linebuf_init_line(self->main_linebuf, y); + if (y <= (int)self->cursor->y) { + // this is needed because screen_resize() checks to see if the cursor is beyond the content, + // so insert some fake content + Line *line = self->linebuf->line; + line->cpu_cells[0].ch = '>'; } } } @@ -333,7 +331,7 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) { HistoryBuf *nh = realloc_hb(self->historybuf, self->historybuf->ynum, columns, &self->as_ansi_buf); if (nh == NULL) return false; Py_CLEAR(self->historybuf); self->historybuf = nh; - if (is_main) prevent_current_prompt_from_rewrapping(self, columns); + if (is_main) prevent_current_prompt_from_rewrapping(self); LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, self->historybuf, &cursor, &main_saved_cursor, &self->as_ansi_buf); if (n == NULL) return false; Py_CLEAR(self->main_linebuf); self->main_linebuf = n; @@ -3324,11 +3322,39 @@ reverse_scroll(Screen *self, PyObject *args) { Py_RETURN_NONE; } +static PyObject* +dump_lines_with_attrs(Screen *self, PyObject *accum) { + int y = (self->linebuf == self->main_linebuf) ? -self->historybuf->count : 0; + PyObject *t; + while (y < (int)self->lines) { + Line *line = range_line_(self, y); + t = PyUnicode_FromFormat("\x1b[31m%d: \x1b[39m", y++); + if (t) { + PyObject_CallFunctionObjArgs(accum, t); + Py_DECREF(t); + } + if (line->attrs.is_prompt_start) PyObject_CallFunction(accum, "s", "\x1b[32mprompt \x1b[39m"); + if (line->attrs.is_output_start) PyObject_CallFunction(accum, "s", "\x1b[33moutput \x1b[39m"); + if (line->attrs.continued) PyObject_CallFunction(accum, "s", "continued "); + if (line->attrs.has_dirty_text) PyObject_CallFunction(accum, "s", "dirty "); + PyObject_CallFunction(accum, "s", "\n"); + t = line_as_unicode(line, false); + if (t) { + PyObject_CallFunctionObjArgs(accum, t, NULL); + Py_DECREF(t); + } + PyObject_CallFunction(accum, "s", "\n"); + } + Py_RETURN_NONE; +} + + #define MND(name, args) {#name, (PyCFunction)name, args, #name}, #define MODEFUNC(name) MND(name, METH_NOARGS) MND(set_##name, METH_O) static PyMethodDef methods[] = { MND(line, METH_O) + MND(dump_lines_with_attrs, METH_O) MND(visual_line, METH_VARARGS) MND(current_url_text, METH_NOARGS) MND(draw, METH_O) diff --git a/kitty/types.py b/kitty/types.py index 13053a0c8..6663c4943 100644 --- a/kitty/types.py +++ b/kitty/types.py @@ -97,7 +97,7 @@ def run_once(f: Callable[[], _T]) -> RunOnce: if TYPE_CHECKING: from typing import Literal - ActionGroup = Literal['cp', 'sc', 'win', 'tab', 'mouse', 'mk', 'lay', 'misc'] + ActionGroup = Literal['cp', 'sc', 'win', 'tab', 'mouse', 'mk', 'lay', 'misc', 'debug'] else: ActionGroup = str diff --git a/kitty/window.py b/kitty/window.py index 013a46394..237d0ce34 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -545,6 +545,13 @@ class Window: return True self.write_to_child(text) + @ac('debug', 'Show a dump of the current lines in the scrollback + screen with their line attributes') + def dump_lines_with_attrs(self) -> None: + strings: List[str] = [] + self.screen.dump_lines_with_attrs(strings.append) + text = ''.join(strings) + get_boss().display_scrollback(self, text, title='Dump of lines') + def write_to_child(self, data: Union[str, bytes]) -> None: if data: if get_boss().child_monitor.needs_write(self.id, data) is not True: