Avoid a double call for mark functions

This commit is contained in:
Kovid Goyal 2020-01-11 10:42:26 +05:30
parent 0b3602f764
commit 23bc2171c9
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 88 additions and 22 deletions

View File

@ -58,7 +58,7 @@ typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
#define MAX_CHILDREN 512 #define MAX_CHILDREN 512
#define BLANK_CHAR 0 #define BLANK_CHAR 0
#define ATTRS_MASK_WITHOUT_WIDTH 0xFFC #define ATTRS_MASK_WITHOUT_WIDTH 0xFFFC
#define WIDTH_MASK 3 #define WIDTH_MASK 3
#define DECORATION_SHIFT 2 #define DECORATION_SHIFT 2
#define DECORATION_MASK 3 #define DECORATION_MASK 3
@ -69,7 +69,7 @@ typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
#define STRIKE_SHIFT 7 #define STRIKE_SHIFT 7
#define DIM_SHIFT 8 #define DIM_SHIFT 8
#define MARK_SHIFT 9 #define MARK_SHIFT 9
#define MARK_MASK 3 #define ATTRS_MASK_WITHOUT_MARK 0xf9ff
#define COL_MASK 0xFFFFFFFF #define COL_MASK 0xFFFFFFFF
#define UTF8_ACCEPT 0 #define UTF8_ACCEPT 0
#define UTF8_REJECT 1 #define UTF8_REJECT 1
@ -143,6 +143,12 @@ typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
#define END_ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic pop") #define END_ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic pop")
#endif #endif
typedef struct {
PyObject *callback;
const char *name;
} Marker;
typedef struct { typedef struct {
uint32_t left, top, right, bottom; uint32_t left, top, right, bottom;
} Region; } Region;

View File

@ -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; 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 {{{ // Boilerplate {{{
static PyObject* static PyObject*
copy_char(Line* self, PyObject *args); copy_char(Line* self, PyObject *args);

View File

@ -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_mark_line_dirty(HistoryBuf *self, index_type y);
void historybuf_refresh_sprite_positions(HistoryBuf *self); void historybuf_refresh_sprite_positions(HistoryBuf *self);
void historybuf_clear(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) { \ #define as_text_generic(args, container, get_line, lines, columns) { \

View File

@ -105,7 +105,6 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
self->callbacks = callbacks; Py_INCREF(callbacks); self->callbacks = callbacks; Py_INCREF(callbacks);
self->test_child = test_child; Py_INCREF(test_child); self->test_child = test_child; Py_INCREF(test_child);
self->cursor = alloc_cursor(); self->cursor = alloc_cursor();
self->markers.callbacks = PyList_New(0);
self->color_profile = alloc_color_profile(); self->color_profile = alloc_color_profile();
self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns); self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns);
self->linebuf = self->main_linebuf; self->linebuf = self->main_linebuf;
@ -119,7 +118,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
if ( if (
self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL ||
self->main_tabstops == NULL || self->historybuf == NULL || self->main_grman == 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; Py_CLEAR(self); return NULL;
} }
@ -269,6 +268,12 @@ reset_callbacks(Screen *self, PyObject *a UNUSED) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static void
free_marker(Marker *marker) {
Py_CLEAR(marker->callback);
free((void*)marker->name);
}
static void static void
dealloc(Screen* self) { dealloc(Screen* self) {
pthread_mutex_destroy(&self->read_buf_lock); pthread_mutex_destroy(&self->read_buf_lock);
@ -283,7 +288,10 @@ dealloc(Screen* self) {
Py_CLEAR(self->alt_linebuf); Py_CLEAR(self->alt_linebuf);
Py_CLEAR(self->historybuf); Py_CLEAR(self->historybuf);
Py_CLEAR(self->color_profile); 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.cpu_cells);
PyMem_Free(self->overlay_line.gpu_cells); PyMem_Free(self->overlay_line.gpu_cells);
PyMem_Free(self->main_tabstops); PyMem_Free(self->main_tabstops);
@ -1509,6 +1517,12 @@ screen_reset_dirty(Screen *self) {
self->history_line_added_count = 0; self->history_line_added_count = 0;
} }
static inline bool
screen_has_markers(Screen *self) {
return self->markers.count > 0;
}
void void
screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_data, bool cursor_has_moved) { 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; 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); historybuf_init_line(self->historybuf, lnum, self->historybuf->line);
if (self->historybuf->line->has_dirty_text) { if (self->historybuf->line->has_dirty_text) {
render_line(fonts_data, self->historybuf->line, lnum, self->cursor, self->disable_ligatures); 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); historybuf_mark_line_clean(self->historybuf, lnum);
} }
update_line_data(self->historybuf->line, y, address); 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 || if (self->linebuf->line->has_dirty_text ||
(cursor_has_moved && (self->cursor->y == lnum || self->last_rendered_cursor_y == lnum))) { (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); 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); linebuf_mark_line_clean(self->linebuf, lnum);
} }
update_line_data(self->linebuf->line, y, address); update_line_data(self->linebuf->line, y, address);
@ -2247,27 +2264,60 @@ send_escape_code_to_child(Screen *self, PyObject *args) {
Py_RETURN_NONE; 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* 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)) { if (!PyCallable_Check(marker)) {
PyErr_SetString(PyExc_TypeError, "marker must be a callable"); PyErr_SetString(PyExc_TypeError, "marker must be a callable");
return NULL; return NULL;
} }
if (!PySequence_Contains(self->markers.callbacks, marker)) { for (size_t i = 0; i < self->markers.count; i++) {
if (PyList_Append(self->markers.callbacks, marker) != 0) return NULL; if (strcmp(self->markers.items[i].name, name) == 0) {
self->markers.dirty = true; 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; Py_RETURN_NONE;
} }
static PyObject* static PyObject*
remove_marker(Screen *self, PyObject *marker) { remove_marker(Screen *self, PyObject *args) {
Py_ssize_t idx = PySequence_Index(self->markers.callbacks, marker); const char *name;
if (idx > -1) { if (!PyArg_ParseTuple(args, "s", &name)) return NULL;
PySequence_DelItem(self->markers.callbacks, idx); for (size_t i = 0; i < self->markers.count; i++) {
self->markers.dirty = true; 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_TRUE;
} }
}
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
@ -2370,8 +2420,8 @@ static PyMethodDef methods[] = {
MND(paste, METH_O) MND(paste, METH_O)
MND(paste_bytes, METH_O) MND(paste_bytes, METH_O)
MND(copy_colors_from, METH_O) MND(copy_colors_from, METH_O)
MND(add_marker, METH_O) MND(add_marker, METH_VARARGS)
MND(remove_marker, METH_O) MND(remove_marker, METH_VARARGS)
{"select_graphic_rendition", (PyCFunction)_select_graphic_rendition, METH_VARARGS, ""}, {"select_graphic_rendition", (PyCFunction)_select_graphic_rendition, METH_VARARGS, ""},
{NULL} /* Sentinel */ {NULL} /* Sentinel */

View File

@ -61,7 +61,6 @@ typedef struct {
index_type xstart, ynum, xnum; index_type xstart, ynum, xnum;
} OverlayLine; } OverlayLine;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
@ -108,12 +107,10 @@ typedef struct {
uint8_t stop_buf[32]; uint8_t stop_buf[32];
} pending_mode; } pending_mode;
DisableLigature disable_ligatures; DisableLigature disable_ligatures;
struct { struct {
PyObject *callbacks; Marker *items;
bool dirty; size_t count, capacity;
} markers; } markers;
} Screen; } Screen;