More work on migrating Screen
This commit is contained in:
parent
3c73da224a
commit
fa106c2585
@ -36,15 +36,20 @@ repr(Cursor *self) {
|
||||
);
|
||||
}
|
||||
|
||||
static inline void cursor_reset_display_attrs(Cursor *self) {
|
||||
self->bg = 0; self->fg = 0; self->decoration_fg = 0;
|
||||
self->decoration = 0; self->bold = false; self->italic = false; self->reverse = false; self->strikethrough = false;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
reset_display_attrs(Cursor *self) {
|
||||
#define reset_display_attrs_doc "Reset all display attributes to unset"
|
||||
self->bg = 0; self->fg = 0; self->decoration_fg = 0;
|
||||
self->decoration = 0; self->bold = false; self->italic = false; self->reverse = false; self->strikethrough = false;
|
||||
cursor_reset_display_attrs(self);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void cursor_reset(Cursor *self) {
|
||||
cursor_reset_display_attrs(self);
|
||||
self->x = 0; self->y = 0;
|
||||
self->shape = 0; self->blink = false;
|
||||
self->color = 0; self->hidden = false;
|
||||
|
||||
@ -271,28 +271,33 @@ PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *);
|
||||
PyObject* parse_bytes(PyObject UNUSED *, PyObject *);
|
||||
uint16_t* translation_table(char);
|
||||
uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte);
|
||||
void linebuf_init_line(LineBuf *, index_type);
|
||||
void cursor_reset(Cursor*);
|
||||
Cursor* cursor_copy(Cursor*);
|
||||
bool update_cell_range_data(SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, const uint32_t, const uint32_t, unsigned int *);
|
||||
uint32_t to_color(ColorProfile *, uint32_t, uint32_t);
|
||||
|
||||
PyObject* line_text_at(char_type, combining_type);
|
||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch);
|
||||
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
|
||||
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *);
|
||||
void line_right_shift(Line *, unsigned int , unsigned int );
|
||||
void line_add_combining_char(Line *, uint32_t , unsigned int );
|
||||
void cursor_reset(Cursor*);
|
||||
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int );
|
||||
Cursor* cursor_copy(Cursor*);
|
||||
|
||||
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_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 );
|
||||
|
||||
void screen_restore_cursor(Screen *);
|
||||
void screen_save_cursor(Screen *);
|
||||
void screen_cursor_position(Screen*, unsigned int, unsigned int);
|
||||
void screen_erase_in_display(Screen *, unsigned int, bool);
|
||||
void screen_draw(Screen *screen, uint8_t *buf, unsigned int buflen);
|
||||
bool update_cell_range_data(SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, const uint32_t, const uint32_t, unsigned int *);
|
||||
uint32_t to_color(ColorProfile *, uint32_t, uint32_t);
|
||||
PyObject* line_text_at(char_type, combining_type);
|
||||
void linebuf_init_line(LineBuf *, index_type);
|
||||
void linebuf_index(LineBuf* self, index_type top, index_type bottom);
|
||||
void linebuf_clear_line(LineBuf *self, index_type y);
|
||||
void screen_ensure_bounds(Screen *self, bool use_margins);
|
||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch);
|
||||
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
|
||||
void screen_toggle_screen_buffer(Screen *self);
|
||||
void screen_normal_keypad_mode(Screen *self);
|
||||
void screen_alternate_keypad_mode(Screen *self);
|
||||
|
||||
@ -266,13 +266,9 @@ is_continued(LineBuf *self, PyObject *val) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
insert_lines(LineBuf *self, PyObject *args) {
|
||||
#define insert_lines_doc "insert_lines(num, y, bottom) -> Insert num blank lines at y, only changing lines in the range [y, bottom]."
|
||||
unsigned int y, num, bottom;
|
||||
void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom) {
|
||||
index_type i;
|
||||
if (!PyArg_ParseTuple(args, "III", &num, &y, &bottom)) return NULL;
|
||||
if (y >= self->ynum || y > bottom || bottom >= self->ynum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
|
||||
if (y >= self->ynum || y > bottom || bottom >= self->ynum) return;
|
||||
index_type ylimit = bottom + 1;
|
||||
num = MIN(ylimit - y, num);
|
||||
if (num > 0) {
|
||||
@ -294,12 +290,22 @@ insert_lines(LineBuf *self, PyObject *args) {
|
||||
self->continued_map[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
insert_lines(LineBuf *self, PyObject *args) {
|
||||
#define insert_lines_doc "insert_lines(num, y, bottom) -> Insert num blank lines at y, only changing lines in the range [y, bottom]."
|
||||
unsigned int y, num, bottom;
|
||||
if (!PyArg_ParseTuple(args, "III", &num, &y, &bottom)) return NULL;
|
||||
linebuf_insert_lines(self, num, y, bottom);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static inline void do_delete(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) {
|
||||
index_type i;
|
||||
index_type ylimit = bottom + 1;
|
||||
num = MIN(bottom + 1 - y, num);
|
||||
if (y >= self->ynum || y > bottom || bottom >= self->ynum || num < 1) return;
|
||||
for (i = y; i < y + num; i++) {
|
||||
self->scratch[i] = self->line_map[i];
|
||||
}
|
||||
@ -324,11 +330,7 @@ delete_lines(LineBuf *self, PyObject *args) {
|
||||
#define delete_lines_doc "delete_lines(num, y, bottom) -> Delete num blank lines at y, only changing lines in the range [y, bottom]."
|
||||
unsigned int y, num, bottom;
|
||||
if (!PyArg_ParseTuple(args, "III", &num, &y, &bottom)) return NULL;
|
||||
if (y >= self->ynum || y > bottom || bottom >= self->ynum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
|
||||
num = MIN(bottom + 1 - y, num);
|
||||
if (num > 0) {
|
||||
do_delete(self, num, y, bottom);
|
||||
}
|
||||
linebuf_delete_lines(self, num, y, bottom);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
@ -207,12 +207,16 @@ void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int
|
||||
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||
color_type col = (cursor->fg & COL_MASK) | ((color_type)(cursor->bg & COL_MASK) << COL_SHIFT);
|
||||
decoration_type dfg = cursor->decoration_fg & COL_MASK;
|
||||
if (!clear_char) attrs = ((attrs >> ATTRS_SHIFT) & ~WIDTH_MASK) << ATTRS_SHIFT;
|
||||
|
||||
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
||||
if (clear_char) {
|
||||
self->chars[i] = 32 | attrs;
|
||||
self->combining_chars[i] = 0;
|
||||
} else self->chars[i] = (self->chars[i] & CHAR_MASK) | attrs;
|
||||
} else {
|
||||
char_type w = ((self->chars[i] >> ATTRS_SHIFT) & WIDTH_MASK) << ATTRS_SHIFT;
|
||||
self->chars[i] = (self->chars[i] & CHAR_MASK) | attrs | w;
|
||||
}
|
||||
self->colors[i] = col;
|
||||
self->decoration_fg[i] = dfg;
|
||||
}
|
||||
|
||||
123
kitty/screen.c
123
kitty/screen.c
@ -34,6 +34,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
self->cursor = alloc_cursor();
|
||||
self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns);
|
||||
self->linebuf = self->main_linebuf;
|
||||
// TODO: Change the savepoints objects to use a circular buffer, so there are no mallocs during normal operation
|
||||
self->main_savepoints = PyList_New(0); self->alt_savepoints = PyList_New(0);
|
||||
self->savepoints = self->main_savepoints;
|
||||
self->change_tracker = alloc_change_tracker(lines, columns);
|
||||
@ -184,19 +185,6 @@ void screen_shift_in(Screen UNUSED *self, uint8_t UNUSED ch) {
|
||||
// TODO: Implement this
|
||||
}
|
||||
|
||||
void screen_toggle_screen_buffer(Screen *self) {
|
||||
screen_save_cursor(self);
|
||||
if (self->linebuf == self->main_linebuf) {
|
||||
self->linebuf = self->alt_linebuf;
|
||||
self->savepoints = self->alt_savepoints;
|
||||
} else {
|
||||
self->linebuf = self->main_linebuf;
|
||||
self->savepoints = self->main_savepoints;
|
||||
}
|
||||
screen_restore_cursor(self);
|
||||
tracker_update_screen(self->change_tracker);
|
||||
}
|
||||
|
||||
// Graphics {{{
|
||||
void screen_change_default_color(Screen *self, unsigned int which, uint32_t col) {
|
||||
if (self->callbacks == Py_None) return;
|
||||
@ -210,6 +198,19 @@ void screen_change_default_color(Screen *self, unsigned int which, uint32_t col)
|
||||
|
||||
// Modes {{{
|
||||
|
||||
void screen_toggle_screen_buffer(Screen *self) {
|
||||
screen_save_cursor(self);
|
||||
if (self->linebuf == self->main_linebuf) {
|
||||
self->linebuf = self->alt_linebuf;
|
||||
self->savepoints = self->alt_savepoints;
|
||||
} else {
|
||||
self->linebuf = self->main_linebuf;
|
||||
self->savepoints = self->main_savepoints;
|
||||
}
|
||||
screen_restore_cursor(self);
|
||||
tracker_update_screen(self->change_tracker);
|
||||
}
|
||||
|
||||
void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
||||
void screen_alternate_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
||||
|
||||
@ -517,6 +518,61 @@ void screen_erase_in_display(Screen *self, unsigned int how, bool private) {
|
||||
screen_erase_in_line(self, how, private);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_insert_lines(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
if (top <= (unsigned int)self->cursor->y && (unsigned int)self->cursor->y <= bottom) {
|
||||
linebuf_insert_lines(self->linebuf, count, self->cursor->y, bottom);
|
||||
tracker_update_line_range(self->change_tracker, self->cursor->y, bottom);
|
||||
screen_carriage_return(self, 13);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_delete_lines(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
if (top <= (unsigned int)self->cursor->y && (unsigned int)self->cursor->y <= bottom) {
|
||||
linebuf_delete_lines(self->linebuf, count, self->cursor->y, bottom);
|
||||
tracker_update_line_range(self->change_tracker, self->cursor->y, bottom);
|
||||
screen_carriage_return(self, 13);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_insert_characters(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
if (top <= (unsigned int)self->cursor->y && (unsigned int)self->cursor->y <= bottom) {
|
||||
unsigned int x = self->cursor->x;
|
||||
unsigned int num = MIN(self->columns - x, count);
|
||||
linebuf_init_line(self->linebuf, self->cursor->y);
|
||||
line_right_shift(self->linebuf->line, x, num);
|
||||
line_apply_cursor(self->linebuf->line, self->cursor, x, num, true);
|
||||
tracker_update_cell_range(self->change_tracker, self->cursor->y, x, self->columns - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_delete_characters(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
if (top <= (unsigned int)self->cursor->y && (unsigned int)self->cursor->y <= bottom) {
|
||||
unsigned int x = self->cursor->x;
|
||||
unsigned int num = MIN(self->columns - x, count);
|
||||
linebuf_init_line(self->linebuf, self->cursor->y);
|
||||
left_shift_line(self->linebuf->line, x, num);
|
||||
line_apply_cursor(self->linebuf->line, self->cursor, self->columns - num, num, true);
|
||||
tracker_update_cell_range(self->change_tracker, self->cursor->y, x, self->columns - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_erase_characters(Screen *self, unsigned int count) {
|
||||
if (count == 0) count = 1;
|
||||
unsigned int x = self->cursor->x;
|
||||
unsigned int num = MIN(self->columns - x, count);
|
||||
linebuf_init_line(self->linebuf, self->cursor->y);
|
||||
line_apply_cursor(self->linebuf->line, self->cursor, x, num, true);
|
||||
tracker_update_cell_range(self->change_tracker, self->cursor->y, x, MIN(x + num, self->columns) - 1);
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Python interface {{{
|
||||
@ -590,6 +646,40 @@ cursor_back(Screen *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
erase_in_line(Screen *self, PyObject *args) {
|
||||
#define erase_in_line_doc ""
|
||||
bool private = false;
|
||||
unsigned int how = 0;
|
||||
if (!PyArg_ParseTuple(args, "|Ip", &how, &private)) return NULL;
|
||||
screen_erase_in_line(self, how, private);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
erase_in_display(Screen *self, PyObject *args) {
|
||||
#define erase_in_display_doc ""
|
||||
bool private = false;
|
||||
unsigned int how = 0;
|
||||
if (!PyArg_ParseTuple(args, "|Ip", &how, &private)) return NULL;
|
||||
screen_erase_in_display(self, how, private);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#define COUNT_WRAP(name) \
|
||||
static PyObject* name(Screen *self, PyObject *args) { \
|
||||
unsigned int count = 1; \
|
||||
if (!PyArg_ParseTuple(args, "|I", &count)) return NULL; \
|
||||
screen_##name(self, count); \
|
||||
Py_RETURN_NONE; }
|
||||
COUNT_WRAP(insert_lines)
|
||||
COUNT_WRAP(delete_lines)
|
||||
COUNT_WRAP(insert_characters)
|
||||
COUNT_WRAP(delete_characters)
|
||||
COUNT_WRAP(erase_characters)
|
||||
|
||||
#define MND(name, args) {#name, (PyCFunction)name, args, ""},
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(line, METH_O)
|
||||
METHOD(draw, METH_VARARGS)
|
||||
@ -601,6 +691,13 @@ static PyMethodDef methods[] = {
|
||||
METHOD(reset_dirty, METH_NOARGS)
|
||||
METHOD(consolidate_changes, METH_NOARGS)
|
||||
METHOD(cursor_back, METH_VARARGS)
|
||||
METHOD(erase_in_line, METH_VARARGS)
|
||||
METHOD(erase_in_display, METH_VARARGS)
|
||||
MND(insert_lines, METH_VARARGS)
|
||||
MND(delete_lines, METH_VARARGS)
|
||||
MND(insert_characters, METH_VARARGS)
|
||||
MND(delete_characters, METH_VARARGS)
|
||||
MND(erase_characters, METH_VARARGS)
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
from . import BaseTest
|
||||
|
||||
from kitty.fast_data_types import DECAWM, IRM
|
||||
from kitty.fast_data_types import DECAWM, IRM, Cursor
|
||||
|
||||
|
||||
class TestScreen(BaseTest):
|
||||
@ -55,7 +55,7 @@ class TestScreen(BaseTest):
|
||||
|
||||
def test_draw_char(self):
|
||||
# Test in line-wrap, non-insert mode
|
||||
s = self.create_screen()
|
||||
s = self.create_screen2()
|
||||
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_screen()
|
||||
s = self.create_screen2()
|
||||
|
||||
def init():
|
||||
s.reset(), s.reset_dirty()
|
||||
@ -128,6 +128,10 @@ class TestScreen(BaseTest):
|
||||
s.insert_characters(1)
|
||||
self.ae(str(s.line(0)), ' xコ ')
|
||||
self.assertChanges(s, ignore='cursor', cells={0: ((0, 4),)})
|
||||
c = Cursor()
|
||||
c.bold = True
|
||||
s.line(0).apply_cursor(c, 0, 5)
|
||||
self.ae(s.line(0).width(2), 2)
|
||||
|
||||
init()
|
||||
s.delete_characters(2)
|
||||
@ -160,7 +164,7 @@ class TestScreen(BaseTest):
|
||||
self.ae(str(s.line(0)), ' ')
|
||||
self.assertChanges(s, cells={0: ((0, 4),)})
|
||||
init()
|
||||
s.erase_in_line(2, private=True)
|
||||
s.erase_in_line(2, True)
|
||||
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):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user