Switch to tracking linewrap on the last cell in a line

This allows us to have newline not affect the wrap status of a line.

Now a lines wrapping status is changed only when the last cell
in the line is changed. This actually matches the behavior of many other
terminal emulators so is probably a good thing from a ecosystem
compatibility perspective.

The fish shell expects this weird behavior of newline not changing
wrapping status, for unknown reasons, which is the actual motivation for
doing all this work.

Fixes #5766
This commit is contained in:
Kovid Goyal
2022-12-26 20:26:21 +05:30
parent 4556f5b8f1
commit 68cf9f7514
10 changed files with 156 additions and 91 deletions

View File

@@ -20,11 +20,10 @@ from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf
def create_lbuf(*lines):
maxw = max(map(len, lines))
ans = LineBuf(len(lines), maxw)
prev_full_length = False
for i, l0 in enumerate(lines):
ans.line(i).set_text(l0, 0, len(l0), C())
ans.set_continued(i, prev_full_length)
prev_full_length = len(l0) == maxw
if i > 0:
ans.set_continued(i, len(lines[i-1]) == maxw)
return ans
@@ -73,9 +72,9 @@ class TestDataTypes(BaseTest):
self.assertFalse(c.reverse)
self.assertTrue(c.bold)
self.assertFalse(old.is_continued(0))
old.set_continued(0, True)
self.assertTrue(old.is_continued(0))
self.assertFalse(old.is_continued(1))
old.set_continued(1, True)
self.assertTrue(old.is_continued(1))
self.assertFalse(old.is_continued(0))
lb = filled_line_buf(5, 5, filled_cursor())
lb2 = LineBuf(5, 5)
@@ -518,7 +517,7 @@ class TestDataTypes(BaseTest):
self.ae(l2.as_ansi(), '\x1b[1;2;3;7;9;34;48:2:1:2:3;58:5:5m' '1'
'\x1b[22;23;27;29;39;49;59m' '0000')
lb = filled_line_buf()
for i in range(lb.ynum):
for i in range(1, lb.ynum + 1):
lb.set_continued(i, True)
a = []
lb.as_ansi(a.append)

View File

@@ -210,22 +210,23 @@ class TestScreen(BaseTest):
s.reset_dirty()
s.cursor.x, s.cursor.y = 2, 1
s.cursor.bold = True
self.ae(continuations(s), (True, True, True, True, False))
def all_lines(s):
return tuple(str(s.line(i)) for i in range(s.lines))
def continuations(s):
return tuple(s.line(i).is_continued() for i in range(s.lines))
return tuple(s.line(i).last_char_has_wrapped_flag() for i in range(s.lines))
init()
s.erase_in_display(0)
self.ae(all_lines(s), ('12345', '12', '', '', ''))
self.ae(continuations(s), (False, True, False, False, False))
self.ae(continuations(s), (True, False, False, False, False))
init()
s.erase_in_display(1)
self.ae(all_lines(s), ('', ' 45', '12345', '12345', '12345'))
self.ae(continuations(s), (False, False, True, True, True))
self.ae(continuations(s), (False, True, True, True, False))
init()
s.erase_in_display(2)
@@ -547,16 +548,20 @@ class TestScreen(BaseTest):
s.draw(str(i) * s.columns)
s.start_selection(0, 0)
s.update_selection(4, 4)
expected = ('55555', '\n66666', '\n77777', '\n88888', '\n99999')
self.ae(s.text_for_selection(), expected)
def ts(*args):
return ''.join(s.text_for_selection(*args))
expected = ''.join(('55555', '\n66666', '\n77777', '\n88888', '\n99999'))
self.ae(ts(), expected)
s.scroll(2, True)
self.ae(s.text_for_selection(), expected)
self.ae(ts(), expected)
s.reset()
s.draw('ab cd')
s.start_selection(0, 0)
s.update_selection(1, 3)
self.ae(s.text_for_selection(), ('ab ', 'cd'))
self.ae(s.text_for_selection(False, True), ('ab', 'cd'))
self.ae(ts(), ''.join(('ab ', 'cd')))
self.ae(ts(False, True), ''.join(('ab', 'cd')))
s.reset()
s.draw('ab cd')
s.start_selection(0, 0)
@@ -630,6 +635,22 @@ class TestScreen(BaseTest):
s.draw('bcdef')
self.ae(as_text(s, True), '\x1b[ma\x1b]8;;moo\x1b\\bcde\x1b[mf\n\n\n\x1b]8;;\x1b\\')
def test_wrapping_serialization(self):
from kitty.window import as_text
s = self.create_screen(cols=2, lines=2, scrollback=2, options={'scrollback_pager_history_size': 128})
s.draw('aabbccddeeff')
self.ae(as_text(s, add_history=True), 'aabbccddeeff')
self.assertNotIn('\n', as_text(s, add_history=True, as_ansi=True))
s = self.create_screen(cols=2, lines=2, scrollback=2, options={'scrollback_pager_history_size': 128})
s.draw('1'), s.carriage_return(), s.linefeed()
s.draw('2'), s.carriage_return(), s.linefeed()
s.draw('3'), s.carriage_return(), s.linefeed()
s.draw('4'), s.carriage_return(), s.linefeed()
s.draw('5'), s.carriage_return(), s.linefeed()
s.draw('6'), s.carriage_return(), s.linefeed()
s.draw('7')
self.ae(as_text(s, add_history=True), '1\n2\n3\n4\n5\n6\n7')
def test_pagerhist(self):
hsz = 8
s = self.create_screen(cols=2, lines=2, scrollback=2, options={'scrollback_pager_history_size': hsz})
@@ -666,17 +687,17 @@ class TestScreen(BaseTest):
s = self.create_screen(options={'scrollback_pager_history_size': 2048})
text = '\x1b[msoft\r\x1b[mbreak\nnext😼cat'
w(text)
self.ae(contents(), text + '\n')
self.ae(contents(), text)
s.historybuf.pagerhist_rewrap(2)
self.ae(contents(), '\x1b[mso\rft\x1b[m\rbr\rea\rk\nne\rxt\r😼\rca\rt\n')
self.ae(contents(), '\x1b[mso\rft\x1b[m\rbr\rea\rk\nne\rxt\r😼\rca\rt')
s = self.create_screen(options={'scrollback_pager_history_size': 8})
w('😼')
self.ae(contents(), '😼\n')
self.ae(contents(), '😼')
w('abcd')
self.ae(contents(), '😼abcd\n')
self.ae(contents(), '😼abcd')
w('e')
self.ae(contents(), 'abcde\n')
self.ae(contents(), 'abcde')
def test_user_marking(self):