Use the native tracker implementation

This commit is contained in:
Kovid Goyal 2016-11-12 08:29:48 +05:30
parent 2b362108b8
commit d2a27d9892
4 changed files with 19 additions and 82 deletions

View File

@ -11,8 +11,7 @@ from typing import Sequence
from pyte import charsets as cs, graphics as g, modes as mo
from .utils import wcwidth, is_simple_string, sanitize_title
from .unicode import ignore_pat
from .tracker import ChangeTracker
from .fast_data_types import LineBuf, REVERSE, Cursor
from .fast_data_types import LineBuf, REVERSE, Cursor, ChangeTracker
#: A container for screen's scroll margins.
@ -63,7 +62,7 @@ class Screen:
self.savepoints = self.main_savepoints
self.columns = columns
self.lines = lines
self.tracker = ChangeTracker()
self.tracker = ChangeTracker(self.lines, self.columns)
for attr in self.tracker_callbacks:
setattr(self, attr, getattr(self.tracker, attr))
self.consolidate_changes = self.tracker.consolidate_changes
@ -159,6 +158,7 @@ class Screen:
"""
self.lines, self.columns = lines, columns
self.tracker.resize(self.lines, self.columns)
# TODO: Implement rewrap for history buf
self.tophistorybuf.clear()
is_main = self.linebuf is self.main_linebuf

View File

@ -48,15 +48,19 @@ dealloc(ChangeTracker* self) {
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject*
reset(ChangeTracker *self) {
#define reset_doc "Reset all changes"
static inline void reset_inner(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);
}
static PyObject*
reset(ChangeTracker *self) {
#define reset_doc "Reset all changes"
reset_inner(self);
Py_RETURN_NONE;
}
@ -146,16 +150,16 @@ consolidate_changes(ChangeTracker *self) {
// Changed lines
Py_ssize_t num = 0;
if (!self->screen_changed) {
for (unsigned int i = 0; i < self->ynum; i++) { if (self->changed_lines[i]) num++; }
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 (!self->screen_changed) {
for (unsigned int i = 0, j=0; i < self->ynum; i++, j++) {
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);
PyTuple_SET_ITEM(t, j++, n);
}
}
}
@ -181,7 +185,7 @@ consolidate_changes(ChangeTracker *self) {
if (PyDict_SetItemString(ans, "cells", t) != 0) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
Py_CLEAR(t);
reset_inner(self);
return ans;
}

View File

@ -1,68 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from collections import defaultdict
from operator import itemgetter
from typing import Set, Tuple, Iterator
def merge_ranges(ranges: Set[Tuple[int]]) -> Iterator[Tuple[int]]:
if ranges:
sorted_intervals = sorted(ranges, key=itemgetter(0))
# low and high represent the bounds of the current run of merges
low, high = sorted_intervals[0]
for iv in sorted_intervals[1:]:
if iv[0] <= high + 1: # new interval overlaps current run or borders it
high = max(high, iv[1]) # merge with the current run
else: # current run is over
yield low, high # yield accumulated interval
low, high = iv # start new run
yield low, high # end the final run
class ChangeTracker:
def __init__(self):
self.reset()
def reset(self):
self.dirty = False
self.changed_cursor = False
self.changed_cells = defaultdict(set)
self.changed_lines = set()
self.screen_changed = False
self.history_line_added_count = 0
def cursor_changed(self) -> None:
self.changed_cursor = True
self.dirty = True
def update_screen(self):
self.screen_changed = True
self.dirty = True
def update_line_range(self, first_line, last_line):
self.changed_lines |= set(range(first_line, last_line + 1))
self.dirty = True
def update_cell_range(self, y, first_cell, last_cell):
self.changed_cells[y].add((first_cell, last_cell))
self.dirty = True
def line_added_to_history(self):
self.history_line_added_count += 1
self.dirty = True
def consolidate_changes(self):
if self.screen_changed:
self.changed_lines.clear()
cc = {}
else:
cc = {y: tuple(merge_ranges(cell_ranges)) for y, cell_ranges in self.changed_cells.items() if y not in self.changed_lines}
changes = {'screen': self.screen_changed, 'cursor': self.changed_cursor, 'lines': self.changed_lines,
'cells': cc, 'history_line_added_count': self.history_line_added_count}
self.reset()
return changes

View File

@ -2,7 +2,6 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from collections import defaultdict
from unittest import TestCase
from kitty.screen import Screen
@ -49,9 +48,11 @@ class BaseTest(TestCase):
actual_changes = s.consolidate_changes()
ignore = frozenset(ignore.split())
for k, v in actual_changes.items():
if isinstance(v, defaultdict):
v = dict(v)
if k not in ignore:
if isinstance(v, dict):
v = {ky: tuple(vy) for ky, vy in v.items()}
if k == 'lines':
v = set(v)
if k in expected_changes:
self.ae(expected_changes[k], v)
else: