Multicell selections: Clamp to line

When the end point of the selection is within a multicell character of
the same size and vertical position as the start point, clamp the
selection line to the start line to avoid un-intuitive multiline
selections.

Fixes #8310
This commit is contained in:
Kovid Goyal
2025-02-15 13:07:48 +05:30
parent dc5c9b5bf4
commit b4b2b44c92
2 changed files with 57 additions and 17 deletions

View File

@@ -444,30 +444,30 @@ def test_multicell(self: TestMulticell) -> None:
s.reset()
multicell(s, 'a', width=2, scale=3, subscale_n=1, subscale_d=2, vertical_align=1)
ta('\x1b]66;w=2:s=3:n=1:d=2:v=1;a\x07')
ta(f'\x1b]{TEXT_SIZE_CODE};w=2:s=3:n=1:d=2:v=1;a\x07')
s.draw('a')
multicell(s, 'b', width=2)
s.draw('c')
ta('a\x1b]66;w=2;b\x07c')
ta(f'a\x1b]{TEXT_SIZE_CODE};w=2;b\x07c')
multicell(s, 'a')
s.cursor.fg = as_rgb(0xffffff)
multicell(s, 'b')
ta('a\x1b[38:2:255:255:255mb')
multicell(s, 'a', scale=2)
multicell(s, 'b', scale=2)
ta('\x1b]66;s=2;ab\x07')
ta(f'\x1b]{TEXT_SIZE_CODE};s=2;ab\x07')
multicell(s, '😀a', scale=2)
ta('\x1b]66;s=2;😀a\x07')
ta(f'\x1b]{TEXT_SIZE_CODE};s=2;😀a\x07')
multicell(s, '😀', scale=2)
multicell(s, 'b', width=1, scale=2)
ta('\x1b]66;s=2;😀\x07\x1b]66;w=1:s=2;b\x07')
ta(f'\x1b]{TEXT_SIZE_CODE};s=2;😀\x07\x1b]{TEXT_SIZE_CODE};w=1:s=2;b\x07')
multicell(s, 'a', scale=2)
s.cursor.fg = as_rgb(0xffffff)
multicell(s, 'b', scale=2)
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')
ta(f'\x1b]{TEXT_SIZE_CODE};s=2;a\x07\x1b[38:2:255:255:255m\x1b]{TEXT_SIZE_CODE};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;s=3;a\x07\x1b]66;s=2;b\x07')
ta(f'\x1b]{TEXT_SIZE_CODE};s=3;a\x07\x1b]{TEXT_SIZE_CODE};s=2;b\x07')
# rewrap with multicells
s = self.create_screen(cols=6, lines=6, scrollback=20)
@@ -521,14 +521,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;s=3;a\x07bb\x1b[mb', as_ansi().rstrip()) # ]]
self.ae(f'\x1b[m\x1b]{TEXT_SIZE_CODE};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;s=3;a\x071\x1b[m23\x1b[m45', as_ansi().rstrip()) # ]]
self.ae(f'\x1b[mX\x1b]{TEXT_SIZE_CODE};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')
@@ -554,7 +554,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;s=2;X\x07\x1b[mbcd', as_ansi().rstrip()) # ]]]]]]]
self.ae(f'\x1b[maaaaa\x1b]{TEXT_SIZE_CODE};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)
@@ -563,7 +563,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;s=2;X\x07b\x1b[mcd1234\x1b[m!', as_ansi().rstrip()) # ]]]]]]]
self.ae(f'\x1b[maaaaa\x1b]{TEXT_SIZE_CODE};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)
@@ -692,7 +692,13 @@ def test_multicell(self: TestMulticell) -> None:
s.reset()
multicell(s, 'ab cd ef', scale=2)
ss(p(6, 1), p(9, 0, in_left_half_of_cell=False))
ast('ab ef')
ast('cd')
asa(f'\x1b]{TEXT_SIZE_CODE};s=2;cd\x07', '\x1b[m')
s.reset()
multicell(s, 'ab', scale=2), s.draw(' '), multicell(s, 'cd', scale=2), s.draw(' '), multicell(s, 'ef', scale=2)
ss(p(6, 1), p(9, 0, in_left_half_of_cell=False))
ast('cd')
# Hyperlinks
s = self.create_screen(lines=5, cols=8)