Implement pager scrollback history buffer
For now, use big fixed-size buffer that is lost on resize
This commit is contained in:
parent
a4c2a9ef0d
commit
d0104660c8
@ -173,11 +173,19 @@ typedef struct {
|
||||
line_attrs_type *line_attrs;
|
||||
} HistoryBufSegment;
|
||||
|
||||
typedef struct {
|
||||
index_type bufsize;
|
||||
Py_UCS4 *buffer;
|
||||
index_type start, end;
|
||||
index_type bufend;
|
||||
} PagerHistoryBuf;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
index_type xnum, ynum, num_segments;
|
||||
HistoryBufSegment* segments;
|
||||
HistoryBufSegment *segments;
|
||||
PagerHistoryBuf pagerhist;
|
||||
Line *line;
|
||||
index_type start_of_data, count;
|
||||
} HistoryBuf;
|
||||
|
||||
@ -74,6 +74,10 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
add_segment(self);
|
||||
self->line = alloc_line();
|
||||
self->line->xnum = xnum;
|
||||
self->pagerhist.start = self->pagerhist.end = self->pagerhist.bufend = 0;
|
||||
self->pagerhist.buffer = PyMem_RawMalloc(1024*1024*10);
|
||||
self->pagerhist.bufsize = 1024*1024*10 / sizeof(Py_UCS4);
|
||||
// abort if allocation failed?
|
||||
}
|
||||
|
||||
return (PyObject*)self;
|
||||
@ -88,6 +92,7 @@ dealloc(HistoryBuf* self) {
|
||||
PyMem_Free(self->segments[i].line_attrs);
|
||||
}
|
||||
PyMem_Free(self->segments);
|
||||
PyMem_Free(self->pagerhist.buffer);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
@ -132,12 +137,37 @@ historybuf_clear(HistoryBuf *self) {
|
||||
self->start_of_data = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pagerhist_push(HistoryBuf *self) {
|
||||
PagerHistoryBuf *ph = &self->pagerhist;
|
||||
if (!ph->buffer) return;
|
||||
Line l = {.xnum=self->xnum};
|
||||
init_line(self, self->start_of_data, &l);
|
||||
if (ph->start != ph->end && !l.continued) {
|
||||
ph->buffer[ph->end++] = '\n';
|
||||
}
|
||||
if (ph->bufsize - ph->end < 1024) { ph->bufend = ph->end; ph->end = 0; }
|
||||
ph->end += line_as_ansi(&l, ph->buffer + ph->end, 1024);
|
||||
if (ph->bufend) {
|
||||
#if NEXTLINE
|
||||
/* something like wcsrchr would be more accurate, but is *slow* */
|
||||
Py_UCS4 *newstart = (Py_UCS4 *)strchr((char *)ph->buffer + ph->end, '\n');
|
||||
if (!newstart || newstart - ph->buffer > ph->bufend) ph->start = 0;
|
||||
else ph->start = newstart - ph->buffer;
|
||||
#else
|
||||
ph->start = ph->end + 1 < ph->bufend ? ph->end + 1 : 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
if (self->count == self->ynum) {
|
||||
pagerhist_push(self);
|
||||
self->start_of_data = (self->start_of_data + 1) % self->ynum;
|
||||
} else self->count++;
|
||||
return idx;
|
||||
}
|
||||
|
||||
@ -209,6 +239,48 @@ as_ansi(HistoryBuf *self, PyObject *callback) {
|
||||
static inline Line*
|
||||
get_line(HistoryBuf *self, index_type y, Line *l) { init_line(self, index_of(self, self->count - y - 1), l); return l; }
|
||||
|
||||
static PyObject *
|
||||
pagerhist_as_text(HistoryBuf *self, PyObject *callback) {
|
||||
PagerHistoryBuf *ph = &self->pagerhist;
|
||||
PyObject *ret = NULL, *t = NULL;
|
||||
Py_UCS4 *buf = NULL;
|
||||
if (!ph->buffer) Py_RETURN_NONE;
|
||||
|
||||
index_type num = (ph->bufend ? ph->bufend : ph->end) - ph->start;
|
||||
buf = ph->buffer + ph->start;
|
||||
t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, num);
|
||||
if (t == NULL) goto end;
|
||||
ret = PyObject_CallFunctionObjArgs(callback, t, NULL);
|
||||
Py_DECREF(t);
|
||||
if (ret == NULL) goto end;
|
||||
Py_DECREF(ret);
|
||||
if (ph->bufend) {
|
||||
num = ph->end;
|
||||
buf = ph->buffer;
|
||||
t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, num);
|
||||
if (t == NULL) goto end;
|
||||
ret = PyObject_CallFunctionObjArgs(callback, t, NULL);
|
||||
Py_DECREF(t);
|
||||
if (ret == NULL) goto end;
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
Line l = {.xnum=self->xnum};
|
||||
get_line(self, 0, &l);
|
||||
if (!l.continued) {
|
||||
t = PyUnicode_FromString("\n");
|
||||
if (t == NULL) goto end;
|
||||
ret = PyObject_CallFunctionObjArgs(callback, t, NULL);
|
||||
Py_DECREF(t);
|
||||
if (ret == NULL) goto end;
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
end:
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
as_text(HistoryBuf *self, PyObject *args) {
|
||||
Line l = {.xnum=self->xnum};
|
||||
@ -238,6 +310,7 @@ static PyObject* rewrap(HistoryBuf *self, PyObject *args);
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(line, METH_O)
|
||||
METHOD(as_ansi, METH_O)
|
||||
METHODB(pagerhist_as_text, METH_O),
|
||||
METHODB(as_text, METH_VARARGS),
|
||||
METHOD(dirty_lines, METH_NOARGS)
|
||||
METHOD(push, METH_VARARGS)
|
||||
|
||||
@ -436,7 +436,7 @@ class Window:
|
||||
self.screen.reset_callbacks()
|
||||
self.screen = None
|
||||
|
||||
def as_text(self, as_ansi=False, add_history=False, add_wrap_markers=False, alternate_screen=False):
|
||||
def as_text(self, as_ansi=False, add_history=False, add_pager_history=False, add_wrap_markers=False, alternate_screen=False):
|
||||
lines = []
|
||||
add_history = add_history and not self.screen.is_using_alternate_linebuf() and not alternate_screen
|
||||
if alternate_screen:
|
||||
@ -446,6 +446,9 @@ class Window:
|
||||
f(lines.append, as_ansi, add_wrap_markers)
|
||||
if add_history:
|
||||
h = []
|
||||
if add_pager_history:
|
||||
# assert as_ansi and add_wrap_markers?
|
||||
self.screen.historybuf.pagerhist_as_text(h.append)
|
||||
self.screen.historybuf.as_text(h.append, as_ansi, add_wrap_markers)
|
||||
lines = h + lines
|
||||
return ''.join(lines)
|
||||
@ -461,7 +464,7 @@ class Window:
|
||||
# actions {{{
|
||||
|
||||
def show_scrollback(self):
|
||||
data = self.as_text(as_ansi=True, add_history=True, add_wrap_markers=True)
|
||||
data = self.as_text(as_ansi=True, add_history=True, add_pager_history=True, add_wrap_markers=True)
|
||||
data = data.replace('\r\n', '\n').replace('\r', '\n')
|
||||
lines = data.count('\n')
|
||||
input_line_number = (lines - (self.screen.lines - 1) - self.screen.scrolled_by)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user