diff --git a/kitty/data_types.py b/kitty/data_types.py index c41e7f529..1779786b9 100644 --- a/kitty/data_types.py +++ b/kitty/data_types.py @@ -112,6 +112,10 @@ class Line: to.bg[dest] = self.bg[src] to.decoration_fg[dest] = self.decoration_fg[src] + def cursor_to_attrs(self, c: Cursor) -> int: + return ((c.decoration & 0b11) << DECORATION_SHIFT) | ((c.bold & 0b1) << BOLD_SHIFT) | \ + ((c.italic & 0b1) << ITALIC_SHIFT) | ((c.reverse & 0b1) << REVERSE_SHIFT) | ((c.strikethrough & 0b1) << STRIKE_SHIFT) + def apply_cursor(self, c: Cursor, at: int=0, num: int=1, clear_char=False, char=' ') -> None: for i in range(at, at + num): self.fg[i] = c.fg @@ -121,8 +125,7 @@ class Line: ch = ord(char) if clear_char else sc & CHAR_MASK sattrs = sc >> ATTRS_SHIFT w = 1 if clear_char else sattrs & WIDTH_MASK - attrs = w | ((c.decoration & 0b11) << DECORATION_SHIFT) | ((c.bold & 0b1) << BOLD_SHIFT) | \ - ((c.italic & 0b1) << ITALIC_SHIFT) | ((c.reverse & 0b1) << REVERSE_SHIFT) | ((c.strikethrough & 0b1) << STRIKE_SHIFT) + attrs = w | self.cursor_to_attrs(c) self.char[i] = (ch & CHAR_MASK) | (attrs << ATTRS_SHIFT) def cursor_from(self, x: int, ypos: int=0) -> Cursor: @@ -136,6 +139,17 @@ class Line: c.strikethrough = bool((attrs >> STRIKE_SHIFT) & 0b1) return c + def set_text(self, text: str, offset_in_text: int, sz: int, cursor: Cursor) -> None: + ' Set the specified text in this line, with attributes taken from the cursor ' + attrs = self.cursor_to_attrs(cursor) | 1 + fg, bg, dfg = cursor.fg, cursor.bg, cursor.decoration_fg + dx = cursor.x + for cpos in range(offset_in_text, offset_in_text + sz): + ch = ord(text[cpos]) & CHAR_MASK + self.char[dx] = ch | (attrs << ATTRS_SHIFT) + self.fg[dx], self.bg[dx], self.decoration_fg[dx] = fg, bg, dfg + dx += 1 + def copy_slice(self, src, dest, num): src, dest = slice(src, src + num), slice(dest, dest + num) for a in (self.char, self.fg, self.bg, self.decoration_fg): @@ -164,10 +178,14 @@ class Line: def width(self, i): return (self.char[i] >> ATTRS_SHIFT) & 0b11 - def set_char(self, i, ch, width=1): - c = self.char[i] - a = c >> ATTRS_SHIFT - a = (a & ~WIDTH_MASK) | (width & WIDTH_MASK) + def set_char(self, i: int, ch: str, width: int=1, cursor: Cursor=None) -> None: + if cursor is None: + c = self.char[i] + a = (c >> ATTRS_SHIFT) & ~WIDTH_MASK + else: + a = self.cursor_to_attrs(cursor) + self.fg[i], self.bg[i], self.decoration_fg[i] = cursor.fg, cursor.bg, cursor.decoration_fg + a |= width & WIDTH_MASK self.char[i] = (a << ATTRS_SHIFT) | (ord(ch) & CHAR_MASK) def set_bold(self, i, val): diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 476024c00..8f01f5575 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -8,12 +8,3 @@ from unittest import TestCase class BaseTest(TestCase): ae = TestCase.assertEqual - - -def set_text_in_line(line, text, offset=0): - pos = offset - for ch in text: - line.set_char(pos, ch) - pos += 1 - if pos >= len(line): - break diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index a90abf3d7..7ddcf6aea 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -4,7 +4,7 @@ import codecs -from . import BaseTest, set_text_in_line +from . import BaseTest from kitty.data_types import Line, Cursor from kitty.utils import is_simple_string, wcwidth @@ -15,7 +15,7 @@ class TestDataTypes(BaseTest): def test_line_ops(self): t = 'Testing with simple text' l = Line(len(t)) - set_text_in_line(l, t) + l.set_text(t, 0, len(t), Cursor()) self.ae(l, l) self.ae(str(l), t) self.ae(str(l.copy()), t) @@ -49,7 +49,7 @@ class TestDataTypes(BaseTest): t = '0123456789' lo = Line(len(t)) - set_text_in_line(lo, t) + lo.set_text(t, 0, len(t), Cursor()) l = lo.copy() l.right_shift(4, 2) self.ae(str(l), '0123454567') @@ -75,6 +75,14 @@ class TestDataTypes(BaseTest): l.set_decoration(0, q.decoration) c = l.cursor_from(0) self.ae(c, q) + l = Line(len(t)) + l.set_text(t, 0, len(t), q) + self.ae(l.cursor_from(0), q) + l.set_text('axyb', 1, 2, Cursor(3)) + self.ae(str(l), '012xy56789') + l = Line(1) + l.set_char(0, 'x', cursor=q) + self.ae(l.cursor_from(0), q) def test_utils(self): d = codecs.getincrementaldecoder('utf-8')('strict').decode