Implement Screen.resize

This commit is contained in:
Kovid Goyal 2016-11-18 12:38:31 +05:30
parent a120b25286
commit 6c39b07552
4 changed files with 74 additions and 20 deletions

View File

@ -295,6 +295,7 @@ 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 screen_restore_cursor(Screen *);
void screen_save_cursor(Screen *);

View File

@ -415,10 +415,12 @@ 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); \
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 (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); \
}\
} else dest_y++; \
INIT_LINE(dest, dest->line, dest->line_map[dest_y]); \
dest->continued_map[dest_y] = continued; \
@ -426,6 +428,7 @@ static inline void copy_range(Line *src, index_type src_at, Line* dest, index_ty
}
static bool rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, PyObject *extra_lines) {
// 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;
INIT_LINE(dest, dest->line, dest->line_map[dest_y]);
@ -452,18 +455,10 @@ static bool rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit
return true;
}
static PyObject*
rewrap(LineBuf *self, PyObject *val) {
LineBuf* other;
bool linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, PyObject *extra_lines) {
index_type first, i;
int cursor_y = -1;
bool is_empty = true;
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();
// Fast path
if (other->xnum == self->xnum && other->ynum == self->ynum) {
Py_BEGIN_ALLOW_THREADS;
@ -471,7 +466,7 @@ rewrap(LineBuf *self, PyObject *val) {
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;
goto end;
return true;
}
// Find the first line that contains some content
@ -485,16 +480,27 @@ rewrap(LineBuf *self, PyObject *val) {
}
Py_END_ALLOW_THREADS;
if (first == 0) { cursor_y = 0; goto end; } // All lines are empty
if (first == 0) { *cursor_y_out = 0; return true; } // All lines are empty
if (!rewrap_inner(self, other, first + 1, ret)) {
Py_CLEAR(ret);
return PyErr_NoMemory();
if (!rewrap_inner(self, other, first + 1, extra_lines)) {
PyErr_NoMemory();
return false;
}
*cursor_y_out = other->line->ynum;
return true;
}
cursor_y = other->line->ynum;
static PyObject*
rewrap(LineBuf *self, PyObject *val) {
LineBuf* other;
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;
end:
return Py_BuildValue("Ni", ret, cursor_y);
}

View File

@ -66,6 +66,41 @@ 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) {
LineBuf *ans = alloc_linebuf(lines, columns);
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
if(!linebuf_rewrap(old, ans, cursor_y, NULL)) return NULL;
return ans;
}
static bool screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
lines = MAX(1, lines); columns = MAX(1, columns);
bool is_main = self->linebuf == self->main_linebuf;
int cursor_y = -1;
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &cursor_y);
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);
if (n == NULL) return false;
Py_CLEAR(self->alt_linebuf); self->alt_linebuf = n;
if (!is_main) self->cursor->y = MAX(0, cursor_y);
self->linebuf = is_main ? self->main_linebuf : self->alt_linebuf;
if (!tracker_resize(self->change_tracker, lines, columns)) return false;
PyMem_Free(self->tabstops);
self->tabstops = PyMem_Calloc(self->columns, sizeof(bool));
if (self->tabstops == NULL) { PyErr_NoMemory(); return false; }
self->lines = lines; self->columns = columns;
self->margin_top = 0; self->margin_bottom = self->lines - 1;
screen_reset_mode(self, DECOM);
// TODO: resize history buf
return true;
}
static void
dealloc(Screen* self) {
@ -555,6 +590,8 @@ void screen_restore_cursor(Screen *self) {
self->utf8_state = sp->utf8_state;
if (sp->mDECOM) screen_set_mode(self, DECOM);
if (sp->mDECAWM) screen_set_mode(self, DECAWM);
self->cursor = cursor_copy(sp->cursor);
screen_ensure_bounds(self, false);
PyList_SetSlice(self->savepoints, sz-1, sz, NULL);
} else {
screen_cursor_position(self, 1, 1);
@ -935,6 +972,14 @@ reverse_index(Screen *self) {
Py_RETURN_NONE;
}
static PyObject*
resize(Screen *self, PyObject *args) {
unsigned int lines = 1, columns = 1;
if (!PyArg_ParseTuple(args, "II", &lines, &columns)) return NULL;
if (!screen_resize(self, lines, columns)) return NULL;
Py_RETURN_NONE;
}
#define COUNT_WRAP(name) \
static PyObject* name(Screen *self, PyObject *args) { \
unsigned int count = 1; \
@ -978,6 +1023,7 @@ static PyMethodDef methods[] = {
MND(cursor_forward, METH_VARARGS)
MND(index, METH_NOARGS)
MND(reverse_index, METH_NOARGS)
MND(resize, METH_VARARGS)
{NULL} /* Sentinel */
};

View File

@ -51,3 +51,4 @@ static inline void tracker_reset(ChangeTracker *self) {
}
PyObject* tracker_consolidate_changes(ChangeTracker *self);
bool tracker_resize(ChangeTracker *self, unsigned int ynum, unsigned int xnum);