From 23bc2171c94b24c04400f320a723f2e2ece6d47c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 11 Jan 2020 10:42:26 +0530 Subject: [PATCH] Avoid a double call for mark functions --- kitty/data-types.h | 10 ++++-- kitty/line.c | 12 +++++++ kitty/lineops.h | 1 + kitty/screen.c | 80 +++++++++++++++++++++++++++++++++++++--------- kitty/screen.h | 7 ++-- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/kitty/data-types.h b/kitty/data-types.h index 7de045222..ca7c9f702 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -58,7 +58,7 @@ typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn; #define MAX_CHILDREN 512 #define BLANK_CHAR 0 -#define ATTRS_MASK_WITHOUT_WIDTH 0xFFC +#define ATTRS_MASK_WITHOUT_WIDTH 0xFFFC #define WIDTH_MASK 3 #define DECORATION_SHIFT 2 #define DECORATION_MASK 3 @@ -69,7 +69,7 @@ typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn; #define STRIKE_SHIFT 7 #define DIM_SHIFT 8 #define MARK_SHIFT 9 -#define MARK_MASK 3 +#define ATTRS_MASK_WITHOUT_MARK 0xf9ff #define COL_MASK 0xFFFFFFFF #define UTF8_ACCEPT 0 #define UTF8_REJECT 1 @@ -143,6 +143,12 @@ typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn; #define END_ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic pop") #endif +typedef struct { + PyObject *callback; + const char *name; +} Marker; + + typedef struct { uint32_t left, top, right, bottom; } Region; diff --git a/kitty/line.c b/kitty/line.c index 8ca62de9a..80f0cf3a3 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -665,6 +665,18 @@ __eq__(Line *a, Line *b) { return a->xnum == b->xnum && memcmp(a->cpu_cells, b->cpu_cells, sizeof(CPUCell) * a->xnum) == 0 && memcmp(a->gpu_cells, b->gpu_cells, sizeof(GPUCell) * a->xnum) == 0; } + +void +mark_text_in_line(Marker *markers, size_t markers_count, Line *line) { + if (!markers_count) { + for (index_type i = 0; i < line->xnum; i++) { + line->gpu_cells[i].attrs &= ATTRS_MASK_WITHOUT_MARK; + } + return; + } + (void)markers; +} + // Boilerplate {{{ static PyObject* copy_char(Line* self, PyObject *args); diff --git a/kitty/lineops.h b/kitty/lineops.h index 04f8ae60e..3c3b8ec59 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -90,6 +90,7 @@ void historybuf_mark_line_clean(HistoryBuf *self, index_type y); void historybuf_mark_line_dirty(HistoryBuf *self, index_type y); void historybuf_refresh_sprite_positions(HistoryBuf *self); void historybuf_clear(HistoryBuf *self); +void mark_text_in_line(Marker *markers, size_t markers_count, Line *line); #define as_text_generic(args, container, get_line, lines, columns) { \ diff --git a/kitty/screen.c b/kitty/screen.c index 7a991be80..1b104c408 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -105,7 +105,6 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { self->callbacks = callbacks; Py_INCREF(callbacks); self->test_child = test_child; Py_INCREF(test_child); self->cursor = alloc_cursor(); - self->markers.callbacks = PyList_New(0); self->color_profile = alloc_color_profile(); self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns); self->linebuf = self->main_linebuf; @@ -119,7 +118,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { if ( self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->main_tabstops == NULL || self->historybuf == NULL || self->main_grman == NULL || - self->alt_grman == NULL || self->color_profile == NULL || self->markers.callbacks == NULL + self->alt_grman == NULL || self->color_profile == NULL ) { Py_CLEAR(self); return NULL; } @@ -269,6 +268,12 @@ reset_callbacks(Screen *self, PyObject *a UNUSED) { Py_RETURN_NONE; } +static void +free_marker(Marker *marker) { + Py_CLEAR(marker->callback); + free((void*)marker->name); +} + static void dealloc(Screen* self) { pthread_mutex_destroy(&self->read_buf_lock); @@ -283,7 +288,10 @@ dealloc(Screen* self) { Py_CLEAR(self->alt_linebuf); Py_CLEAR(self->historybuf); Py_CLEAR(self->color_profile); - Py_CLEAR(self->markers.callbacks); + if (self->markers.items) { + for (size_t i = 0; i < self->markers.count; i++) free_marker(self->markers.items + i); + free(self->markers.items); + } PyMem_Free(self->overlay_line.cpu_cells); PyMem_Free(self->overlay_line.gpu_cells); PyMem_Free(self->main_tabstops); @@ -1509,6 +1517,12 @@ screen_reset_dirty(Screen *self) { self->history_line_added_count = 0; } +static inline bool +screen_has_markers(Screen *self) { + return self->markers.count > 0; +} + + void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_data, bool cursor_has_moved) { unsigned int history_line_added_count = self->history_line_added_count; @@ -1522,6 +1536,7 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat historybuf_init_line(self->historybuf, lnum, self->historybuf->line); if (self->historybuf->line->has_dirty_text) { render_line(fonts_data, self->historybuf->line, lnum, self->cursor, self->disable_ligatures); + if (screen_has_markers(self)) mark_text_in_line(self->markers.items, self->markers.count, self->historybuf->line); historybuf_mark_line_clean(self->historybuf, lnum); } update_line_data(self->historybuf->line, y, address); @@ -1532,6 +1547,8 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat if (self->linebuf->line->has_dirty_text || (cursor_has_moved && (self->cursor->y == lnum || self->last_rendered_cursor_y == lnum))) { render_line(fonts_data, self->linebuf->line, lnum, self->cursor, self->disable_ligatures); + if (self->linebuf->line->has_dirty_text && screen_has_markers(self)) mark_text_in_line(self->markers.items, self->markers.count, self->linebuf->line); + linebuf_mark_line_clean(self->linebuf, lnum); } update_line_data(self->linebuf->line, y, address); @@ -2247,26 +2264,59 @@ send_escape_code_to_child(Screen *self, PyObject *args) { Py_RETURN_NONE; } +static inline void +screen_mark_all(Screen *self) { + for (index_type y = 0; y < self->main_linebuf->ynum; y++) { + linebuf_init_line(self->main_linebuf, y); + mark_text_in_line(self->markers.items, self->markers.count, self->main_linebuf->line); + } + for (index_type y = 0; y < self->alt_linebuf->ynum; y++) { + linebuf_init_line(self->alt_linebuf, y); + mark_text_in_line(self->markers.items, self->markers.count, self->alt_linebuf->line); + } + for (index_type y = 0; y < self->historybuf->ynum; y++) { + historybuf_init_line(self->historybuf, y, self->historybuf->line); + mark_text_in_line(self->markers.items, self->markers.count, self->historybuf->line); + } +} + static PyObject* -add_marker(Screen *self, PyObject *marker) { +add_marker(Screen *self, PyObject *args) { + const char *name; + PyObject *marker; + if (!PyArg_ParseTuple(args, "sO", &name, &marker)) return NULL; if (!PyCallable_Check(marker)) { PyErr_SetString(PyExc_TypeError, "marker must be a callable"); return NULL; } - if (!PySequence_Contains(self->markers.callbacks, marker)) { - if (PyList_Append(self->markers.callbacks, marker) != 0) return NULL; - self->markers.dirty = true; + for (size_t i = 0; i < self->markers.count; i++) { + if (strcmp(self->markers.items[i].name, name) == 0) { + Py_DECREF(self->markers.items[i].callback); + self->markers.items[i].callback = marker; + Py_INCREF(marker); + screen_mark_all(self); + Py_RETURN_NONE; + } } + ensure_space_for(&self->markers, items, Marker, 1, capacity, 8, true); + self->markers.items[self->markers.count].name = strdup(name); + self->markers.items[self->markers.count++].callback = marker; + Py_INCREF(marker); + screen_mark_all(self); Py_RETURN_NONE; } static PyObject* -remove_marker(Screen *self, PyObject *marker) { - Py_ssize_t idx = PySequence_Index(self->markers.callbacks, marker); - if (idx > -1) { - PySequence_DelItem(self->markers.callbacks, idx); - self->markers.dirty = true; - Py_RETURN_TRUE; +remove_marker(Screen *self, PyObject *args) { + const char *name; + if (!PyArg_ParseTuple(args, "s", &name)) return NULL; + for (size_t i = 0; i < self->markers.count; i++) { + if (strcmp(self->markers.items[i].name, name) == 0) { + free_marker(self->markers.items + i); + remove_i_from_array(self->markers.items, i, self->markers.count); + screen_mark_all(self); + Py_RETURN_TRUE; + } } Py_RETURN_FALSE; } @@ -2370,8 +2420,8 @@ static PyMethodDef methods[] = { MND(paste, METH_O) MND(paste_bytes, METH_O) MND(copy_colors_from, METH_O) - MND(add_marker, METH_O) - MND(remove_marker, METH_O) + MND(add_marker, METH_VARARGS) + MND(remove_marker, METH_VARARGS) {"select_graphic_rendition", (PyCFunction)_select_graphic_rendition, METH_VARARGS, ""}, {NULL} /* Sentinel */ diff --git a/kitty/screen.h b/kitty/screen.h index 84362ec87..524b92160 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -61,7 +61,6 @@ typedef struct { index_type xstart, ynum, xnum; } OverlayLine; - typedef struct { PyObject_HEAD @@ -108,12 +107,10 @@ typedef struct { uint8_t stop_buf[32]; } pending_mode; DisableLigature disable_ligatures; - struct { - PyObject *callbacks; - bool dirty; + Marker *items; + size_t count, capacity; } markers; - } Screen;