Pure scanner for a DSR-6 cursor position report (CPR — CSI Pr ; Pc R,
the reply a terminal sends to CSI 6n) inside a raw tty input stream.
Extracted from Raxol.Terminal.InlineDriver.probe_cursor/2's receive
loop so the byte-boundary contract is unit-testable with zero
process/device setup:
- The CPR itself is consumed — split out of the stream so it can
never reach
Raxol.Terminal.ANSI.InputParser(which would decode a row-1 reply,\e[1;<n>R, as a modified F3 keypress — the classic DSR/F3 wire collision — and deliver a phantom key event to the app). - Every other byte is preserved in arrival order — real
keystrokes interleaved with (or split around) the reply are handed
back for normal dispatch, never dropped (the same leak-free rule
the T1 capability probe's
{:leak_free, _}action enforces). - The held-back tail is bounded — at most 12 bytes (the
longest possible CPR is
\e[9999;9999R, 12 bytes) are ever kept waiting for a continuation chunk, so a flooding device cannot grow the probe buffer: everything already scanned past is flushed forward immediately.
The scan is byte-oriented (no /u regex, no String walking): raw tty
input is untrusted binary and may contain invalid UTF-8, 8-bit C1
controls, or anything else — none of which may crash the scanner.
Summary
Types
1-based {row, col} as reported by the terminal.
Functions
Scans buffer for a complete CPR.
Types
@type position() :: {pos_integer(), pos_integer()}
1-based {row, col} as reported by the terminal.
Functions
Scans buffer for a complete CPR.
{:reply, {row, col}, leading, trailing}— a CPR was found.leading/trailingare the non-CPR bytes before/after it, in arrival order, for normal input dispatch. The CPR bytes themselves appear in neither.{:pending, forward, keep}— no complete CPR yet.forwardis safe to dispatch as ordinary input NOW;keep(at most 12 bytes, possibly empty) is the tail that could still be the start of a CPR split across chunks — prepend it to the next chunk and scan again (or dispatch it as ordinary input once the probe deadline lapses).
A 0 row or column (\e[0;0R — not a screen position any 1-based
terminal can report) is rejected as a reply and forwarded as ordinary
input; scanning continues past it.