^[control-codes live in libghostty-vt

Control sequences

VPR Line Position Forward

Move the cursor down n lines, keeping its column.

CSI Pn e
Defaults
Pn = 1
ECMA-48
§8.3.160 VPR – Line Position Forward, p. 74
VT510
VPR—Vertical Position Relative

Move the cursor down Pn lines, keeping its column. A 0 is taken as 1. The VT510 manual says that an attempt to move below the last line stops at the last line. It never scrolls.

It is a relative move, so origin mode makes no difference to it: the cursor moves Pn lines from wherever it is.

ECMA-48 names it for the data component, which a terminal does not have apart from its screen (§6, p. 14). Going up is VPB, and the absolute form is VPA. The VT510 manual’s one-line summary and “Parameters” entry for VPR are copying errors, as they are for VPA; the description beneath them is the right one.

Validation

VPR-1: One line by default

\e[1;2H
\e[e
X
|_____|
|_X___|
|_____|

VPR-2: n lines

\e[1;4H
\e[2e
X
|_____|
|_____|
|___X_|

VPR-3: Stops at the last line, without scrolling

A
\e[2;3H
\e[99e
X
|A____|
|_____|
|__X__|

VPR-4: The same in origin mode

\e[2;5r   # region is lines 2 to 5
\e[?69h   # allow left and right margins
\e[2;6s   # margins at columns 2 and 6
\e[?6h    # origin mode
\e[1;2H   # line 2, column 3 of the screen
X
\e[2e
Y
\e[?6l
|_______|
|__X____|
|_______|
|___Y___|
|_______|

The Y should be two lines below the cell after X, which is what esctest2’s test_VPR_IgnoresOriginMode checks. libghostty-vt puts it further down and further right. VPR there is setCursorPos(current line + 1 + Pn, current column + 1), and in origin mode setCursorPos adds the margins to both, so the move is offset by the top margin and the column by the left margin.

Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.