fix(input): discard unrecognised CSI sequences instead of typing them - #6
Open
basil-k-aji-dev wants to merge 1 commit into
Open
basil-k-aji-dev wants to merge 1 commit into
basil-k-aji-dev wants to merge 1 commit into
Conversation
TerminalEventParser recognised only a small set of CSI sequences. SGR colour sequences such as \x1b[31m matched none of them, which failed two ways depending on timing. Before ESCAPE_DELAY elapsed the parse loop broke and left the sequence buffered, stalling every byte behind it. The session read loop only calls flush() when select() times out, so during a paste feed() runs back to back and the residue is never cleared; once it crossed the 8192 guard the ValueError propagated out of the input worker and ended the session. Roughly 8KB of coloured text — git diff output, coloured logs — was enough. After the delay the ESC fallback removed only the ESC byte and emitted an ESCAPE key, leaving "[31m" to be parsed as ordinary characters and typed at the remote host. Add CSI_ANY_RE, matching a complete CSI sequence, and consume it once every specific handler has declined. Partial sequences still buffer as before, so split reads keep working. Fixes rylena#5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5
TerminalEventParserrecognised only a small set of CSI sequences. SGR colour sequences —\x1b[31m,\x1b[0m— matched none of them, and failed two different ways depending on timing.Typed at the remote host. After
ESCAPE_DELAYthe ESC fallback diddel self.buffer[0], removing only the ESC byte and emitting an ESCAPE key. The remaining[31mwas then parsed as ordinary characters, so a single colour sequence produced five keystrokes:Ended the session. Before the delay elapsed the loop
breaks and left the sequence buffered, stalling every byte behind it. The read loop insession/direct.pyonly callsflush()whenselect()times out, so during a pastefeed()runs back to back and the residue is never cleared. Once it crossed the 8192 guard:That propagates out of
_input_worker, which forwards it viaself._controls.put(exc), and the main loop re-raises it withraise control. About 8 KB of coloured text is enough —git diffoutput, coloured logs, anything copied from another terminal.Change
CSI_ANY_REmatches a complete CSI sequence (ESC [, parameter bytes0x30–0x3f, intermediate bytes0x20–0x2f, final byte0x40–0x7e). It is consulted only after every specific handler has declined, so a sequence this parser does not act on is discarded rather than buffered or retyped.It sits after the existing incomplete-sequence check, so partial sequences still buffer and split reads keep working —
feed(b"\x1b[12;")thenfeed(b"40R")still yields one cursor report.Tests
Four added to
tests/test_input.py. The first three fail onmain:with the first showing exactly the spurious keystrokes:
The fourth guards against regressing arrow keys, cursor reports and partial-sequence buffering.
pytest -q tests/— 92 passed (88 before).ruff checkclean on both changed files. Python 3.13.3, Linux aarch64.Note
The 8192 guard is left as it is. It still measures the whole buffer before parsing rather than the residue after it, so it can in principle fire on input that is merely unconsumed rather than on one oversized sequence — but with unknown CSI sequences no longer accumulating, I could not reach it with realistic input. Tightening it to check after the parse loop would match the wording of its message; happy to include that here if you would prefer.