Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions pyte/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class Stream:
}

#: CSI escape sequences -- ``CSI P1;P2;...;Pn <fn>``.
# Note that Pn can contain digits or `:`
csi = {
esc.ICH: "insert_characters",
esc.CUU: "cursor_up",
Expand Down Expand Up @@ -306,10 +307,14 @@ def create_dispatcher(mapping: Mapping[str, str]) -> Dict[str, Callable[..., Non
basic_dispatch[char]()
elif char == CSI_C1:
# All parameters are unsigned, positive decimal integers, with
# the most significant digit sent first. Any parameter greater
# the most significant digit sent first*. Any parameter greater
# than 9999 is set to 9999. If you do not specify a value, a 0
# value is assumed.
#
# *Not entirely true: Some SGR parameters allow `:`-delimited additional
# subparameters. These additional subparameters are a list of positive decimal integers
# following the above rules.
#
# .. seealso::
#
# `VT102 User Guide <http://vt100.net/docs/vt102-ug/>`_
Expand All @@ -318,8 +323,12 @@ def create_dispatcher(mapping: Mapping[str, str]) -> Dict[str, Callable[..., Non
# `VT220 Programmer Ref. <http://vt100.net/docs/vt220-rm/>`_
# For details on the characters valid for use as
# arguments.
#
# `XTerm <https://invisible-island.net/xterm/xterm.faq.html#color_by_number>`_
# "Using semicolon was incorrect because [...]"
#
params = []
current = ""
param_with_subparameters = [0]
private = False
while True:
char = yield None
Expand All @@ -337,17 +346,24 @@ def create_dispatcher(mapping: Mapping[str, str]) -> Dict[str, Callable[..., Non
draw(char)
break
elif char.isdigit():
current += char
digit_value = ord(char) - ord("0")
param_with_subparameters[-1] = min(param_with_subparameters[-1] * 10 + digit_value, 9999)
elif char == ":":
param_with_subparameters.append(0)
elif char == "$":
# XTerm-specific ESC]...$[a-z] sequences are not
# currently supported.
yield None
break
else:
params.append(min(int(current or 0), 9999))
# Note: pyte currently doesn't support subparameters.
# Ideally, we'd update SGR handling to be aware of it.
# That's tracked by <https://github.com/selectel/pyte/issues/179>.
current_param, *_subparameters = param_with_subparameters
params.append(current_param)

if char == ";":
current = ""
param_with_subparameters = [0]
else:
if private:
csi_dispatch[char](*params, private=True)
Expand Down
13 changes: 13 additions & 0 deletions tests/test_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ def test_unknown_sequences():
assert handler.args == (6, 0)
assert handler.kwargs == {}

def test_csi_param_with_colon_context():
handler = argcheck()
screen = pyte.Screen(80, 24)
screen.debug = handler

stream = pyte.Stream(screen)
stream.feed(ctrl.CSI + "6:4Z")
assert handler.count == 1
# Note: currently pyte doesn't actually do anything with `:`-delimited context,
# which is why the `4` disappears here.
assert handler.args == ((6),)
assert handler.kwargs == {}


def test_non_csi_sequences():
for cmd, event in pyte.Stream.csi.items():
Expand Down