# Scroll Up (SU)

> Move the contents of the scrolling region up n lines.

- **Sequence:** `CSI Pn S`
- **Defaults:** Pn = 1
- **ECMA-48:** [§8.3.147 SU – Scroll Up, p. 71](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n84/mode/1up)
- **DEC STD 070:** [§5.5 Pan Down (Scroll Up), p. 5-91](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n345/mode/1up)
- **VT510:** [SU—Pan Down](https://vt100.net/docs/vt510-rm/SU.html)

Move the lines of the scrolling region up `Pn` lines. The top `Pn` lines of
the region are lost, and `Pn` blank lines appear at the bottom margin. A `0`
is taken as `1`. The cursor does not move.

Unlike [DL](https://control-codes.page/csi/dl/index.html.md), SU does not depend on where the cursor is. It scrolls
the whole scrolling region, from the top margin, even when the cursor is
outside it. With left and right margins set, only the part of each line
between them moves.

The two DEC documents call this *Pan Down*, and describe something
different. In DEC's windowing extension the screen is a window onto a page of
display memory that can be taller than the screen, and SU moves that window
down the page: a line at the top of the window goes out of view, a new one
comes into view at the bottom, and DEC STD 070 says that "no movement of data
within the Logical Display occurs". ECMA-48's name describes the same thing
from the other side, as data that "appear to move up". A terminal whose page
is no bigger than its screen, as xterm's and libghostty-vt's are, has nothing
to pan across, so it moves the lines of the scrolling region instead. xterm
documents `CSI Ps S` as "Scroll up Ps lines".

With a `?` before the parameters, `CSI ? … S` is a different sequence in
xterm, XTSMGRAPHICS.

[SD](https://control-codes.page/csi/sd/index.html.md) scrolls the other way.

## Validation

### SU-1: Scroll one line

Input, one step per line:

```text
1\r\n2\r\n3\r\n4
\e[2;3H
\e[S
```

Expected screen:

```text
|2____|
|3____|
|4____|
|_____|
cursor 2,3
```

### SU-2: Scroll two lines

Input, one step per line:

```text
1\r\n2\r\n3\r\n4
\e[2S
```

Expected screen:

```text
|3____|
|4____|
|_____|
|_____|
```

### SU-3: The scrolling region, with the cursor outside it

Input, one step per line:

```text
1\r\n2\r\n3\r\n4
\e[2;3r   # region is lines 2 and 3; homes the cursor, above it
\e[S
```

Expected screen:

```text
|1____|
|3____|
|_____|
|4____|
cursor 1,1
```

### SU-4: Inside left and right margins

Input, one step per line:

```text
abcde\r\nfghij\r\nklmno\r\npqrst\r\nuvwxy
\e[?69h   # allow left and right margins
\e[2;4s   # margins at columns 2 and 4
\e[2;3H
\e[2S
```

Expected screen:

```text
|almne|
|fqrsj|
|kvwxo|
|p___t|
|u___y|
```

---

This is the Markdown version of <https://control-codes.page/csi/su/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
