Use HistoryBuf (still need to implement rewrap)

This commit is contained in:
Kovid Goyal 2016-11-20 20:20:14 +05:30
parent 222911874d
commit 0b0a216856
5 changed files with 66 additions and 51 deletions

View File

@ -254,6 +254,7 @@ typedef struct {
SavepointBuffer main_savepoints, alt_savepoints;
PyObject *callbacks;
LineBuf *linebuf, *main_linebuf, *alt_linebuf;
HistoryBuf *historybuf;
bool *tabstops;
ChangeTracker *change_tracker;
ScreenModes modes;
@ -317,7 +318,9 @@ void linebuf_clear_line(LineBuf *self, index_type y);
void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom);
void linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int );
bool linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, PyObject *extra_lines);
void linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *);
bool historybuf_resize(HistoryBuf *self, index_type lines);
void historybuf_add_line(HistoryBuf *self, const Line *line);
void screen_restore_cursor(Screen *);
void screen_save_cursor(Screen *);

View File

@ -41,9 +41,9 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
}
static void
dealloc(LineBuf* self) {
PyMem_Free(self->buf);
dealloc(HistoryBuf* self) {
Py_CLEAR(self->line);
PyMem_Free(self->buf);
Py_TYPE(self)->tp_free((PyObject*)self);
}
@ -55,7 +55,7 @@ static inline index_type index_of(HistoryBuf *self, index_type lnum) {
return (self->start_of_data + idx) % self->ynum;
}
static inline void* start_of(HistoryBuf *self, index_type num) {
static inline uint8_t* start_of(HistoryBuf *self, index_type num) {
// Pointer to the start of the line with index (buffer position) num
return self->buf + CELL_SIZE_H * num * self->xnum;
}
@ -70,25 +70,26 @@ static inline void init_line(HistoryBuf *self, index_type num, Line *l) {
l->combining_chars = (combining_type*)(l->decoration_fg + self->xnum);
}
static inline void historybuf_push(HistoryBuf *self) {
init_line(self, (self->start_of_data + self->count) % self->ynum, self->line);
static inline index_type historybuf_push(HistoryBuf *self) {
index_type idx = (self->start_of_data + self->count) % self->ynum;
init_line(self, idx, self->line);
if (self->count == self->ynum) self->start_of_data = (self->start_of_data + 1) % self->ynum;
else self->count++;
return idx;
}
static PyObject*
change_num_of_lines(HistoryBuf *self, PyObject *val) {
#define change_num_of_lines_doc "Change the number of lines in this buffer"
bool
historybuf_resize(HistoryBuf *self, index_type lines) {
HistoryBuf t = {0};
t.xnum=self->xnum;
t.ynum=(index_type) PyLong_AsUnsignedLong(val);
t.ynum=lines;
if (t.ynum > 0 && t.ynum != self->ynum) {
t.buf = PyMem_Calloc(t.xnum * t.ynum, CELL_SIZE_H);
if (t.buf == NULL) return PyErr_NoMemory();
if (t.buf == NULL) { PyErr_NoMemory(); return false; }
t.count = MIN(self->count, t.ynum);
if (t.count > 0) {
for (index_type s=0; s < t.count; s++) {
void *src = start_of(self, index_of(self, s)), *dest = start_of(&t, index_of(&t, s));
uint8_t *src = start_of(self, index_of(self, s)), *dest = start_of(&t, index_of(&t, s));
memcpy(dest, src, CELL_SIZE_H * t.xnum);
}
}
@ -98,6 +99,19 @@ change_num_of_lines(HistoryBuf *self, PyObject *val) {
PyMem_Free(self->buf);
self->buf = t.buf;
}
return true;
}
void historybuf_add_line(HistoryBuf *self, const Line *line) {
index_type idx = historybuf_push(self);
COPY_LINE(line, self->line);
*(start_of(self, idx)) = line->continued;
}
static PyObject*
change_num_of_lines(HistoryBuf *self, PyObject *val) {
#define change_num_of_lines_doc "Change the number of lines in this buffer"
if(!historybuf_resize(self, (index_type)PyLong_AsUnsignedLong(val))) return NULL;
Py_RETURN_NONE;
}

View File

@ -345,7 +345,7 @@ copy_old(LineBuf *self, PyObject *y);
#define copy_old_doc "Copy the contents of the specified LineBuf to this LineBuf. Both must have the same number of columns, but the number of lines can be different, in which case the bottom lines are copied."
static PyObject*
rewrap(LineBuf *self, PyObject *val);
rewrap(LineBuf *self, PyObject *args);
#define rewrap_doc "rewrap(new_screen) -> Fill up new screen (which can have different size to this screen) with as much of the contents of this screen as will fit. Return lines that overflow."
static PyMethodDef methods[] = {
@ -354,7 +354,7 @@ static PyMethodDef methods[] = {
METHOD(copy_old, METH_O)
METHOD(copy_line_to, METH_VARARGS)
METHOD(create_line_copy, METH_O)
METHOD(rewrap, METH_O)
METHOD(rewrap, METH_VARARGS)
METHOD(clear, METH_NOARGS)
METHOD(set_attribute, METH_VARARGS)
METHOD(set_continued, METH_VARARGS)
@ -415,11 +415,9 @@ static inline void copy_range(Line *src, index_type src_at, Line* dest, index_ty
#define next_dest_line(continued) {\
if (dest_y >= dest->ynum - 1) { \
linebuf_index(dest, 0, dest->ynum - 1); \
if (extra_lines != NULL) {\
PyObject *l = create_line_copy_inner(dest, dest_y); \
if (l == NULL) return false; \
if (PyList_Append(extra_lines, l) != 0) { Py_CLEAR(l); return false; } \
Py_CLEAR(l); \
if (historybuf != NULL) { \
linebuf_init_line(dest, dest->ynum - 1); \
historybuf_add_line(historybuf, dest->line); \
}\
} else dest_y++; \
INIT_LINE(dest, dest->line, dest->line_map[dest_y]); \
@ -427,7 +425,7 @@ static inline void copy_range(Line *src, index_type src_at, Line* dest, index_ty
dest_x = 0; \
}
static bool rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, PyObject *extra_lines) {
static void rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, HistoryBuf *historybuf) {
// TODO: Change this to put the extra lines into the history buf
bool src_line_is_continued = false;
index_type src_y = 0, src_x = 0, dest_x = 0, dest_y = 0, num = 0, src_x_limit = 0;
@ -452,10 +450,9 @@ static bool rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit
if (!src_line_is_continued && src_y < src_limit) next_dest_line(false);
} while (src_y < src_limit);
dest->line->ynum = dest_y;
return true;
}
bool linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, PyObject *extra_lines) {
void linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *historybuf) {
index_type first, i;
bool is_empty = true;
@ -466,7 +463,7 @@ bool linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, PyObject *
memcpy(other->continued_map, self->continued_map, sizeof(bool) * self->ynum);
memcpy(other->buf, self->buf, self->xnum * self->ynum * CELL_SIZE);
Py_END_ALLOW_THREADS;
return true;
return;
}
// Find the first line that contains some content
@ -480,28 +477,22 @@ bool linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, PyObject *
}
Py_END_ALLOW_THREADS;
if (first == 0) { *cursor_y_out = 0; return true; } // All lines are empty
if (first == 0) { *cursor_y_out = 0; return; } // All lines are empty
if (!rewrap_inner(self, other, first + 1, extra_lines)) {
PyErr_NoMemory();
return false;
}
rewrap_inner(self, other, first + 1, historybuf);
*cursor_y_out = other->line->ynum;
return true;
}
static PyObject*
rewrap(LineBuf *self, PyObject *val) {
rewrap(LineBuf *self, PyObject *args) {
LineBuf* other;
HistoryBuf *historybuf;
int cursor_y = -1;
if (!PyObject_TypeCheck(val, &LineBuf_Type)) { PyErr_SetString(PyExc_TypeError, "Not a LineBuf object"); return NULL; }
other = (LineBuf*) val;
PyObject *ret = PyList_New(0);
if (ret == NULL) return PyErr_NoMemory();
if(!linebuf_rewrap(self, other, &cursor_y, ret)) return NULL;
if (!PyArg_ParseTuple(args, "O!O!", &LineBuf_Type, &other, &HistoryBuf_Type, &historybuf)) return NULL;
linebuf_rewrap(self, other, &cursor_y, historybuf);
return Py_BuildValue("Ni", ret, cursor_y);
return Py_BuildValue("i", cursor_y);
}
LineBuf *alloc_linebuf(unsigned int lines, unsigned int columns) {

View File

@ -35,8 +35,9 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
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(lines, columns);
self->tabstops = PyMem_Calloc(self->columns, sizeof(bool));
if (self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->change_tracker == NULL || self->tabstops == NULL) {
if (self->cursor == NULL || self->main_linebuf == NULL || self->alt_linebuf == NULL || self->change_tracker == NULL || self->tabstops == NULL || self->historybuf == NULL) {
Py_CLEAR(self); return NULL;
}
}
@ -63,10 +64,10 @@ void screen_reset(Screen *self) {
tracker_update_screen(self->change_tracker);
}
static inline LineBuf* realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, int *cursor_y) {
static inline LineBuf* realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, int *cursor_y, HistoryBuf *hb) {
LineBuf *ans = alloc_linebuf(lines, columns);
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
if(!linebuf_rewrap(old, ans, cursor_y, NULL)) return NULL;
linebuf_rewrap(old, ans, cursor_y, hb);
return ans;
}
@ -75,12 +76,12 @@ static bool screen_resize(Screen *self, unsigned int lines, unsigned int columns
bool is_main = self->linebuf == self->main_linebuf;
int cursor_y = -1;
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &cursor_y);
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &cursor_y, self->historybuf);
if (n == NULL) return false;
Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
if (is_main) self->cursor->y = MAX(0, cursor_y);
cursor_y = -1;
n = realloc_lb(self->alt_linebuf, lines, columns, &cursor_y);
n = realloc_lb(self->alt_linebuf, lines, columns, &cursor_y, NULL);
if (n == NULL) return false;
Py_CLEAR(self->alt_linebuf); self->alt_linebuf = n;
if (!is_main) self->cursor->y = MAX(0, cursor_y);
@ -99,9 +100,8 @@ static bool screen_resize(Screen *self, unsigned int lines, unsigned int columns
return true;
}
static bool screen_change_scrollback_size(Screen UNUSED *self, unsigned int UNUSED size) {
// TODO: Implement this
return true;
static bool screen_change_scrollback_size(Screen *self, unsigned int size) {
return historybuf_resize(self->historybuf, size);
}
@ -524,8 +524,10 @@ void screen_index(Screen *self) {
unsigned int top = self->margin_top, bottom = self->margin_bottom;
if (self->cursor->y == bottom) {
linebuf_index(self->linebuf, top, bottom);
if (self->linebuf == self->main_linebuf) {
// TODO: Add line to tophistorybuf
if (self->linebuf == self->main_linebuf && bottom == self->lines - 1) {
// 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);
}
linebuf_clear_line(self->linebuf, bottom);

View File

@ -8,7 +8,7 @@
from kitty.config import build_ansi_color_table, defaults
from kitty.utils import is_simple_string, wcwidth, sanitize_title
from kitty.fast_data_types import LineBuf, Cursor as C, REVERSE, ColorProfile, SpriteMap
from kitty.fast_data_types import LineBuf, Cursor as C, REVERSE, ColorProfile, SpriteMap, HistoryBuf
def create_lbuf(*lines):
@ -210,15 +210,20 @@ def test_line(self):
l.set_char(0, 'x', 1, q)
self.assertEqualAttributes(l.cursor_from(0), q)
def rewrap(self, lb, lb2):
hb = HistoryBuf(lb2.ynum, lb2.xnum)
cy = lb.rewrap(lb2, hb)
return hb, cy
def test_rewrap_simple(self):
' Same width buffers '
lb = filled_line_buf(5, 5)
lb2 = LineBuf(lb.ynum, lb.xnum)
lb.rewrap(lb2)
self.rewrap(lb, lb2)
for i in range(lb.ynum):
self.ae(lb2.line(i), lb.line(i))
lb2 = LineBuf(8, 5)
cy = lb.rewrap(lb2)[1]
cy = self.rewrap(lb, lb2)[1]
self.ae(cy, 4)
for i in range(lb.ynum):
self.ae(lb2.line(i), lb.line(i))
@ -226,14 +231,14 @@ def test_rewrap_simple(self):
for i in range(lb.ynum, lb2.ynum):
self.ae(str(lb2.line(i)), str(empty.line(0)))
lb2 = LineBuf(3, 5)
extra, cy = lb.rewrap(lb2)
cy = self.rewrap(lb, lb2)[1]
self.ae(cy, 2)
for i in range(lb2.ynum):
self.ae(lb2.line(i), lb.line(i + 2))
def line_comparison(self, lb, *lines):
lb2 = LineBuf(len(lines), max(map(len, lines)))
lb.rewrap(lb2)
self.rewrap(lb, lb2)
for i, l in enumerate(lines):
l2 = lb2.line(i)
self.ae(l, str(l2))