diff --git a/kitty/data-types.h b/kitty/data-types.h index 91101df7c..7393f5753 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -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 *); diff --git a/kitty/line-buf.c b/kitty/line-buf.c index affaaf4f1..5bbc37d8a 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -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); } diff --git a/kitty/screen.c b/kitty/screen.c index e903d67ea..3c7460c79 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -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 */ }; diff --git a/kitty/tracker.h b/kitty/tracker.h index 276554ca2..75e644d52 100644 --- a/kitty/tracker.h +++ b/kitty/tracker.h @@ -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);