Use the native tracker implementation
This commit is contained in:
parent
2b362108b8
commit
d2a27d9892
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user