All screen tests pass with the new screen code

This commit is contained in:
Kovid Goyal 2016-11-13 22:23:28 +05:30
parent bfaaf41a9f
commit a734fb79e6
5 changed files with 61 additions and 16 deletions

View File

@ -287,6 +287,7 @@ void linebuf_init_line(LineBuf *, index_type);
void linebuf_clear(LineBuf *); void linebuf_clear(LineBuf *);
void linebuf_init_line(LineBuf *, index_type); void linebuf_init_line(LineBuf *, index_type);
void linebuf_index(LineBuf* self, index_type top, index_type bottom); 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_clear_line(LineBuf *self, index_type y);
void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom); 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_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);

View File

@ -219,6 +219,7 @@ clear_line(LineBuf *self, PyObject *val) {
} }
void linebuf_index(LineBuf* self, index_type top, index_type bottom) { 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]; index_type old_top = self->line_map[top];
bool old_cont = self->continued_map[top]; bool old_cont = self->continued_map[top];
for (index_type i = top; i < bottom; i++) { 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." #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; unsigned int top, bottom;
if (!PyArg_ParseTuple(args, "II", &top, &bottom)) return NULL; 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); linebuf_index(self, top, bottom);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject* void linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom) {
reverse_index(LineBuf *self, PyObject *args) { if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return;
#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; }
index_type old_bottom = self->line_map[bottom]; index_type old_bottom = self->line_map[bottom];
bool old_cont = self->continued_map[bottom]; bool old_cont = self->continued_map[bottom];
for (index_type i = bottom; i > top; i--) { 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->line_map[top] = old_bottom;
self->continued_map[top] = old_cont; 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; Py_RETURN_NONE;
} }

View File

@ -365,6 +365,18 @@ void screen_index(Screen *self) {
} else screen_cursor_down(self, 1); } 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) { void screen_carriage_return(Screen *self, uint8_t UNUSED ch) {
if (self->cursor->x != 0) { if (self->cursor->x != 0) {
self->cursor->x = 0; self->cursor->x = 0;
@ -666,6 +678,27 @@ erase_in_display(Screen *self, PyObject *args) {
Py_RETURN_NONE; 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) \ #define COUNT_WRAP(name) \
static PyObject* name(Screen *self, PyObject *args) { \ static PyObject* name(Screen *self, PyObject *args) { \
unsigned int count = 1; \ unsigned int count = 1; \
@ -677,6 +710,10 @@ COUNT_WRAP(delete_lines)
COUNT_WRAP(insert_characters) COUNT_WRAP(insert_characters)
COUNT_WRAP(delete_characters) COUNT_WRAP(delete_characters)
COUNT_WRAP(erase_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, ""}, #define MND(name, args) {#name, (PyCFunction)name, args, ""},
@ -698,6 +735,13 @@ static PyMethodDef methods[] = {
MND(insert_characters, METH_VARARGS) MND(insert_characters, METH_VARARGS)
MND(delete_characters, METH_VARARGS) MND(delete_characters, METH_VARARGS)
MND(erase_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 */ {NULL} /* Sentinel */
}; };

View File

@ -4,7 +4,6 @@
from unittest import TestCase from unittest import TestCase
from kitty.screen import Screen as S
from kitty.fast_data_types import LineBuf, Cursor, Screen from kitty.fast_data_types import LineBuf, Cursor, Screen
@ -30,10 +29,7 @@ class BaseTest(TestCase):
ae = TestCase.assertEqual ae = TestCase.assertEqual
def create_screen(self, cols=5, lines=5, history_size=5): def create_screen(self, cols=5, lines=5):
return S(history_size, columns=cols, lines=lines)
def create_screen2(self, cols=5, lines=5):
return Screen(None, lines, cols) return Screen(None, lines, cols)
def assertEqualAttributes(self, c1, c2): def assertEqualAttributes(self, c1, c2):

View File

@ -10,7 +10,7 @@ from kitty.fast_data_types import DECAWM, IRM, Cursor
class TestScreen(BaseTest): class TestScreen(BaseTest):
def test_draw_fast(self): def test_draw_fast(self):
s = self.create_screen2() s = self.create_screen()
# Test in line-wrap, non-insert mode # Test in line-wrap, non-insert mode
s.draw(b'a' * 5) s.draw(b'a' * 5)
@ -55,7 +55,7 @@ class TestScreen(BaseTest):
def test_draw_char(self): def test_draw_char(self):
# Test in line-wrap, non-insert mode # Test in line-wrap, non-insert mode
s = self.create_screen2() s = self.create_screen()
s.draw('ココx'.encode('utf-8')) s.draw('ココx'.encode('utf-8'))
self.ae(str(s.line(0)), 'ココx') self.ae(str(s.line(0)), 'ココx')
self.ae(tuple(map(s.line(0).width, range(5))), (2, 0, 2, 0, 1)) 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),)}) self.assertChanges(s, ignore='cursor', cells={4: ((0, 4),)})
def test_char_manipulation(self): def test_char_manipulation(self):
s = self.create_screen2() s = self.create_screen()
def init(): def init():
s.reset(), s.reset_dirty() 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)))) 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): def test_erase_in_screen(self):
s = self.create_screen2() s = self.create_screen()
def init(): def init():
s.reset() s.reset()