jupyterlab_terminal_cpr_escape_fix
Fix the JupyterLab terminado issue where returning to an idle terminal causes cursor position report (CPR) escape sequences to appear as literal text. This is particularly noticeable with fish shell, where sequences like [2;2R[3;1R or [?1;2c[>0;276;0c appear at the prompt after reconnecting.
How it works
When a JupyterLab terminal sits idle, the shell (especially fish) periodically queries terminal capabilities. These queries accumulate in terminado's buffer. On reconnect, terminado replays that buffer, xterm.js answers the old queries again, and the shell inserts the answers as literal text.
This extension patches TermSocket.on_pty_read() server-side to filter terminal query responses before they reach the browser. It handles both ESC-prefixed sequences and bare remnants where fish shell has stripped the ESC byte.
Filtered sequences (terminal query responses):
- CPR - Cursor Position Report (
ESC[row;colR) - DA/DA2 - Device Attributes (
ESC[?...c,ESC[>...c) - DECRPM - DEC Report Mode (
ESC[?mode;value$y) - OSC 4/10/11/12 - Color query responses
Preserved sequences (functional terminal output):
- All SGR color codes, cursor movement, erase, scroll
- OSC 0 (window/tab title), OSC 7 (cwd), OSC 8 (hyperlinks)
- OSC 52 (clipboard - used by companion clipboard extension)
- OSC 133 (shell integration prompt marks)
- Bracketed paste mode, alternate screen, all DEC private modes
Repaint on attach (window refresh recovery):
- After a client attaches and the buffer replay drains, the PTY is nudged one row taller and back
- The kernel delivers SIGWINCH, so the foreground app (Claude Code, vim, htop) repaints its full screen
- Without it, a refreshed browser shows a torn screen: the replay holds only incremental diff frames, so static regions (status line, input box) are never delivered and never self-heal
- Toggle:
DEFAULTS['repaint_on_attach']in__init__.py(default on), debounced 5s per terminal
Replay query stripping (no replies on reconnect):
On attach, terminado replays the terminal's buffered output and xterm.js answers every query in it as if it were live, so the shell receives the answers as typed text. The extension removes those queries from the replay only.
- Stripped: OSC 4/10/11/12 color queries, DA/DA2 queries,
ESC[5n,ESC[6n,ESC[?6n, DECRQM, DECRQSS - Queries at the very end of the replay are kept, because the program that sent them may still wait for the answer
- Live output after the attach passes every query unchanged
- Toggle:
DEFAULTS['strip_replay_queries']in__init__.py(default on);suppress_buffer_replaytakes precedence
Requirements
- JupyterLab >= 4.0.0
Installation
pip install jupyterlab_terminal_cpr_escape_fix
Uninstall
pip uninstall jupyterlab_terminal_cpr_escape_fix
Release files for jupyterlab-terminal-cpr-escape-fix 1.0.15
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jupyterlab_terminal_cpr_escape_fix-1.0.15.tar.gz | 470.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jupyterlab_terminal_cpr_escape_fix-1.0.15-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 507.1 kB
Release files / jupyterlab_terminal_cpr_escape_fix-1.0.15.tar.gz
| Download URL | jupyterlab_terminal_cpr_escape_fix-1.0.15.tar.gz |
|---|---|
| Size | 470.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a92cff62a56e3ab6f6cdbcdee3e5ed82c862c519943cbf8e9fe2d18d6e6f38f4
|
|
BLAKE2b-256 checksum How to use checksums |
7602146b5536b969be182b679d637abfea368704b49a47df86fcfa8bf56ca5b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Release files / jupyterlab_terminal_cpr_escape_fix-1.0.15-py3-none-any.whl
| Download URL | jupyterlab_terminal_cpr_escape_fix-1.0.15-py3-none-any.whl |
|---|---|
| Size | 36.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4e515459785a25736013f3d4b5b6704103a0d0f96f338d606843167cbc42e354
|
|
BLAKE2b-256 checksum How to use checksums |
5f81754af6b10d8c36fe67cb06dedd7baa42104183e18bcb9a1bd0e158c622ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|