From a734fb79e691e411bcd56daa8352f92fe28a10b0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 13 Nov 2016 22:23:28 +0530 Subject: [PATCH] All screen tests pass with the new screen code --- kitty/data-types.h | 1 + kitty/line-buf.c | 18 ++++++++++------- kitty/screen.c | 44 +++++++++++++++++++++++++++++++++++++++++ kitty_tests/__init__.py | 6 +----- kitty_tests/screen.py | 8 ++++---- 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/kitty/data-types.h b/kitty/data-types.h index 5e3a1a32e..307460f72 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -287,6 +287,7 @@ void linebuf_init_line(LineBuf *, index_type); void linebuf_clear(LineBuf *); void linebuf_init_line(LineBuf *, index_type); void linebuf_index(LineBuf* self, index_type top, index_type bottom); +void linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom); 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); diff --git a/kitty/line-buf.c b/kitty/line-buf.c index fe9233a27..affaaf4f1 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -219,6 +219,7 @@ clear_line(LineBuf *self, PyObject *val) { } void linebuf_index(LineBuf* self, index_type top, index_type bottom) { + if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return; index_type old_top = self->line_map[top]; bool old_cont = self->continued_map[top]; for (index_type i = top; i < bottom; i++) { @@ -234,17 +235,12 @@ index(LineBuf *self, PyObject *args) { #define index_doc "index(top, bottom) -> Scroll all lines in the range [top, bottom] by one upwards. After scrolling, bottom will be top." unsigned int top, bottom; 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; } linebuf_index(self, top, bottom); Py_RETURN_NONE; } -static PyObject* -reverse_index(LineBuf *self, PyObject *args) { -#define reverse_index_doc "reverse_index(top, bottom) -> Scroll all lines in the range [top, bottom] by one down. After scrolling, top will be bottom." - unsigned int top, bottom; - 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; } +void linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom) { + if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return; index_type old_bottom = self->line_map[bottom]; bool old_cont = self->continued_map[bottom]; for (index_type i = bottom; i > top; i--) { @@ -253,6 +249,14 @@ reverse_index(LineBuf *self, PyObject *args) { } self->line_map[top] = old_bottom; self->continued_map[top] = old_cont; +} + +static PyObject* +reverse_index(LineBuf *self, PyObject *args) { +#define reverse_index_doc "reverse_index(top, bottom) -> Scroll all lines in the range [top, bottom] by one down. After scrolling, top will be bottom." + unsigned int top, bottom; + if (!PyArg_ParseTuple(args, "II", &top, &bottom)) return NULL; + linebuf_reverse_index(self, top, bottom); Py_RETURN_NONE; } diff --git a/kitty/screen.c b/kitty/screen.c index ebfabd02b..a7665e9f4 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -365,6 +365,18 @@ void screen_index(Screen *self) { } else screen_cursor_down(self, 1); } +void screen_reverse_index(Screen *self) { + // Move cursor up one line, scrolling screen if needed + unsigned int top = self->margin_top, bottom = self->margin_bottom; + if ((unsigned int)self->cursor->y == top) { + linebuf_reverse_index(self->linebuf, top, bottom); + linebuf_clear_line(self->linebuf, top); + if (bottom - top > self->lines - 1) tracker_update_screen(self->change_tracker); + else tracker_update_line_range(self->change_tracker, top, bottom); + } else screen_cursor_up(self, 1, false, -1); +} + + void screen_carriage_return(Screen *self, uint8_t UNUSED ch) { if (self->cursor->x != 0) { self->cursor->x = 0; @@ -666,6 +678,27 @@ erase_in_display(Screen *self, PyObject *args) { Py_RETURN_NONE; } +static PyObject* +cursor_up(Screen *self, PyObject *args) { + unsigned int count = 1; + int do_carriage_return = false, move_direction = -1; + if (!PyArg_ParseTuple(args, "|Ipi", &count, &do_carriage_return, &move_direction)) return NULL; + screen_cursor_up(self, count, do_carriage_return, move_direction); + Py_RETURN_NONE; +} + +static PyObject* +index(Screen *self) { + screen_index(self); + Py_RETURN_NONE; +} + +static PyObject* +reverse_index(Screen *self) { + screen_reverse_index(self); + Py_RETURN_NONE; +} + #define COUNT_WRAP(name) \ static PyObject* name(Screen *self, PyObject *args) { \ unsigned int count = 1; \ @@ -677,6 +710,10 @@ COUNT_WRAP(delete_lines) COUNT_WRAP(insert_characters) COUNT_WRAP(delete_characters) COUNT_WRAP(erase_characters) +COUNT_WRAP(cursor_up1) +COUNT_WRAP(cursor_down) +COUNT_WRAP(cursor_down1) +COUNT_WRAP(cursor_forward) #define MND(name, args) {#name, (PyCFunction)name, args, ""}, @@ -698,6 +735,13 @@ static PyMethodDef methods[] = { MND(insert_characters, METH_VARARGS) MND(delete_characters, METH_VARARGS) MND(erase_characters, METH_VARARGS) + MND(cursor_up, METH_VARARGS) + MND(cursor_up1, METH_VARARGS) + MND(cursor_down, METH_VARARGS) + MND(cursor_down1, METH_VARARGS) + MND(cursor_forward, METH_VARARGS) + MND(index, METH_NOARGS) + MND(reverse_index, METH_NOARGS) {NULL} /* Sentinel */ }; diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index ebdc850bc..8920b656e 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -4,7 +4,6 @@ from unittest import TestCase -from kitty.screen import Screen as S from kitty.fast_data_types import LineBuf, Cursor, Screen @@ -30,10 +29,7 @@ class BaseTest(TestCase): ae = TestCase.assertEqual - def create_screen(self, cols=5, lines=5, history_size=5): - return S(history_size, columns=cols, lines=lines) - - def create_screen2(self, cols=5, lines=5): + def create_screen(self, cols=5, lines=5): return Screen(None, lines, cols) def assertEqualAttributes(self, c1, c2): diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 8ef5373e6..d75b6ed0d 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -10,7 +10,7 @@ from kitty.fast_data_types import DECAWM, IRM, Cursor class TestScreen(BaseTest): def test_draw_fast(self): - s = self.create_screen2() + s = self.create_screen() # Test in line-wrap, non-insert mode s.draw(b'a' * 5) @@ -55,7 +55,7 @@ class TestScreen(BaseTest): def test_draw_char(self): # Test in line-wrap, non-insert mode - s = self.create_screen2() + s = self.create_screen() s.draw('ココx'.encode('utf-8')) self.ae(str(s.line(0)), 'ココx') self.ae(tuple(map(s.line(0).width, range(5))), (2, 0, 2, 0, 1)) @@ -103,7 +103,7 @@ class TestScreen(BaseTest): self.assertChanges(s, ignore='cursor', cells={4: ((0, 4),)}) def test_char_manipulation(self): - s = self.create_screen2() + s = self.create_screen() def init(): s.reset(), s.reset_dirty() @@ -170,7 +170,7 @@ class TestScreen(BaseTest): self.ae((False, False, False, False, False), tuple(map(lambda i: s.line(0).cursor_from(i).bold, range(5)))) def test_erase_in_screen(self): - s = self.create_screen2() + s = self.create_screen() def init(): s.reset()