API to set text in Line efficiently

This commit is contained in:
Kovid Goyal 2016-10-17 13:50:53 +05:30
parent b02dc836fb
commit 44e8238eaf
3 changed files with 35 additions and 18 deletions

View File

@ -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):

View File

@ -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

View File

@ -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