ANSI output: Preserve use of natural_width

Keeps semantics of the text the same when roundtripping rather than
visual appearance.
This commit is contained in:
Kovid Goyal
2025-02-15 11:03:20 +05:30
parent 888b8a3bfb
commit 0e820f5d9c
2 changed files with 18 additions and 14 deletions

View File

@@ -66,7 +66,9 @@ write_multicell_ansi_prefix(ANSILineState *s, const CPUCell *mcd) {
w(0x1b); w(']');
for (unsigned i = 0; i < sizeof(xstr(TEXT_SIZE_CODE)) - 1; i++) w(xstr(TEXT_SIZE_CODE)[i]);
w(';');
w('w'); w('='); nonnegative_integer_as_utf32(mcd->width, s->output_buf); w(':');
if (!mcd->natural_width) {
w('w'); w('='); nonnegative_integer_as_utf32(mcd->width, s->output_buf); w(':');
}
if (mcd->scale > 1) {
w('s'); w('='); nonnegative_integer_as_utf32(mcd->scale, s->output_buf); w(':');
}

View File

@@ -405,7 +405,7 @@ def test_multicell(self: TestMulticell) -> None:
s.erase_in_display(22)
assert_line('ab_c\0\0', -2)
assert_line('\0__\0\0\0', -1)
self.ae(s.historybuf.line(1).as_ansi(), f'a\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07c')
self.ae(s.historybuf.line(1).as_ansi(), f'a\x1b]{TEXT_SIZE_CODE};s=2;b\x07c')
self.ae(s.historybuf.line(0).as_ansi(), ' ')
# Insert lines
@@ -455,14 +455,16 @@ def test_multicell(self: TestMulticell) -> None:
ta('a\x1b[38:2:255:255:255mb')
multicell(s, 'a', scale=2)
multicell(s, 'b', scale=2)
ta('\x1b]66;w=1:s=2;ab\x07')
ta('\x1b]66;s=2;ab\x07')
multicell(s, '😀a', scale=2)
ta('\x1b]66;s=2;😀a\x07')
multicell(s, 'a', scale=2)
s.cursor.fg = as_rgb(0xffffff)
multicell(s, 'b', scale=2)
ta('\x1b]66;w=1:s=2;a\x07\x1b[38:2:255:255:255m\x1b]66;w=1:s=2;b\x07\n\x1b[m\x1b[38:2:255:255:255m')
ta('\x1b]66;s=2;a\x07\x1b[38:2:255:255:255m\x1b]66;s=2;b\x07\n\x1b[m\x1b[38:2:255:255:255m')
multicell(s, 'a', scale=3)
multicell(s, 'b', scale=2)
ta('\x1b]66;w=1:s=3;a\x07\x1b]66;w=1:s=2;b\x07')
ta('\x1b]66;s=3;a\x07\x1b]66;s=2;b\x07')
# rewrap with multicells
s = self.create_screen(cols=6, lines=6, scrollback=20)
@@ -516,14 +518,14 @@ def test_multicell(self: TestMulticell) -> None:
reset()
multicell(s, 'a', scale=3), s.draw('b'*(s.columns-3))
resize(s.lines, s.columns-1, 5, 0)
self.ae('\x1b[m\x1b]66;w=1:s=3;a\x07bb\x1b[mb', as_ansi().rstrip()) # ]]
self.ae('\x1b[m\x1b]66;s=3;a\x07bb\x1b[mb', as_ansi().rstrip()) # ]]
ac(0, 0, is_multicell=True)
ac(0, 1, is_multicell=True)
ac(3, 1, is_multicell=False, text='b')
reset()
s.draw('X'), multicell(s, 'a', scale=3), s.draw('12345')
resize(s.lines, s.columns-1, 4, 0)
self.ae('\x1b[mX\x1b]66;w=1:s=3;a\x071\x1b[m23\x1b[m45', as_ansi().rstrip()) # ]]
self.ae('\x1b[mX\x1b]66;s=3;a\x071\x1b[m23\x1b[m45', as_ansi().rstrip()) # ]]
for y in (0, 1):
ac(0, y, is_multicell=False), ac(1, y, is_multicell=True), ac(3, y, is_multicell=True)
ac(0, 1, is_multicell=False, text='2'), ac(4, 1, is_multicell=False, text='3')
@@ -549,7 +551,7 @@ def test_multicell(self: TestMulticell) -> None:
reset()
s.draw('a'*(s.columns - 1)), multicell(s, 'X', scale=2), s.draw('bcd')
resize(s.lines, s.columns + 1, 0, 2)
self.ae('\x1b[maaaaa\x1b]66;w=1:s=2;X\x07\x1b[mbcd', as_ansi().rstrip()) # ]]]]]]]
self.ae('\x1b[maaaaa\x1b]66;s=2;X\x07\x1b[mbcd', as_ansi().rstrip()) # ]]]]]]]
for y in (0, 1):
for x in (1, 2):
ac(s.columns-x, y, is_multicell=True)
@@ -558,7 +560,7 @@ def test_multicell(self: TestMulticell) -> None:
reset()
s.draw('a'*(s.columns - 1)), multicell(s, 'X', scale=2), s.draw('bcd1234!')
s.resize(s.lines, s.columns + 2)
self.ae('\x1b[maaaaa\x1b]66;w=1:s=2;X\x07b\x1b[mcd1234\x1b[m!', as_ansi().rstrip()) # ]]]]]]]
self.ae('\x1b[maaaaa\x1b]66;s=2;X\x07b\x1b[mcd1234\x1b[m!', as_ansi().rstrip()) # ]]]]]]]
for y in (0, 1):
for x in (1, 2):
ac(s.columns-x -1, y, is_multicell=True)
@@ -660,15 +662,15 @@ def test_multicell(self: TestMulticell) -> None:
ss(p(), p(x=4, in_left_half_of_cell=False))
asl((0, 0, 5), (1, 1, 2), (1, 4, 5))
ast('abcd')
asa(f'a\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07c\x1b]{TEXT_SIZE_CODE};w=1:s=2;d\x07', '\x1b[m')
asa(f'a\x1b]{TEXT_SIZE_CODE};s=2;b\x07c\x1b]{TEXT_SIZE_CODE};s=2;d\x07', '\x1b[m')
ss(p(y=1, x=1), p(y=1, x=1, in_left_half_of_cell=False))
asl((0, 1, 2), (1, 1, 2))
ast('b')
asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07', '\x1b[m')
asa(f'\x1b]{TEXT_SIZE_CODE};s=2;b\x07', '\x1b[m')
ss(p(y=1, x=0), p(y=1, x=1, in_left_half_of_cell=False)) # empty leading cell before multiline on y=1
asl((0, 1, 2), (1, 0, 2))
ast('b')
asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07', '\x1b[m')
asa(f'\x1b]{TEXT_SIZE_CODE};s=2;b\x07', '\x1b[m')
s.reset()
multicell(s, 'X', scale=2), s.draw('123456abcd')
@@ -676,11 +678,11 @@ def test_multicell(self: TestMulticell) -> None:
ss(p(x=x), p(x=3, y=1, in_left_half_of_cell=False))
asl((0, 0, 7), (1, 0, 3))
ast('X123456', 'ab')
asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;X\x07123456', 'ab', '\x1b[m')
asa(f'\x1b]{TEXT_SIZE_CODE};s=2;X\x07123456', 'ab', '\x1b[m')
ss(p(y=1), p(y=1, x=3, in_left_half_of_cell=False))
asl((0, 0, 1), (1, 0, 3))
ast('X', 'ab')
asa(f'\x1b]{TEXT_SIZE_CODE};w=1:s=2;X\x07', 'ab', '\x1b[m')
asa(f'\x1b]{TEXT_SIZE_CODE};s=2;X\x07', 'ab', '\x1b[m')
s = self.create_screen(lines=5, cols=24)