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

View File

@ -48,15 +48,19 @@ dealloc(ChangeTracker* self) {
Py_TYPE(self)->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject* static inline void reset_inner(ChangeTracker *self) {
reset(ChangeTracker *self) {
#define reset_doc "Reset all changes"
self->screen_changed = false; self->cursor_changed = false; self->dirty = false; self->screen_changed = false; self->cursor_changed = false; self->dirty = false;
self->history_line_added_count = 0; self->history_line_added_count = 0;
memset(self->changed_lines, 0, self->ynum * sizeof(bool)); memset(self->changed_lines, 0, self->ynum * sizeof(bool));
memset(self->changed_cells, 0, self->ynum * self->xnum * sizeof(bool)); memset(self->changed_cells, 0, self->ynum * self->xnum * sizeof(bool));
memset(self->lines_with_changed_cells, 0, self->ynum * sizeof(bool)); memset(self->lines_with_changed_cells, 0, self->ynum * sizeof(bool));
RESET_STATE_VARS(self); RESET_STATE_VARS(self);
}
static PyObject*
reset(ChangeTracker *self) {
#define reset_doc "Reset all changes"
reset_inner(self);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -146,16 +150,16 @@ consolidate_changes(ChangeTracker *self) {
// Changed lines // Changed lines
Py_ssize_t num = 0; Py_ssize_t num = 0;
if (!self->screen_changed) { 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); t = PyTuple_New(num);
if (t == NULL) { Py_CLEAR(ans); return NULL; } if (t == NULL) { Py_CLEAR(ans); return NULL; }
if (!self->screen_changed) { if (num > 0) {
for (unsigned int i = 0, j=0; i < self->ynum; i++, j++) { for (unsigned int i = 0, j=0; i < self->ynum; i++) {
if (self->changed_lines[i]) { if (self->changed_lines[i]) {
PyObject *n = PyLong_FromUnsignedLong(i); PyObject *n = PyLong_FromUnsignedLong(i);
if (n == NULL) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; } 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; } if (PyDict_SetItemString(ans, "cells", t) != 0) { Py_CLEAR(t); Py_CLEAR(ans); return NULL; }
Py_CLEAR(t); Py_CLEAR(t);
reset_inner(self);
return ans; 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 # vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from collections import defaultdict
from unittest import TestCase from unittest import TestCase
from kitty.screen import Screen from kitty.screen import Screen
@ -49,9 +48,11 @@ class BaseTest(TestCase):
actual_changes = s.consolidate_changes() actual_changes = s.consolidate_changes()
ignore = frozenset(ignore.split()) ignore = frozenset(ignore.split())
for k, v in actual_changes.items(): for k, v in actual_changes.items():
if isinstance(v, defaultdict):
v = dict(v)
if k not in ignore: 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: if k in expected_changes:
self.ae(expected_changes[k], v) self.ae(expected_changes[k], v)
else: else: