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 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;

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;
}
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);

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_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) { \

View File

@ -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,27 +2264,60 @@ 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;
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 */

View File

@ -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;