Remove the now useless change tracking code

This commit is contained in:
Kovid Goyal 2017-09-08 18:41:04 +05:30
parent 906937149e
commit f5dbe36cf3
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 48 additions and 400 deletions

View File

@ -357,7 +357,7 @@ class CharGrid:
def prepare_for_render(self, cell_program):
if self.vao_id is None:
self.vao_id = cell_program.create_sprite_map()
if self.scroll_changed or self.screen.is_dirty():
if self.scroll_changed or self.screen.is_dirty:
self.update_cell_data(cell_program)
self.scroll_changed = False
sg = self.render_data

View File

@ -114,7 +114,6 @@ PyInit_fast_data_types(void) {
if (!init_Timers(m)) return NULL;
if (!init_ChildMonitor(m)) return NULL;
if (!init_ColorProfile(m)) return NULL;
if (!init_ChangeTracker(m)) return NULL;
if (!init_Screen(m)) return NULL;
if (!add_module_gl_constants(m)) return NULL;
if (!init_glfw(m)) return NULL;

View File

@ -195,21 +195,6 @@ typedef struct {
} ColorProfile;
PyTypeObject ColorProfile_Type;
typedef struct {
PyObject_HEAD
index_type xnum, ynum;
bool screen_changed;
bool cursor_changed;
bool dirty;
bool *changed_lines;
bool *lines_with_changed_cells;
bool *changed_cells;
unsigned int history_line_added_count;
} ChangeTracker;
PyTypeObject ChangeTracker_Type;
typedef struct {
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM,
mBRACKETED_PASTE, mFOCUS_TRACKING, mEXTENDED_KEYBOARD;
@ -245,11 +230,11 @@ typedef struct {
bool use_latin1;
Cursor *cursor;
SavepointBuffer main_savepoints, alt_savepoints;
PyObject *callbacks;
PyObject *callbacks, *is_dirty, *cursor_changed;
LineBuf *linebuf, *main_linebuf, *alt_linebuf;
HistoryBuf *historybuf;
unsigned int history_line_added_count;
bool *tabstops, *main_tabstops, *alt_tabstops;
ChangeTracker *change_tracker;
ScreenModes modes;
ColorProfile *color_profile;
@ -307,7 +292,6 @@ Line* alloc_line();
Cursor* alloc_cursor();
LineBuf* alloc_linebuf(unsigned int, unsigned int);
HistoryBuf* alloc_historybuf(unsigned int, unsigned int);
ChangeTracker* alloc_change_tracker(unsigned int, unsigned int);
ColorProfile* alloc_color_profile();
int init_LineBuf(PyObject *);
int init_HistoryBuf(PyObject *);
@ -316,7 +300,6 @@ int init_Timers(PyObject *);
int init_ChildMonitor(PyObject *);
int init_Line(PyObject *);
int init_ColorProfile(PyObject *);
int init_ChangeTracker(PyObject *);
int init_Screen(PyObject *);
int init_Face(PyObject *);
int init_Window(PyObject *);

View File

@ -9,7 +9,6 @@
#include <structmember.h>
#include <limits.h>
#include "unicode-data.h"
#include "tracker.h"
#include "modes.h"
#include "wcwidth9.h"
@ -59,17 +58,18 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
self->columns = columns; self->lines = lines;
self->write_buf = NULL;
self->modes = empty_modes;
self->cursor_changed = Py_True; self->is_dirty = Py_True;
self->margin_top = 0; self->margin_bottom = self->lines - 1;
self->history_line_added_count = 0;
RESET_CHARSETS;
self->callbacks = callbacks; Py_INCREF(callbacks);
self->cursor = alloc_cursor();
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;
self->change_tracker = alloc_change_tracker(lines, columns);
self->historybuf = alloc_historybuf(MAX(scrollback, lines), columns);
self->main_tabstops = PyMem_Calloc(2 * self->columns, sizeof(bool));
if (self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->change_tracker == NULL || self->main_tabstops == NULL || self->historybuf == NULL || self->color_profile == NULL) {
if (self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->main_tabstops == NULL || self->historybuf == NULL || self->color_profile == NULL) {
Py_CLEAR(self); return NULL;
}
self->alt_tabstops = self->main_tabstops + self->columns * sizeof(bool);
@ -94,12 +94,12 @@ screen_reset(Screen *self) {
init_tabstops(self->main_tabstops, self->columns);
init_tabstops(self->alt_tabstops, self->columns);
cursor_reset(self->cursor);
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
self->is_dirty = Py_True;
screen_cursor_position(self, 1, 1);
set_dynamic_color(self, 110, NULL);
set_dynamic_color(self, 111, NULL);
set_color_table_color(self, 104, NULL);
tracker_update_screen(self->change_tracker);
}
static inline HistoryBuf*
@ -150,7 +150,6 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
self->linebuf = is_main ? self->main_linebuf : self->alt_linebuf;
if (is_x_shrink && cursor_x >= columns) self->cursor->x = columns - 1;
if (!tracker_resize(self->change_tracker, lines, columns)) return false;
self->lines = lines; self->columns = columns;
self->margin_top = 0; self->margin_bottom = self->lines - 1;
@ -161,8 +160,7 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
self->tabstops = self->main_tabstops;
init_tabstops(self->main_tabstops, self->columns);
init_tabstops(self->alt_tabstops, self->columns);
tracker_update_screen(self->change_tracker);
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True; self->is_dirty = Py_True;
if (index_after_resize) screen_index(self);
return true;
@ -200,7 +198,6 @@ dealloc(Screen* self) {
Py_CLEAR(self->cursor);
Py_CLEAR(self->main_linebuf);
Py_CLEAR(self->alt_linebuf);
Py_CLEAR(self->change_tracker);
Py_CLEAR(self->historybuf);
Py_CLEAR(self->color_profile);
PyMem_Free(self->main_tabstops);
@ -268,7 +265,6 @@ screen_draw(Screen *self, uint32_t och) {
}
}
if (char_width > 0) {
unsigned int cx = self->cursor->x;
linebuf_init_line(self->linebuf, self->cursor->y);
if (self->modes.mIRM) {
line_right_shift(self->linebuf->line, self->cursor->x, char_width);
@ -279,20 +275,19 @@ screen_draw(Screen *self, uint32_t och) {
line_set_char(self->linebuf->line, self->cursor->x, 0, 0, self->cursor);
self->cursor->x++;
}
unsigned int right = self->modes.mIRM ? self->columns - 1 : MIN((MAX(self->cursor->x, 1) - 1), self->columns - 1);
tracker_update_cell_range(self->change_tracker, self->cursor->y, cx, right);
self->is_dirty = Py_True;
} else if (is_combining_char(ch)) {
if (self->cursor->x > 0) {
linebuf_init_line(self->linebuf, self->cursor->y);
line_add_combining_char(self->linebuf->line, ch, self->cursor->x - 1);
tracker_update_cell_range(self->change_tracker, self->cursor->y, self->cursor->x - 1, self->cursor->x - 1);
self->is_dirty = Py_True;
} else if (self->cursor->y > 0) {
linebuf_init_line(self->linebuf, self->cursor->y - 1);
line_add_combining_char(self->linebuf->line, ch, self->columns - 1);
tracker_update_cell_range(self->change_tracker, self->cursor->y - 1, self->columns - 1, self->columns - 1);
self->is_dirty = Py_True;
}
}
if (x != self->cursor->x || y != self->cursor->y) tracker_cursor_changed(self->change_tracker);
if (x != self->cursor->x || y != self->cursor->y) self->cursor_changed = Py_True;
}
void
@ -414,7 +409,7 @@ screen_toggle_screen_buffer(Screen *self) {
screen_restore_cursor(self);
}
CALLBACK("buf_toggled", "O", self->linebuf == self->main_linebuf ? Py_True : Py_False);
tracker_update_screen(self->change_tracker);
self->is_dirty = Py_True;
}
void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
@ -453,13 +448,13 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
break;
case DECTCEM:
self->modes.mDECTCEM = val;
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
break;
case DECSCNM:
// Render screen in reverse video
if (self->modes.mDECSCNM != val) {
self->modes.mDECSCNM = val;
tracker_update_screen(self->change_tracker);
self->is_dirty = Py_True;
}
break;
case DECOM:
@ -479,7 +474,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
break;
case CONTROL_CURSOR_BLINK:
self->cursor->blink = val;
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
break;
case ALTERNATE_SCREEN:
if (val && self->linebuf == self->main_linebuf) screen_toggle_screen_buffer(self);
@ -521,7 +516,7 @@ screen_tab(Screen *self) {
if (!found) found = self->columns - 1;
if (found != self->cursor->x) {
self->cursor->x = found;
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
}
}
@ -538,7 +533,7 @@ screen_backtab(Screen *self, unsigned int count) {
}
if (i <= 0) self->cursor->x = 0;
}
if (before != self->cursor->x) tracker_cursor_changed(self->change_tracker);
if (before != self->cursor->x) self->cursor_changed = Py_True;
}
void
@ -571,7 +566,7 @@ screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_direction/*=
if (move_direction < 0 && count > self->cursor->x) self->cursor->x = 0;
else self->cursor->x += move_direction * count;
screen_ensure_bounds(self, false);
if (x != self->cursor->x) tracker_cursor_changed(self->change_tracker);
if (x != self->cursor->x) self->cursor_changed = Py_True;
}
void
@ -587,7 +582,7 @@ screen_cursor_up(Screen *self, unsigned int count/*=1*/, bool do_carriage_return
else self->cursor->y += move_direction * count;
screen_ensure_bounds(self, true);
if (do_carriage_return) self->cursor->x = 0;
if (x != self->cursor->x || y != self->cursor->y) tracker_cursor_changed(self->change_tracker);
if (x != self->cursor->x || y != self->cursor->y) self->cursor_changed = Py_True;
}
void
@ -611,7 +606,7 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
if (x != self->cursor->x) {
self->cursor->x = x;
screen_ensure_bounds(self, false);
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
}
}
@ -621,11 +616,10 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
/* Only add to history when no page margins have been set */ \
linebuf_init_line(self->linebuf, bottom); \
historybuf_add_line(self->historybuf, self->linebuf->line); \
tracker_line_added_to_history(self->change_tracker); \
self->history_line_added_count++; \
} \
linebuf_clear_line(self->linebuf, bottom); \
if (bottom - top > self->lines - 1) tracker_update_screen(self->change_tracker); \
else tracker_update_line_range(self->change_tracker, top, bottom);
self->is_dirty = Py_True;
void
screen_index(Screen *self) {
@ -650,8 +644,7 @@ screen_scroll(Screen *self, unsigned int count) {
#define INDEX_DOWN \
linebuf_reverse_index(self->linebuf, top, bottom); \
linebuf_clear_line(self->linebuf, top); \
if (bottom - top > self->lines - 1) tracker_update_screen(self->change_tracker); \
else tracker_update_line_range(self->change_tracker, top, bottom);
self->is_dirty = Py_True;
void
screen_reverse_index(Screen *self) {
@ -678,7 +671,7 @@ void
screen_carriage_return(Screen *self) {
if (self->cursor->x != 0) {
self->cursor->x = 0;
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
}
}
@ -729,7 +722,7 @@ screen_restore_cursor(Screen *self) {
Savepoint *sp = savepoints_pop(pts);
if (sp == NULL) {
screen_cursor_position(self, 1, 1);
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
screen_reset_mode(self, DECOM);
RESET_CHARSETS;
screen_reset_mode(self, DECSCNM);
@ -766,7 +759,7 @@ screen_cursor_position(Screen *self, unsigned int line, unsigned int column) {
unsigned int x = self->cursor->x, y = self->cursor->y;
self->cursor->x = column; self->cursor->y = line;
screen_ensure_bounds(self, false);
if (x != self->cursor->x || y != self->cursor->y) tracker_cursor_changed(self->change_tracker);
if (x != self->cursor->x || y != self->cursor->y) self->cursor_changed = Py_True;
}
void
@ -813,7 +806,7 @@ void screen_erase_in_line(Screen *self, unsigned int how, bool private) {
} else {
line_apply_cursor(self->linebuf->line, self->cursor, s, n, true);
}
tracker_update_cell_range(self->change_tracker, self->cursor->y, s, MIN(s+n, self->columns) - 1);
self->is_dirty = Py_True;
}
}
@ -850,7 +843,7 @@ void screen_erase_in_display(Screen *self, unsigned int how, bool private) {
line_apply_cursor(self->linebuf->line, self->cursor, 0, self->columns, true);
}
}
tracker_update_line_range(self->change_tracker, a, b-1);
self->is_dirty = Py_True;
}
if (how != 2) {
screen_erase_in_line(self, how, private);
@ -862,7 +855,7 @@ void screen_insert_lines(Screen *self, unsigned int count) {
if (count == 0) count = 1;
if (top <= self->cursor->y && self->cursor->y <= bottom) {
linebuf_insert_lines(self->linebuf, count, self->cursor->y, bottom);
tracker_update_line_range(self->change_tracker, self->cursor->y, bottom);
self->is_dirty = Py_True;
screen_carriage_return(self);
}
}
@ -872,7 +865,7 @@ void screen_delete_lines(Screen *self, unsigned int count) {
if (count == 0) count = 1;
if (top <= self->cursor->y && self->cursor->y <= bottom) {
linebuf_delete_lines(self->linebuf, count, self->cursor->y, bottom);
tracker_update_line_range(self->change_tracker, self->cursor->y, bottom);
self->is_dirty = Py_True;
screen_carriage_return(self);
}
}
@ -886,7 +879,7 @@ void screen_insert_characters(Screen *self, unsigned int count) {
linebuf_init_line(self->linebuf, self->cursor->y);
line_right_shift(self->linebuf->line, x, num);
line_apply_cursor(self->linebuf->line, self->cursor, x, num, true);
tracker_update_cell_range(self->change_tracker, self->cursor->y, x, self->columns - 1);
self->is_dirty = Py_True;
}
}
@ -900,7 +893,7 @@ void screen_delete_characters(Screen *self, unsigned int count) {
linebuf_init_line(self->linebuf, self->cursor->y);
left_shift_line(self->linebuf->line, x, num);
line_apply_cursor(self->linebuf->line, self->cursor, self->columns - num, num, true);
tracker_update_cell_range(self->change_tracker, self->cursor->y, x, self->columns - 1);
self->is_dirty = Py_True;
}
}
@ -911,7 +904,7 @@ void screen_erase_characters(Screen *self, unsigned int count) {
unsigned int num = MIN(self->columns - x, count);
linebuf_init_line(self->linebuf, self->cursor->y);
line_apply_cursor(self->linebuf->line, self->cursor, x, num, true);
tracker_update_cell_range(self->change_tracker, self->cursor->y, x, MIN(x + num, self->columns) - 1);
self->is_dirty = Py_True;
}
// }}}
@ -1034,7 +1027,7 @@ screen_set_cursor(Screen *self, unsigned int mode, uint8_t secondary) {
}
if (shape != self->cursor->shape || blink != self->cursor->blink) {
self->cursor->shape = shape; self->cursor->blink = blink;
tracker_cursor_changed(self->change_tracker);
self->cursor_changed = Py_True;
}
break;
}
@ -1124,15 +1117,12 @@ set_mode(Screen *self, PyObject *args) {
static PyObject*
reset_dirty(Screen *self) {
tracker_reset(self->change_tracker);
self->is_dirty = Py_False;
self->cursor_changed = Py_False;
self->history_line_added_count = 0;
Py_RETURN_NONE;
}
static PyObject*
consolidate_changes(Screen *self) {
return tracker_consolidate_changes(self->change_tracker);
}
WRAP1E(cursor_back, 1, -1)
WRAP1B(erase_in_line, 0)
WRAP1B(erase_in_display, 0)
@ -1194,12 +1184,12 @@ screen_update_cell_data(Screen *self, PyObject *args) {
unsigned int *data;
int force_screen_refresh;
unsigned int scrolled_by;
unsigned int history_line_added_count = self->change_tracker->history_line_added_count;
unsigned int history_line_added_count = self->history_line_added_count;
if (!PyArg_ParseTuple(args, "O!Ip", &PyLong_Type, &dp, &scrolled_by, &force_screen_refresh)) return NULL;
data = PyLong_AsVoidPtr(dp);
PyObject *cursor_changed = self->change_tracker->cursor_changed ? Py_True : Py_False;
PyObject *cursor_changed = self->cursor_changed;
if (scrolled_by) scrolled_by = MIN(scrolled_by + history_line_added_count, self->historybuf->count);
tracker_reset(self->change_tracker);
reset_dirty(self);
for (index_type y = 0; y < MIN(self->lines, scrolled_by); y++) {
historybuf_init_line(self->historybuf, scrolled_by - 1 - y, self->historybuf->line);
self->historybuf->line->ynum = y;
@ -1227,14 +1217,9 @@ apply_selection(Screen *self, PyObject *args) {
Py_RETURN_NONE;
}
static PyObject* is_dirty(Screen *self) {
PyObject *ans = self->change_tracker->dirty ? Py_True : Py_False;
Py_INCREF(ans);
return ans;
}
static PyObject* mark_as_dirty(Screen *self) {
tracker_update_screen(self->change_tracker);
static
PyObject* mark_as_dirty(Screen *self) {
self->is_dirty = Py_True;
Py_RETURN_NONE;
}
@ -1286,7 +1271,6 @@ static PyMethodDef methods[] = {
MND(reset, METH_NOARGS)
MND(reset_dirty, METH_NOARGS)
MND(is_main_linebuf, METH_NOARGS)
MND(consolidate_changes, METH_NOARGS)
MND(cursor_back, METH_VARARGS)
MND(erase_in_line, METH_VARARGS)
MND(erase_in_display, METH_VARARGS)
@ -1313,7 +1297,6 @@ static PyMethodDef methods[] = {
MND(clear_tab_stop, METH_VARARGS)
MND(reverse_index, METH_NOARGS)
MND(refresh_sprite_positions, METH_NOARGS)
MND(is_dirty, METH_NOARGS)
MND(mark_as_dirty, METH_NOARGS)
MND(resize, METH_VARARGS)
MND(set_margins, METH_VARARGS)
@ -1346,6 +1329,8 @@ static PyGetSetDef getsetters[] = {
static PyMemberDef members[] = {
{"callbacks", T_OBJECT_EX, offsetof(Screen, callbacks), 0, "callbacks"},
{"cursor_changed", T_OBJECT_EX, offsetof(Screen, cursor_changed), 0, "cursor_changed"},
{"is_dirty", T_OBJECT_EX, offsetof(Screen, is_dirty), 0, "is_dirty"},
{"cursor", T_OBJECT_EX, offsetof(Screen, cursor), READONLY, "cursor"},
{"color_profile", T_OBJECT_EX, offsetof(Screen, color_profile), READONLY, "color_profile"},
{"linebuf", T_OBJECT_EX, offsetof(Screen, linebuf), READONLY, "linebuf"},
@ -1354,6 +1339,7 @@ static PyMemberDef members[] = {
{"columns", T_UINT, offsetof(Screen, columns), READONLY, "columns"},
{"margin_top", T_UINT, offsetof(Screen, margin_top), READONLY, "margin_top"},
{"margin_bottom", T_UINT, offsetof(Screen, margin_bottom), READONLY, "margin_bottom"},
{"history_line_added_count", T_UINT, offsetof(Screen, history_line_added_count), 0, "history_line_added_count"},
{NULL}
};

View File

@ -1,265 +0,0 @@
/*
* tracker.c
* Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "data-types.h"
#include "tracker.h"
bool tracker_resize(ChangeTracker *self, unsigned int ynum, unsigned int xnum) {
#define ALLOC_VAR(name, sz) \
bool *name = PyMem_Calloc(sz, sizeof(bool)); \
if (name == NULL) { PyErr_NoMemory(); return false; } \
PyMem_Free(self->name); self->name = name;
self->ynum = ynum; self->xnum = xnum;
ALLOC_VAR(changed_lines, self->ynum);
ALLOC_VAR(changed_cells, self->xnum * self->ynum);
ALLOC_VAR(lines_with_changed_cells, self->ynum);
RESET_STATE_VARS(self);
return true;
}
static PyObject*
resize(ChangeTracker *self, PyObject *args) {
#define resize_doc "Resize this change tracker must be called when the screen it is tracking for is resized"
unsigned int ynum=1, xnum=1;
if (!PyArg_ParseTuple(args, "|II", &ynum, &xnum)) return NULL;
if (!tracker_resize(self, ynum, xnum)) return NULL;
Py_RETURN_NONE;
}
static PyObject*
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
ChangeTracker *self;
self = (ChangeTracker *)type->tp_alloc(type, 0);
if (self != NULL) {
PyObject *ret = resize(self, args);
if (ret == NULL) { Py_CLEAR(self); return NULL; }
Py_CLEAR(ret);
}
return (PyObject*) self;
}
static void
dealloc(ChangeTracker* self) {
PyMem_Free(self->changed_lines); PyMem_Free(self->changed_cells); PyMem_Free(self->lines_with_changed_cells);
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject*
reset(ChangeTracker *self) {
#define reset_doc "Reset all changes"
tracker_reset(self);
Py_RETURN_NONE;
}
static PyObject*
cursor_changed(ChangeTracker *self) {
#define cursor_changed_doc ""
tracker_cursor_changed(self);
Py_RETURN_NONE;
}
static PyObject*
line_added_to_history(ChangeTracker *self) {
#define line_added_to_history_doc ""
tracker_line_added_to_history(self);
Py_RETURN_NONE;
}
static PyObject*
update_screen(ChangeTracker *self) {
#define update_screen_doc ""
tracker_update_screen(self);
Py_RETURN_NONE;
}
static PyObject*
update_line_range(ChangeTracker *self, PyObject *args) {
#define update_line_range_doc ""
unsigned int f, l;
if (!PyArg_ParseTuple(args, "II", &f, &l)) return NULL;
tracker_update_line_range(self, f, l);
Py_RETURN_NONE;
}
static PyObject*
update_cell_range(ChangeTracker *self, PyObject *args) {
#define update_cell_range_doc ""
unsigned int line, f, l;
if (!PyArg_ParseTuple(args, "III", &line, &f, &l)) return NULL;
tracker_update_cell_range(self, line, f, l);
Py_RETURN_NONE;
}
bool tracker_update_cell_data(ScreenModes *modes, ChangeTracker *self, LineBuf *lb, unsigned int *data, bool force_screen_refresh) {
unsigned int y;
Py_ssize_t start;
#define UPDATE_RANGE(xstart, xmax) \
linebuf_init_line(lb, y); \
if (!update_cell_range_data(modes, lb->line, (xstart), (xmax), data)) return false;
if (self->screen_changed || force_screen_refresh) {
for (y = 0; y < self->ynum; y++) {
UPDATE_RANGE(0, self->xnum - 1);
}
} else {
for (y = 0; y < self->ynum; y++) {
if (self->changed_lines[y]) {
UPDATE_RANGE(0, self->xnum - 1);
} else if (self->lines_with_changed_cells[y]) {
start = -1;
bool *line = self->changed_cells + y * self->xnum;
for (unsigned int i = 0; i < self->xnum; i++) {
if (line[i]) {
if (start == -1) {
start = i;
}
} else {
if (start != -1) {
UPDATE_RANGE(start, i - 1);
start = -1;
}
}
}
if (start != -1) {
UPDATE_RANGE(start, self->xnum - 1);
}
}
}
}
tracker_reset(self);
return true;
}
static inline PyObject*
get_ranges(bool *line, unsigned int xnum) {
PyObject *ans = PyList_New(0), *t;
Py_ssize_t start = -1;
if (ans == NULL) return PyErr_NoMemory();
#define APPEND_RANGE(x) \
t = Py_BuildValue("nI", start, x); \
if (t == NULL) { Py_CLEAR(ans); return NULL; } \
if (PyList_Append(ans, t) != 0) { Py_CLEAR(ans); Py_CLEAR(t); return NULL; } \
Py_CLEAR(t);
for (unsigned int i = 0; i < xnum; i++) {
if (line[i]) {
if (start == -1) {
start = i;
}
} else {
if (start != -1) {
APPEND_RANGE(i - 1);
start = -1;
}
}
}
if (start != -1) {
APPEND_RANGE(xnum - 1);
}
return ans;
}
PyObject*
tracker_consolidate_changes(ChangeTracker *self) {
PyObject *ans = PyDict_New();
if (ans == NULL) return PyErr_NoMemory();
if (PyDict_SetItemString(ans, "screen", self->screen_changed ? Py_True : Py_False) != 0) { Py_CLEAR(ans); return NULL; }
if (PyDict_SetItemString(ans, "cursor", self->cursor_changed ? Py_True : Py_False) != 0) { Py_CLEAR(ans); return NULL; }
PyObject *t = PyLong_FromUnsignedLong((unsigned long)self->history_line_added_count);
if (t == NULL) { Py_CLEAR(ans); return NULL; }
if (PyDict_SetItemString(ans, "history_line_added_count", t) != 0) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
Py_CLEAR(t);
// Changed lines
Py_ssize_t num = 0;
if (!self->screen_changed) {
for (unsigned int i = 0; i < self->ynum; i++) { num += self->changed_lines[i]; }
}
t = PyTuple_New(num);
if (t == NULL) { Py_CLEAR(ans); return NULL; }
if (num > 0) {
for (unsigned int i = 0, j=0; i < self->ynum; i++) {
if (self->changed_lines[i]) {
PyObject *n = PyLong_FromUnsignedLong(i);
if (n == NULL) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
PyTuple_SET_ITEM(t, j++, n);
}
}
}
if (PyDict_SetItemString(ans, "lines", t) != 0) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
Py_CLEAR(t);
// Changed cells
t = PyDict_New();
if (t == NULL) { Py_CLEAR(ans); return PyErr_NoMemory(); }
if (!self->screen_changed) {
for (unsigned int i = 0; i < self->ynum; i++) {
if (self->lines_with_changed_cells[i] && !self->changed_lines[i]) {
PyObject *ranges = get_ranges(self->changed_cells + i * self->xnum, self->xnum);
if (ranges == NULL) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
PyObject *key = PyLong_FromUnsignedLong(i);
if (key == NULL) { Py_CLEAR(t); Py_CLEAR(ans); Py_CLEAR(ranges); return NULL; }
if (PyDict_SetItem(t, key, ranges) != 0) { Py_CLEAR(key); Py_CLEAR(t); Py_CLEAR(ans); Py_CLEAR(ranges); return NULL; }
Py_CLEAR(key); Py_CLEAR(ranges);
}
}
}
if (PyDict_SetItemString(ans, "cells", t) != 0) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
Py_CLEAR(t);
tracker_reset(self);
return ans;
}
// Boilerplate {{{
BOOL_GETSET(ChangeTracker, dirty)
static PyGetSetDef getseters[] = {
GETSET(dirty)
{NULL} /* Sentinel */
};
static PyMethodDef methods[] = {
METHOD(resize, METH_VARARGS)
METHOD(reset, METH_NOARGS)
METHOD(cursor_changed, METH_NOARGS)
{"consolidate_changes", (PyCFunction)tracker_consolidate_changes, METH_NOARGS, ""},
METHOD(line_added_to_history, METH_NOARGS)
METHOD(update_screen, METH_NOARGS)
METHOD(update_line_range, METH_VARARGS)
METHOD(update_cell_range, METH_VARARGS)
{NULL} /* Sentinel */
};
PyTypeObject ChangeTracker_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "fast_data_types.ChangeTracker",
.tp_basicsize = sizeof(ChangeTracker),
.tp_dealloc = (destructor)dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "ChangeTracker",
.tp_methods = methods,
.tp_getset = getseters,
.tp_new = new,
};
INIT_TYPE(ChangeTracker)
// }}}
ChangeTracker* alloc_change_tracker(unsigned int ynum, unsigned int xnum) {
ChangeTracker *self = (ChangeTracker *)(&ChangeTracker_Type)->tp_alloc((&ChangeTracker_Type), 0);
if (!tracker_resize(self, ynum, xnum)) { Py_CLEAR(self); return NULL; }
return self;
}

View File

@ -1,55 +0,0 @@
/*
* tracker.h
* Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
static inline void tracker_cursor_changed(ChangeTracker *self) {
self->cursor_changed = true;
self->dirty = true;
}
static inline void tracker_line_added_to_history(ChangeTracker *self) {
self->history_line_added_count++;
self->dirty = true;
}
static inline void tracker_update_screen(ChangeTracker *self) {
self->screen_changed = true;
self->dirty = true;
}
static inline void tracker_update_line_range(ChangeTracker *self, unsigned int first_line, unsigned int last_line) {
if (!self->screen_changed) {
for (unsigned int i = first_line; i <= MIN(self->ynum - 1, last_line); i++) self->changed_lines[i] = true;
self->dirty = true;
}
}
static inline void tracker_update_cell_range(ChangeTracker *self, unsigned int line, unsigned int first_cell, unsigned int last_cell) {
if (!self->screen_changed && line < self->ynum && !self->changed_lines[line]) {
self->lines_with_changed_cells[line] = true;
unsigned int base = line * self->xnum;
for (unsigned int i = first_cell; i <= MIN(self->xnum - 1, last_cell); i++) self->changed_cells[base + i] = true;
self->dirty = true;
}
}
#define RESET_STATE_VARS(self) \
self->screen_changed = false; self->cursor_changed = false; self->dirty = false; self->history_line_added_count = 0;
static inline void tracker_reset(ChangeTracker *self) {
self->screen_changed = false; self->cursor_changed = false; self->dirty = false;
self->history_line_added_count = 0;
memset(self->changed_lines, 0, self->ynum * sizeof(bool));
memset(self->changed_cells, 0, self->ynum * self->xnum * sizeof(bool));
memset(self->lines_with_changed_cells, 0, self->ynum * sizeof(bool));
RESET_STATE_VARS(self);
}
PyObject* tracker_consolidate_changes(ChangeTracker *self);
bool tracker_resize(ChangeTracker *self, unsigned int ynum, unsigned int xnum);
bool tracker_update_cell_data(ScreenModes*, ChangeTracker *, LineBuf *, unsigned int *, bool);