diff --git a/kitty/cursor.c b/kitty/cursor.c index 4f433b439..fac35ab95 100644 --- a/kitty/cursor.c +++ b/kitty/cursor.c @@ -42,7 +42,7 @@ dealloc(Cursor* self) { #define EQ(x) (a->x == b->x) #define PEQ(x) (PyObject_RichCompareBool(a->x, b->x, Py_EQ) == 1) -int is_eq(Cursor *a, Cursor *b) { +static int __eq__(Cursor *a, Cursor *b) { return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && PEQ(x) && PEQ(y) && PEQ(shape) && PEQ(blink) && PEQ(color) && PEQ(hidden); } @@ -103,25 +103,10 @@ PyTypeObject Cursor_Type = { .tp_new = new, }; +RICHCMP(Cursor) // }}} -static PyObject * -richcmp(PyObject *obj1, PyObject *obj2, int op) -{ - PyObject *result = NULL; - int eq; - - if (op != Py_EQ && op != Py_NE) { Py_RETURN_NOTIMPLEMENTED; } - if (!PyObject_TypeCheck(obj1, &Cursor_Type)) { Py_RETURN_FALSE; } - if (!PyObject_TypeCheck(obj2, &Cursor_Type)) { Py_RETURN_FALSE; } - eq = is_eq((Cursor*)obj1, (Cursor*)obj2); - if (op == Py_NE) result = eq ? Py_False : Py_True; - else result = eq ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - static PyObject* copy(Cursor *self, PyObject UNUSED *args) { #define CPY(x) ans->x = self->x; Py_XINCREF(self->x); diff --git a/kitty/data-types.h b/kitty/data-types.h index 122d3fee7..49d3b6b90 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -69,6 +69,22 @@ typedef unsigned int index_type; return 1; \ } +#define RICHCMP(type) \ + static PyObject * richcmp(PyObject *obj1, PyObject *obj2, int op) { \ + PyObject *result = NULL; \ + int eq; \ + if (op != Py_EQ && op != Py_NE) { Py_RETURN_NOTIMPLEMENTED; } \ + if (!PyObject_TypeCheck(obj1, &type##_Type)) { Py_RETURN_FALSE; } \ + if (!PyObject_TypeCheck(obj2, &type##_Type)) { Py_RETURN_FALSE; } \ + eq = __eq__((type*)obj1, (type*)obj2); \ + if (op == Py_NE) result = eq ? Py_False : Py_True; \ + else result = eq ? Py_True : Py_False; \ + Py_INCREF(result); \ + return result; \ + } + + + typedef struct { PyObject_HEAD diff --git a/kitty/line.c b/kitty/line.c index 96f47966e..dbc9b999e 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -250,11 +250,22 @@ __len__(PyObject *self) { return (Py_ssize_t)(((Line*)self)->ynum); } +static int __eq__(Line *a, Line *b) { + return a->xnum == b->xnum && \ + memcmp(a->chars, b->chars, sizeof(char_type) * a->xnum) == 0 && \ + memcmp(a->colors, b->colors, sizeof(color_type) * a->xnum) == 0 && \ + memcmp(a->decoration_fg, b->decoration_fg, sizeof(decoration_type) * a->xnum) == 0 && \ + memcmp(a->combining_chars, b->combining_chars, sizeof(combining_type) * a->xnum) == 0; +} + // Boilerplate {{{ static PyObject* copy_char(Line* self, PyObject *args); #define copy_char_doc "copy_char(src, to, dest) -> Copy the character at src to to the character dest in the line `to`" +static PyObject * +richcmp(PyObject *obj1, PyObject *obj2, int op); + static PySequenceMethods sequence_methods = { .sq_length = __len__, @@ -282,6 +293,7 @@ static PyTypeObject Line_Type = { .tp_repr = (reprfunc)as_unicode, .tp_as_sequence = &sequence_methods, .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_richcompare = richcmp, .tp_doc = "Lines", .tp_methods = methods, .tp_new = new @@ -290,6 +302,8 @@ static PyTypeObject Line_Type = { Line *alloc_line() { return (Line*)PyType_GenericAlloc(&Line_Type, 0); } + +RICHCMP(Line) // }} static PyObject* diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index e7cd2be96..c935c6749 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -20,6 +20,15 @@ def filled_line_buf(ynum=5, xnum=5, cursor=Cursor()): return ans +def filled_cursor(): + ans = Cursor() + ans.bold = ans.italic = ans.reverse = ans.strikethrough = True + ans.fg = 0x101 + ans.bg = 0x201 + ans.decoration_fg = 0x301 + return ans + + class BaseTest(TestCase): ae = TestCase.assertEqual diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 726207eb8..591bd1d83 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -4,7 +4,7 @@ import codecs -from . import BaseTest, filled_line_buf +from . import BaseTest, filled_line_buf, filled_cursor from kitty.utils import is_simple_string, wcwidth, sanitize_title from kitty.fast_data_types import LineBuf, Cursor as C @@ -13,10 +13,10 @@ from kitty.fast_data_types import LineBuf, Cursor as C class TestDataTypes(BaseTest): def test_linebuf(self): - old = filled_line_buf(2, 3) + old = filled_line_buf(2, 3, filled_cursor()) new = LineBuf(1, 3) new.copy_old(old) - self.ae(str(new.line(0)), str(old.line(1))) + self.ae(new.line(0), old.line(1)) def test_line(self): lb = LineBuf(2, 3)