End DCS/OSC strings at any ESC, default the external terminal to Terminal.app
A string with no ST swallowed every later sequence, RIS included, and Clear Screen could not recover the tab. Any ESC now ends it, as in xterm, and the sequence it starts is dispatched. The shipped setting needed Kitty. Also: REP, SCOSC/SCORC, DECOM-relative CPR, `:` subparams and more DECRQM modes answered; new rows inserted in one edit; controls stripped from pastes; wide-char mouse columns.
This commit is contained in:
@@ -454,8 +454,67 @@ def run_clear_cases():
|
||||
print("all clear-screen tests passed")
|
||||
|
||||
|
||||
def run_parser_edge_cases():
|
||||
"""Sequences the stock collector misread: intermediates, `:` subparams, REP, marks."""
|
||||
for char_by_char in (False, True):
|
||||
tag = "char-by-char" if char_by_char else "chunked"
|
||||
|
||||
# DECSTR (`reset` sends it): `!` is an intermediate, the `p` must not be drawn
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "\x1b[!pX", char_by_char)
|
||||
assert screen.display[0].rstrip() == "X", (tag, repr(screen.display[0]))
|
||||
|
||||
# `4:3` is curly underline, not SGR 43 (yellow background)
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "\x1b[4:3mX\x1b[38:2:1:2:3mY", char_by_char)
|
||||
cell = screen.buffer[0][0]
|
||||
assert (cell.bg, cell.underscore) == ("default", True), (tag, cell)
|
||||
assert screen.buffer[0][1].data == "Y", (tag, screen.buffer[0][1])
|
||||
|
||||
# REP repeats the last printable; ncurses emits it for runs
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "a\x1b[3b\x1b[31mb\x1b[b", char_by_char)
|
||||
assert screen.display[0].rstrip() == "aaaabb", (tag, repr(screen.display[0]))
|
||||
assert screen.buffer[0][5].fg == "red", (tag, screen.buffer[0][5])
|
||||
|
||||
# a Thai vowel sign has combining class 0 but is still a mark: merged, not dropped
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "\u0e01\u0e31x", char_by_char)
|
||||
assert screen.buffer[0][0].data == "\u0e01\u0e31", (tag, screen.buffer[0][0])
|
||||
assert screen.buffer[0][1].data == "x", (tag, screen.buffer[0][1])
|
||||
|
||||
# DECRQM: the modes we honour answer set/reset, never "unrecognized"
|
||||
proc, screen, stream = make()
|
||||
feed(stream, "\x1b[?2031$p\x1b[?1h\x1b[?1$p\x1b[4$p\x1b[20$p", char_by_char)
|
||||
assert proc.written == "\x1b[?2031;2$y\x1b[?1;1$y\x1b[4;2$y\x1b[20;2$y", (tag, proc.written)
|
||||
|
||||
# RIS on the alternate screen lands back on a cleared primary screen
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "primary\x1b[?1049halt\x1bc", char_by_char)
|
||||
assert not screen.alternate_buffer_mode and not screen.savepoints, tag
|
||||
assert screen.display[0].strip() == "", (tag, repr(screen.display[0]))
|
||||
feed(stream, "\r\n" * 4, char_by_char)
|
||||
assert len(screen.history) == 1, (tag, len(screen.history))
|
||||
|
||||
# SCOSC/SCORC, and CPR relative to the region under DECOM
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "ab\x1b[s\x1b[3;3H\x1b[uX\x1b[2;3r\x1b[?6h\x1b[6n", char_by_char)
|
||||
assert screen.display[0].rstrip() == "abX", (tag, repr(screen.display[0]))
|
||||
assert proc.written == "\x1b[1;1R", (tag, proc.written)
|
||||
|
||||
# a string with no terminator ends at the next ESC, as in xterm; a stray
|
||||
# ESC P from a binary must not swallow the rest of the session
|
||||
proc, screen, stream = make(20, 4)
|
||||
feed(stream, "\x1bPgarbage\x1bcX\x1b]0;title\x1b[1mY", char_by_char)
|
||||
assert screen.display[0].rstrip() == "XY", (tag, repr(screen.display[0]))
|
||||
assert screen.title == "title" and screen.buffer[0][1].bold, (tag, screen.title)
|
||||
|
||||
print("all parser edge-case tests passed")
|
||||
|
||||
|
||||
run_case(char_by_char=False)
|
||||
run_case(char_by_char=True)
|
||||
run_parser_edge_cases()
|
||||
run_clear_cases()
|
||||
run_resize_cases()
|
||||
run_private_csi_cases()
|
||||
|
||||
Reference in New Issue
Block a user