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; SavepointBuffer main_savepoints, alt_savepoints;
PyObject *callbacks; PyObject *callbacks;
LineBuf *linebuf, *main_linebuf, *alt_linebuf; LineBuf *linebuf, *main_linebuf, *alt_linebuf;
HistoryBuf *historybuf;
bool *tabstops; bool *tabstops;
ChangeTracker *change_tracker; ChangeTracker *change_tracker;
ScreenModes modes; 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_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_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int ); 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_restore_cursor(Screen *);
void screen_save_cursor(Screen *); void screen_save_cursor(Screen *);

View File

@ -41,9 +41,9 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
} }
static void static void
dealloc(LineBuf* self) { dealloc(HistoryBuf* self) {
PyMem_Free(self->buf);
Py_CLEAR(self->line); Py_CLEAR(self->line);
PyMem_Free(self->buf);
Py_TYPE(self)->tp_free((PyObject*)self); 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; 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 // Pointer to the start of the line with index (buffer position) num
return self->buf + CELL_SIZE_H * num * self->xnum; 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); l->combining_chars = (combining_type*)(l->decoration_fg + self->xnum);
} }
static inline void historybuf_push(HistoryBuf *self) { static inline index_type historybuf_push(HistoryBuf *self) {
init_line(self, (self->start_of_data + self->count) % self->ynum, self->line); 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; if (self->count == self->ynum) self->start_of_data = (self->start_of_data + 1) % self->ynum;
else self->count++; else self->count++;
return idx;
} }
static PyObject* bool
change_num_of_lines(HistoryBuf *self, PyObject *val) { historybuf_resize(HistoryBuf *self, index_type lines) {
#define change_num_of_lines_doc "Change the number of lines in this buffer"
HistoryBuf t = {0}; HistoryBuf t = {0};
t.xnum=self->xnum; t.xnum=self->xnum;
t.ynum=(index_type) PyLong_AsUnsignedLong(val); t.ynum=lines;
if (t.ynum > 0 && t.ynum != self->ynum) { if (t.ynum > 0 && t.ynum != self->ynum) {
t.buf = PyMem_Calloc(t.xnum * t.ynum, CELL_SIZE_H); 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); t.count = MIN(self->count, t.ynum);
if (t.count > 0) { if (t.count > 0) {
for (index_type s=0; s < t.count; s++) { 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); memcpy(dest, src, CELL_SIZE_H * t.xnum);
} }
} }
@ -98,6 +99,19 @@ change_num_of_lines(HistoryBuf *self, PyObject *val) {
PyMem_Free(self->buf); PyMem_Free(self->buf);
self->buf = t.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; 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." #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* 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." #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[] = { static PyMethodDef methods[] = {
@ -354,7 +354,7 @@ static PyMethodDef methods[] = {
METHOD(copy_old, METH_O) METHOD(copy_old, METH_O)
METHOD(copy_line_to, METH_VARARGS) METHOD(copy_line_to, METH_VARARGS)
METHOD(create_line_copy, METH_O) METHOD(create_line_copy, METH_O)
METHOD(rewrap, METH_O) METHOD(rewrap, METH_VARARGS)
METHOD(clear, METH_NOARGS) METHOD(clear, METH_NOARGS)
METHOD(set_attribute, METH_VARARGS) METHOD(set_attribute, METH_VARARGS)
METHOD(set_continued, 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) {\ #define next_dest_line(continued) {\
if (dest_y >= dest->ynum - 1) { \ if (dest_y >= dest->ynum - 1) { \
linebuf_index(dest, 0, dest->ynum - 1); \ linebuf_index(dest, 0, dest->ynum - 1); \
if (extra_lines != NULL) {\ if (historybuf != NULL) { \
PyObject *l = create_line_copy_inner(dest, dest_y); \ linebuf_init_line(dest, dest->ynum - 1); \
if (l == NULL) return false; \ historybuf_add_line(historybuf, dest->line); \
if (PyList_Append(extra_lines, l) != 0) { Py_CLEAR(l); return false; } \
Py_CLEAR(l); \
}\ }\
} else dest_y++; \ } else dest_y++; \
INIT_LINE(dest, dest->line, dest->line_map[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; \ 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 // TODO: Change this to put the extra lines into the history buf
bool src_line_is_continued = false; 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; 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); if (!src_line_is_continued && src_y < src_limit) next_dest_line(false);
} while (src_y < src_limit); } while (src_y < src_limit);
dest->line->ynum = dest_y; 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; index_type first, i;
bool is_empty = true; 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->continued_map, self->continued_map, sizeof(bool) * self->ynum);
memcpy(other->buf, self->buf, self->xnum * self->ynum * CELL_SIZE); memcpy(other->buf, self->buf, self->xnum * self->ynum * CELL_SIZE);
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
return true; return;
} }
// Find the first line that contains some content // 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; 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)) { rewrap_inner(self, other, first + 1, historybuf);
PyErr_NoMemory();
return false;
}
*cursor_y_out = other->line->ynum; *cursor_y_out = other->line->ynum;
return true;
} }
static PyObject* static PyObject*
rewrap(LineBuf *self, PyObject *val) { rewrap(LineBuf *self, PyObject *args) {
LineBuf* other; LineBuf* other;
HistoryBuf *historybuf;
int cursor_y = -1; int cursor_y = -1;
if (!PyObject_TypeCheck(val, &LineBuf_Type)) { PyErr_SetString(PyExc_TypeError, "Not a LineBuf object"); return NULL; } if (!PyArg_ParseTuple(args, "O!O!", &LineBuf_Type, &other, &HistoryBuf_Type, &historybuf)) return NULL;
other = (LineBuf*) val; linebuf_rewrap(self, other, &cursor_y, historybuf);
PyObject *ret = PyList_New(0);
if (ret == NULL) return PyErr_NoMemory();
if(!linebuf_rewrap(self, other, &cursor_y, ret)) return NULL;
return Py_BuildValue("Ni", ret, cursor_y); return Py_BuildValue("i", cursor_y);
} }
LineBuf *alloc_linebuf(unsigned int lines, unsigned int columns) { 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->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns);
self->linebuf = self->main_linebuf; self->linebuf = self->main_linebuf;
self->change_tracker = alloc_change_tracker(lines, columns); self->change_tracker = alloc_change_tracker(lines, columns);
self->historybuf = alloc_historybuf(lines, columns);
self->tabstops = PyMem_Calloc(self->columns, sizeof(bool)); 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; Py_CLEAR(self); return NULL;
} }
} }
@ -63,10 +64,10 @@ void screen_reset(Screen *self) {
tracker_update_screen(self->change_tracker); 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); LineBuf *ans = alloc_linebuf(lines, columns);
if (ans == NULL) { PyErr_NoMemory(); return NULL; } 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; 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; bool is_main = self->linebuf == self->main_linebuf;
int cursor_y = -1; 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; if (n == NULL) return false;
Py_CLEAR(self->main_linebuf); self->main_linebuf = n; Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
if (is_main) self->cursor->y = MAX(0, cursor_y); if (is_main) self->cursor->y = MAX(0, cursor_y);
cursor_y = -1; 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; if (n == NULL) return false;
Py_CLEAR(self->alt_linebuf); self->alt_linebuf = n; Py_CLEAR(self->alt_linebuf); self->alt_linebuf = n;
if (!is_main) self->cursor->y = MAX(0, cursor_y); 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; return true;
} }
static bool screen_change_scrollback_size(Screen UNUSED *self, unsigned int UNUSED size) { static bool screen_change_scrollback_size(Screen *self, unsigned int size) {
// TODO: Implement this return historybuf_resize(self->historybuf, size);
return true;
} }
@ -524,8 +524,10 @@ void screen_index(Screen *self) {
unsigned int top = self->margin_top, bottom = self->margin_bottom; unsigned int top = self->margin_top, bottom = self->margin_bottom;
if (self->cursor->y == bottom) { if (self->cursor->y == bottom) {
linebuf_index(self->linebuf, top, bottom); linebuf_index(self->linebuf, top, bottom);
if (self->linebuf == self->main_linebuf) { if (self->linebuf == self->main_linebuf && bottom == self->lines - 1) {
// TODO: Add line to tophistorybuf // 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); tracker_line_added_to_history(self->change_tracker);
} }
linebuf_clear_line(self->linebuf, bottom); linebuf_clear_line(self->linebuf, bottom);

View File

@ -8,7 +8,7 @@
from kitty.config import build_ansi_color_table, defaults from kitty.config import build_ansi_color_table, defaults
from kitty.utils import is_simple_string, wcwidth, sanitize_title 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): def create_lbuf(*lines):
@ -210,15 +210,20 @@ def test_line(self):
l.set_char(0, 'x', 1, q) l.set_char(0, 'x', 1, q)
self.assertEqualAttributes(l.cursor_from(0), 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): def test_rewrap_simple(self):
' Same width buffers ' ' Same width buffers '
lb = filled_line_buf(5, 5) lb = filled_line_buf(5, 5)
lb2 = LineBuf(lb.ynum, lb.xnum) lb2 = LineBuf(lb.ynum, lb.xnum)
lb.rewrap(lb2) self.rewrap(lb, lb2)
for i in range(lb.ynum): for i in range(lb.ynum):
self.ae(lb2.line(i), lb.line(i)) self.ae(lb2.line(i), lb.line(i))
lb2 = LineBuf(8, 5) lb2 = LineBuf(8, 5)
cy = lb.rewrap(lb2)[1] cy = self.rewrap(lb, lb2)[1]
self.ae(cy, 4) self.ae(cy, 4)
for i in range(lb.ynum): for i in range(lb.ynum):
self.ae(lb2.line(i), lb.line(i)) 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): for i in range(lb.ynum, lb2.ynum):
self.ae(str(lb2.line(i)), str(empty.line(0))) self.ae(str(lb2.line(i)), str(empty.line(0)))
lb2 = LineBuf(3, 5) lb2 = LineBuf(3, 5)
extra, cy = lb.rewrap(lb2) cy = self.rewrap(lb, lb2)[1]
self.ae(cy, 2) self.ae(cy, 2)
for i in range(lb2.ynum): for i in range(lb2.ynum):
self.ae(lb2.line(i), lb.line(i + 2)) self.ae(lb2.line(i), lb.line(i + 2))
def line_comparison(self, lb, *lines): def line_comparison(self, lb, *lines):
lb2 = LineBuf(len(lines), max(map(len, lines))) lb2 = LineBuf(len(lines), max(map(len, lines)))
lb.rewrap(lb2) self.rewrap(lb, lb2)
for i, l in enumerate(lines): for i, l in enumerate(lines):
l2 = lb2.line(i) l2 = lb2.line(i)
self.ae(l, str(l2)) self.ae(l, str(l2))