# Set Left and Right Margins (DECSLRM)

> Set the columns of the scrolling region, once left and right margins are enabled.

- **Sequence:** `CSI Pl ; Pr s`
- **Defaults:** Pl = 1, Pr = the last column
- **DEC STD 070:** [§5.4.3 Set Left and Right Margins, p. 5-27](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n281/mode/1up)
- **VT510:** [DECSLRM—Set Left and Right Margins](https://vt100.net/docs/vt510-rm/DECSLRM.html)

Set the left margin to column `Pl` and the right margin to column `Pr`.
Together with the top and bottom margins that [DECSTBM](https://control-codes.page/csi/decstbm/index.html.md) sets,
they bound the scrolling region. Text written inside them wraps at the right
margin back to the left one, and scrolling, insertion and deletion move only
what is inside. A parameter left out, or `0`, takes its default.

As with DECSTBM, the left margin has to be left of the right one, and DEC
STD 070 ignores the control otherwise. Setting the margins moves the cursor
to the home position, obeying [origin mode](https://control-codes.page/modes/decom/index.html.md).

DECSLRM works only while *left right margin mode*, DECLRMM, is set with
`CSI ? 69 h`. DEC STD 070 defines the mode at
[§5.4.3, p. 5-29](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n283/mode/1up),
and the VT510 manual as
[DECLRMM—Left Right Margin Mode](https://vt100.net/docs/vt510-rm/DECLRMM.html).
Resetting it with `CSI ? 69 l` puts the left and right margins back at the
edges of the screen. It is off by default.

The mode exists because `CSI s` already meant something. In SCO console
mode, `CSI s` with no parameters saves the cursor position and `CSI u`
restores it ([SCOSC](https://vt100.net/docs/vt510-rm/SCOSC.html) and
[SCORC](https://vt100.net/docs/vt510-rm/SCORC.html) in the VT510 manual). So
xterm reads `CSI s` as DECSLRM while DECLRMM is set, and otherwise as a save
of the cursor if it has no parameters
([`CASE_ANSI_SC`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L4884-L4904)). DEC STD 070 makes DECSLRM,
like DECLRMM, part of level 4 with the horizontal scrolling extension;
xterm accepts DECLRMM only when emulating a VT420 or later
([`srm_DECLRMM`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L7783-L7790)), while libghostty-vt always
does.

## Validation

### DECSLRM-1: Ignored without DECLRMM

Input, one step per line:

```text
\e[1;3H
\e[2;4s   # DECLRMM is off, so not DECSLRM
X
```

Expected screen:

```text
|__X___|
|______|
cursor 1,4
```

### DECSLRM-2: Text wraps at the right margin

Input, one step per line:

```text
\e[?69h   # DECLRMM
\e[2;4s   # columns 2 to 4; the cursor goes home
abcdefgh
\e[?69l   # off again: the margins are the screen's
\e[1;1H
ABCDEFGH
```

Expected screen:

```text
|ABCDEFGH|
|_efg____|
|_h______|
```

### DECSLRM-3: A left margin not left of the right is ignored

Input, one step per line:

```text
\e[2;5H
\e[?69h
\e[3;3s
```

Expected screen:

```text
|________|
|________|
cursor 2,5
```

### DECSLRM-4: Homes to the margin in origin mode

Input, one step per line:

```text
\e[?69h
\e[?6h    # origin mode
\e[3;5s
```

Expected screen:

```text
|________|
|________|
cursor 1,3
```

### DECSLRM-5: Without DECLRMM, CSI s saves the cursor

Input, one step per line:

```text
\e[2;3H
\e[s      # SCOSC
\e[1;1H
\e[u      # SCORC
X
```

Expected screen:

```text
|________|
|__X_____|
```

### DECSLRM-6: With DECLRMM, CSI s resets the margins

Input, one step per line:

```text
\e[?69h
\e[2;4s
\e[2;3H
\e[s      # DECSLRM with both left out
abcdefgh
```

Expected screen:

```text
|abcdefgh|
|________|
```

### DECSLRM-7: Asking about DECLRMM

Input, one step per line:

```text
\e[?69$p  # reset
\e[?69h
\e[?69$p  # set
```

Expected screen:

```text
|________|
reply \e[?69;2$y\e[?69;1$y
```

---

This is the Markdown version of <https://control-codes.page/csi/decslrm/>. 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>.
