prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.11k stars 718 forks source link

Support for XTerm `REPORT` Window Operations CSI queries #1723

Open arcivanov opened 1 year ago

arcivanov commented 1 year ago

Is there a way to support CSI queries such as CSI 14 t and CSI 16 t?

The output they produce is:

$ echo -n $'\x1b[14t'
^[[4;969;1872t
$ echo -n $'\x1b[16t'
^[[6;17;8t

Being able to intercept the response to control sequences would be very helpful.

arcivanov commented 1 year ago

Reference: https://tintin.mudhalla.net/info/xterm/

arcivanov commented 1 year ago

Another old reference: P s = 1 4 → Report xterm window in pixels as CSI 4 ; height ; width t https://www.xfree86.org/current/ctlseqs.html https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

arcivanov commented 1 year ago
            Ps = 1 1  ⇒  Report xterm window state.
          If the xterm window is non-iconified, it returns CSI 1 t .
          If the xterm window is iconified, it returns CSI 2 t .
            Ps = 1 3  ⇒  Report xterm window position.
          Note: X Toolkit positions can be negative, but the reported
          values are unsigned, in the range 0-65535.  Negative values
          correspond to 32768-65535.
          Result is CSI 3 ; x ; y t
            Ps = 1 3 ;  2  ⇒  Report xterm text-area position.
          Result is CSI 3 ; x ; y t
            Ps = 1 4  ⇒  Report xterm text area size in pixels.
          Result is CSI  4 ;  height ;  width t
            Ps = 1 4 ;  2  ⇒  Report xterm window size in pixels.
          Normally xterm's window is larger than its text area, since it
          includes the frame (or decoration) applied by the window
          manager, as well as the area used by a scroll-bar.
          Result is CSI  4 ;  height ;  width t
            Ps = 1 5  ⇒  Report size of the screen in pixels.
          Result is CSI  5 ;  height ;  width t
            Ps = 1 6  ⇒  Report xterm character cell size in pixels.
          Result is CSI  6 ;  height ;  width t
            Ps = 1 8  ⇒  Report the size of the text area in characters.
          Result is CSI  8 ;  height ;  width t
            Ps = 1 9  ⇒  Report the size of the screen in characters.
          Result is CSI  9 ;  height ;  width t
joouha commented 1 year ago

I did this in my project euporie.

prompt_toolkit already recognises escape sequences responses for cursor-position requests and mouse events, so the machinery is there, but there is no accessible API to add support for addition escape sequence responses, so you have to get a bit hacky.

To do this, you'd need to create a new special "Key" definition for each escape sequence response you want to recognise. Since prompt_toolkit.keys.Keys is an enum, I had to use the aenum.extend_enum to modify it.

I then sub-classed and monkey-patched parts of the Vt100Parser in order to respond when an escape sequence response matched a given regex (see here), and emitted the new custom key for the recognised escape sequence response. You can then create a key-binding for the new key, and parse the key-event's data.

In the end I ended up with a system for querying various terminal features, by sending escape sequences and listening for and parsing the responses using prompt_toolkit's input/output machinery (see here)

It would be very nice to have a user-facing API for this in prompt_toolkit, but this would require some not insignificant changes.

arcivanov commented 1 year ago

@joouha I actually started a PR on this already exactly via the above methodology.