mirror of
https://github.com/tmux/tmux.git
synced 2026-10-15 07:44:24 +00:00
134 lines
5.3 KiB
Python
134 lines
5.3 KiB
Python
"""PTY checks adapted from the PR's image scroll regressions."""
|
|
|
|
import re
|
|
from image_test import image_test, sixel, check_image
|
|
from image_terminal import Terminal
|
|
|
|
|
|
MARKER = b'SCROLLMARKER'
|
|
WIRE = sixel(16, 16, [(100, 0, 0), (0, 100, 0)],
|
|
[x >= 8 for y in range(16) for x in range(16)])
|
|
|
|
|
|
def attach(test, scrolls, margins=None, term='xterm-256color'):
|
|
"""Choose scroll features before attaching a client."""
|
|
features = [term, 'imagescroll' if scrolls else 'imagescroll@']
|
|
if margins is not None:
|
|
features.append('margins' if margins else 'margins@')
|
|
test.run('set-option', '-as', 'terminal-features', ':'.join(features))
|
|
client = test.attach(term=term)
|
|
prefix = str(client.pid) + ':'
|
|
actual = next(line[len(prefix):] for line in test.run('list-clients',
|
|
'-F', '#{client_pid}:#{client_termfeatures}').splitlines()
|
|
if line.startswith(prefix)).split(',')
|
|
assert ('imagescroll' in actual) == scrolls, actual
|
|
if margins is not None:
|
|
assert ('margins' in actual) == margins, actual
|
|
return client
|
|
|
|
|
|
def place(test):
|
|
"""Place marker text and a two-colour image away from the scroll edges."""
|
|
test.emit(b'\033[7;1H' + MARKER + b'\033[9;3H' + WIRE + b'\033[16;1H')
|
|
for client in test.clients:
|
|
images = client.images()
|
|
assert len(images) == 1, 'initial image was not sent'
|
|
check_image(images[0], 16, 16,
|
|
[(255, 0, 0) if x < 8 else (0, 255, 0)
|
|
for y in range(16) for x in range(16)])
|
|
|
|
|
|
def check_output(client, replay):
|
|
"""Check whether scroll damage replayed the image and surrounding text."""
|
|
data = bytes(client.data)
|
|
if replay:
|
|
assert client.images(), 'image was not replayed after a manual repaint'
|
|
assert MARKER in data, 'scroll damage did not repaint surrounding text'
|
|
else:
|
|
assert not client.images(), 'native scroll replayed the image'
|
|
assert MARKER not in data, 'native scroll repainted existing text'
|
|
return data
|
|
|
|
|
|
def check_position(test, mixed=False, down=False):
|
|
"""A later full redraw must show the scrolled image at its new position."""
|
|
test.redraw()
|
|
row = 9 if down else 7
|
|
expected = {(x, y): (255, 0, 0) if x < 24 else (0, 255, 0)
|
|
for y in range(row * 16, (row + 1) * 16) for x in range(16, 32)
|
|
if not mixed or x >= 24}
|
|
for client in test.clients:
|
|
terminal = Terminal()
|
|
terminal.feed(client.data)
|
|
terminal.check(expected)
|
|
|
|
|
|
def check_scroll(tmux, scrolls, margins=None, no_erase=False, mixed=False,
|
|
command='linefeed'):
|
|
"""Check one client's native scroll or fallback repaint."""
|
|
with image_test(tmux) as test:
|
|
test.run('set-option', '-w', 'automatic-rename', 'off')
|
|
if margins is not None:
|
|
test.run('set-option', '-w', 'pane-scrollbars', 'on')
|
|
client = attach(test, scrolls, margins)
|
|
place(test)
|
|
if no_erase:
|
|
test.redraw()
|
|
terminal = Terminal()
|
|
terminal.feed(client.data)
|
|
operation = {'linefeed': b'\n', 'up': b'\033[S', 'down': b'\033[T',
|
|
'reverse': b'\033[H\033M'}[command]
|
|
if mixed:
|
|
# An ordinary overwrite must prevent skipping merged scroll damage.
|
|
operation += b'\033[8;3HX'
|
|
test.emit(operation)
|
|
replay = not scrolls or margins is False or mixed
|
|
data = check_output(client, replay)
|
|
if no_erase:
|
|
# Erasing the newly exposed bottom row is valid. Check that
|
|
# none of the moved image pixels were erased or drawn over.
|
|
terminal.feed(data)
|
|
terminal.check({(x, y): (255, 0, 0) if x < 24 else (0, 255, 0)
|
|
for y in range(7 * 16, 8 * 16) for x in range(16, 32)})
|
|
if scrolls and margins:
|
|
assert re.search(rb'\033\[\d+;\d+s', data), (
|
|
'no horizontal scrolling region was set', data)
|
|
check_position(test, mixed, command in ('down', 'reverse'))
|
|
|
|
|
|
def check_clients(tmux, narrow=False):
|
|
"""Check different client capabilities and shared fallback damage."""
|
|
with image_test(tmux) as test:
|
|
test.run('set-option', '-w', 'automatic-rename', 'off')
|
|
if narrow:
|
|
test.run('set-option', '-w', 'pane-scrollbars', 'on')
|
|
native = attach(test, True, True)
|
|
repaint = attach(test, True, False, term='xterm')
|
|
else:
|
|
native = attach(test, True)
|
|
repaint = attach(test, False, term='xterm')
|
|
place(test)
|
|
test.emit(b'\n')
|
|
# A large fallback repaint adds ordinary window damage, which must
|
|
# be drawn on both clients even if the first scrolled natively.
|
|
check_output(native, narrow)
|
|
check_output(repaint, True)
|
|
check_position(test)
|
|
|
|
|
|
def check_capability(tmux, enabled):
|
|
"""Iscrl grants image scrolling, and Iscrl@ overrides an enabled feature."""
|
|
with image_test(tmux) as test:
|
|
test.run('set-option', '-w', 'automatic-rename', 'off')
|
|
capability = 'Iscrl' if enabled else 'Iscrl@'
|
|
test.run('set-option', '-as', 'terminal-overrides',
|
|
'xterm-256color:' + capability)
|
|
if not enabled:
|
|
test.run('set-option', '-as', 'terminal-features',
|
|
'xterm-256color:imagescroll')
|
|
client = test.attach()
|
|
place(test)
|
|
test.emit(b'\n')
|
|
check_output(client, not enabled)
|
|
check_position(test)
|