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 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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
# 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:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user