diff --git a/kitty/cursor.c b/kitty/cursor.c index 8841b757a..2a85171d5 100644 --- a/kitty/cursor.c +++ b/kitty/cursor.c @@ -62,6 +62,11 @@ copy(Cursor *self, PyObject *args); // Boilerplate {{{ +BOOL_GETSET(Cursor, bold) +BOOL_GETSET(Cursor, italic) +BOOL_GETSET(Cursor, reverse) +BOOL_GETSET(Cursor, strikethrough) + static PyMemberDef members[] = { {"x", T_OBJECT_EX, offsetof(Cursor, x), 0, "x"}, {"y", T_OBJECT_EX, offsetof(Cursor, y), 0, "y"}, @@ -70,10 +75,6 @@ static PyMemberDef members[] = { {"color", T_OBJECT_EX, offsetof(Cursor, color), 0, "color"}, {"hidden", T_OBJECT_EX, offsetof(Cursor, hidden), 0, "hidden"}, - {"bold", T_UBYTE, offsetof(Cursor, bold), 0, "bold"}, - {"italic", T_UBYTE, offsetof(Cursor, italic), 0, "italic"}, - {"strikethrough", T_UBYTE, offsetof(Cursor, strikethrough), 0, "strikethrough"}, - {"reverse", T_UBYTE, offsetof(Cursor, reverse), 0, "reverse"}, {"decoration", T_UBYTE, offsetof(Cursor, decoration), 0, "decoration"}, {"fg", T_UINT, offsetof(Cursor, fg), 0, "fg"}, {"bg", T_UINT, offsetof(Cursor, bg), 0, "bg"}, @@ -81,6 +82,14 @@ static PyMemberDef members[] = { {NULL} /* Sentinel */ }; +static PyGetSetDef getseters[] = { + GETSET(bold) + GETSET(italic) + GETSET(reverse) + GETSET(strikethrough) + {NULL} /* Sentinel */ +}; + static PyMethodDef methods[] = { METHOD(copy, METH_NOARGS) {NULL} /* Sentinel */ @@ -101,6 +110,7 @@ PyTypeObject Cursor_Type = { .tp_richcompare = richcmp, .tp_methods = methods, .tp_members = members, + .tp_getset = getseters, .tp_new = new, }; diff --git a/kitty/data-types.h b/kitty/data-types.h index e9d6f4f06..eed13264c 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -9,6 +9,7 @@ #include +#include #define PY_SSIZE_T_CLEAN #include #define UNUSED __attribute__ ((unused)) @@ -68,6 +69,13 @@ typedef unsigned int index_type; #define METHOD(name, arg_type) {#name, (PyCFunction)name, arg_type, name##_doc}, +#define BOOL_GETSET(type, x) \ + static PyObject* x##_get(type *self, void UNUSED *closure) { PyObject *ans = self->x ? Py_True : Py_False; Py_INCREF(ans); return ans; } \ + static int x##_set(type *self, PyObject *value, void UNUSED *closure) { if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } self->x = PyObject_IsTrue(value) ? true : false; return 0; } + +#define GETSET(x) \ + {#x, (getter) x##_get, (setter) x##_set, #x, NULL}, + #define INIT_TYPE(type) \ int init_##type(PyObject *module) {\ if (PyType_Ready(&type##_Type) < 0) return 0; \ @@ -100,18 +108,18 @@ typedef struct { decoration_type *decoration_fg; combining_type *combining_chars; index_type xnum, ynum; - uint8_t continued; - uint8_t needs_free; + bool continued; + bool needs_free; } Line; typedef struct { PyObject_HEAD - uint8_t *buf; + bool *buf; index_type xnum, ynum, *line_map, *scratch; index_type block_size; - uint8_t *continued_map; + bool *continued_map; Line *line; // Pointers into buf @@ -126,7 +134,8 @@ typedef struct { PyObject_HEAD PyObject *x, *y, *shape, *blink, *hidden, *color; - uint8_t bold, italic, reverse, strikethrough, decoration; + bool bold, italic, reverse, strikethrough; + uint8_t decoration; uint32_t fg, bg, decoration_fg; } Cursor; diff --git a/kitty/line-buf.c b/kitty/line-buf.c index 1a7eeeae6..242f3e2de 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -52,7 +52,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { self->buf = PyMem_Calloc(xnum * ynum, CELL_SIZE); self->line_map = PyMem_Calloc(ynum, sizeof(index_type)); self->scratch = PyMem_Calloc(ynum, sizeof(index_type)); - self->continued_map = PyMem_Calloc(ynum, sizeof(uint8_t)); + self->continued_map = PyMem_Calloc(ynum, sizeof(bool)); self->line = alloc_line(); if (self->buf == NULL || self->line_map == NULL || self->scratch == NULL || self->continued_map == NULL || self->line == NULL) { PyErr_NoMemory(); @@ -128,7 +128,7 @@ set_continued(LineBuf *self, PyObject *args) { } static inline int -allocate_line_storage(Line *line, uint8_t initialize) { +allocate_line_storage(Line *line, bool initialize) { if (initialize) { line->chars = PyMem_Calloc(line->xnum, sizeof(char_type)); line->colors = PyMem_Calloc(line->xnum, sizeof(color_type)); @@ -209,7 +209,7 @@ index(LineBuf *self, PyObject *args) { if (!PyArg_ParseTuple(args, "II", &top, &bottom)) return NULL; if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; } index_type old_top = self->line_map[top]; - uint8_t old_cont = self->continued_map[top]; + bool old_cont = self->continued_map[top]; for (index_type i = top; i < bottom; i++) { self->line_map[i] = self->line_map[i + 1]; self->continued_map[i] = self->continued_map[i + 1]; @@ -226,7 +226,7 @@ reverse_index(LineBuf *self, PyObject *args) { if (!PyArg_ParseTuple(args, "II", &top, &bottom)) return NULL; if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; } index_type old_bottom = self->line_map[bottom]; - uint8_t old_cont = self->continued_map[bottom]; + bool old_cont = self->continued_map[bottom]; for (index_type i = bottom; i > top; i--) { self->line_map[i] = self->line_map[i - 1]; self->continued_map[i] = self->continued_map[i - 1]; @@ -308,17 +308,23 @@ delete_lines(LineBuf *self, PyObject *args) { Py_RETURN_NONE; } + // Boilerplate {{{ static PyObject* 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); +#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[] = { METHOD(line, METH_O) METHOD(clear_line, METH_O) METHOD(copy_old, METH_O) METHOD(copy_line_to, METH_VARARGS) METHOD(create_line_copy, METH_O) + METHOD(rewrap, METH_O) METHOD(clear, METH_NOARGS) METHOD(set_attribute, METH_VARARGS) METHOD(set_continued, METH_VARARGS) @@ -369,3 +375,22 @@ copy_old(LineBuf *self, PyObject *y) { Py_RETURN_NONE; } +static PyObject* +rewrap(LineBuf *self, PyObject *val) { + LineBuf* other; + 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) { + memcpy(other->line_map, self->line_map, sizeof(index_type) * self->ynum); + memcpy(other->continued_map, self->continued_map, sizeof(bool) * self->ynum); + memcpy(other->buf, self->buf, self->xnum * self->ynum * CELL_SIZE); + return ret; + } + + return ret; +} +