DECRQDE / DECRPDE — Request / Report Displayed Extent (`CSI " v` / `" w`)
VT420+ pagination query — ask the terminal how many rows / columns are currently displayed and where the scroll window sits inside the page memory. Reply tells the host the visible viewport without relying on `tput lines / cols`.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b["v DECRQDE (request)\n\x1b[<Ph>;<Pw>;<Pml>;<Pmt>;<Pmp>"w DECRPDE (reply)\033["v / \033[<Ph>;<Pw>;<Pml>;<Pmt>;<Pmp>"w\e["v / \e[<Ph>;<Pw>;<Pml>;<Pmt>;<Pmp>"wESC [ " v / ESC [ Ph ; Pw ; Pml ; Pmt ; Pmp " w1b 5b 22 76 / 1b 5b … 22 77Description
**DECRQDE** (*Request Displayed Extent*, `\x1b["v`) asks the terminal to describe the *visible viewport into its page memory*. The reply (**DECRPDE**, `\x1b[Ph;Pw;Pml;Pmt;Pmp"w`) carries five numbers: - **Ph** — number of rows visible in the viewport (almost always the terminal height). - **Pw** — number of columns visible (almost always the terminal width). - **Pml** — left margin column within the page (1-indexed; the leftmost column of the viewport relative to the page memory). - **Pmt** — top row of the viewport within the page memory (1-indexed; usually `1` unless the page is taller than the screen and scrolled). - **Pmp** — page number of the active page (1 on every single-page emulator; only meaningful on DEC VT525 with multi-page memory). **Why a separate query exists**: on classic DEC VT420/VT525 hardware, *page memory* could be larger than the screen — the terminal owned, say, 480 rows of buffer but only displayed 24 at a time, and the host needed to know what slice was on screen without redrawing. The query is the round-trip companion to **DECSCPP** (set columns-per-page) and **DECSLPP** (set lines-per-page) — host sets the geometry, terminal acknowledges via DECRPDE. **Modern usage**: in 2026, almost every emulator has a single page == single viewport == single screen-size buffer, so the reply is degenerate — `Ph` matches `LINES`, `Pw` matches `COLUMNS`, `Pml`/`Pmt`/`Pmp` are `1`. The *useful* role today is as a **feature probe**: terminals that reply at all are advertising VT420-class compatibility, which strongly correlates with support for DECRQTSR / DECRSTS, DECCARA, and the rectangle ops family. Programs that need to gate on 'real VT420 lineage' send `\x1b["v` and treat any reply as 'go'. **Reading the reply safely** - Emit `\x1b["v` to stdout. - Read from stdin with a 50–150 ms timeout. On no-reply terminals (most modern emulators), the timeout fires and you assume *no VT420 support*. - Parse `\x1b\[([0-9]+);([0-9]+);([0-9]+);([0-9]+);([0-9]+)"w` — anchored on the leading CSI and the final `"w` to avoid mis-framing on slow connections that interleave with user input. - **Critical**: terminals can prepend or append other reports if multiple queries are in flight — match the `"w` final byte, not position. **Coverage**: **xterm** = full (reference implementation). **mlterm** + **Konsole** + **gnome-terminal** = full. **WezTerm** = partial (replies, but `Pmt` always `1` regardless of actual scroll). **iTerm2** = no-op (silently consumed). **Kitty** + **Alacritty** + **Ghostty** + **Windows Terminal** + **cmd / ConPTY** + **macOS Terminal** + **Linux console** = no-op. The query is safe to emit unconditionally — non-replying terminals ignore the bytes; replying ones produce 5 small decimal fields parseable in < 30 bytes.
Spec citation: DEC VT420 / VT525 RM (DECRQDE / DECRPDE) / xterm-ctlseqs (CSI " v / " w)
Parameters
| Ph | Reply field: rows visible in the viewport. |
| Pw | Reply field: columns visible in the viewport. |
| Pml | Reply field: leftmost column of the viewport within page memory (1-indexed). |
| Pmt | Reply field: top row of the viewport within page memory (1-indexed). |
| Pmp | Reply field: active page number (1 on single-page emulators). |
Examples
# Probe DECRQDE with a 100 ms read timeout.\nprintf '\\033["v'\nIFS= read -rs -d 'w' -t 0.1 reply </dev/tty 2>/dev/null\necho \"extent reply: ${reply}w\" # e.g. \\x1b[24;80;1;1;1\"wimport sys, re, select\nsys.stdout.write('\\x1b["v')\nsys.stdout.flush()\nif select.select([sys.stdin], [], [], 0.1)[0]:\n reply = sys.stdin.buffer.read1(64)\n m = re.search(rb'\\x1b\\[(\\d+);(\\d+);(\\d+);(\\d+);(\\d+)\"w', reply)\n if m:\n h, w, ml, mt, mp = (int(x) for x in m.groups())\n print(f'viewport: {h}x{w}, page-offset ({mt},{ml}), page {mp}')// Feature-probe — treat any DECRPDE reply as 'VT420-class emulator'.\nimport (\n \"fmt\"\n \"os\"\n)\nfmt.Fprint(os.Stdout, \"\\x1b[\\\"v\")\n// Read with timeout (omitted); a non-empty reply => assume VT420 features.// Trigger DECRQDE, log any reply.\nprocess.stdout.write('\\x1b[\"v');\nprocess.stdin.once('readable', () => {\n const m = /\\x1b\\[(\\d+);(\\d+);(\\d+);(\\d+);(\\d+)\"w/.exec(process.stdin.read()?.toString('binary') ?? '');\n if (m) console.error('extent:', m.slice(1));\n});/* Send DECRQDE; the host expects DECRPDE within ~100 ms or gives up. */\nfputs(\"\\x1b[\\\"v\", stdout);\nfflush(stdout);\n/* Then poll stdin with select() and scanf the 5 decimal fields. */Terminal support
- xterm
- yes
- Linux console (fbcon)
- no
- macOS Terminal.app
- no
- iTerm2
- no
- Windows Terminal
- no
- cmd.exe / ConPTY
- no
- kitty
- no
- alacritty
- no
- WezTerm
- partial
- Ghostty
- no
- GNOME Terminal
- yes
- Konsole
- yes
- tmux
- no
- GNU screen
- no
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | no | no | no | no | no | no | no | partial | no | yes | yes | no | no |