# Origin Mode (DECOM)

> Count cursor positions from the margins instead of the corner of the screen.

- **Sequence:** `CSI ? 6 h`
- **DEC STD 070:** [§5.4.3 Set/Reset Origin Mode, p. 5-31](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n285/mode/1up)
- **VT510:** [DECOM—Origin Mode](https://vt100.net/docs/vt510-rm/DECOM.html)

`CSI ? 6 h` sets origin mode and `CSI ? 6 l` resets it. It is reset by
default, and by a reset of the terminal.

Reset, positions count from the top-left corner of the screen. Set, they
count from the top and left margins, the corner of the scrolling region:
line 1 of [CUP](https://control-codes.page/csi/cup/index.html.md) is the top margin, and column 1 the left margin.
DEC STD 070 also says that in origin mode "the Active Position cannot be
moved above the Top Margin or left of the Left Margin", and the VT510
manual that it "cannot move outside of the margins", so a position past the
bottom or right margin is clamped to it. The margins are set by
[DECSTBM](https://control-codes.page/csi/decstbm/index.html.md) and [DECSLRM](https://control-codes.page/csi/decslrm/index.html.md).

Setting or resetting the mode moves the cursor to the new home position: the
top and left margins when set, the first line and column when reset. Origin
mode affects every function that takes a position, and the reports that give
one back, such as the cursor position report from [DSR](https://control-codes.page/csi/dsr/index.html.md). It does
not limit erasing: [ED](https://control-codes.page/csi/ed/index.html.md) still erases the whole screen.

A host can ask whether it is set with DECRQM, `CSI ? 6 $ p`.

## Validation

### DECOM-1: Setting it homes the cursor to the margins

Input, one step per line:

```text
\e[2;3r   # region is lines 2 and 3
\e[3;4H
\e[?6h
```

Expected screen:

```text
|_____|
|_____|
|_____|
|_____|
cursor 2,1
```

### DECOM-2: Resetting it homes the cursor to the corner

Input, one step per line:

```text
\e[2;3r
\e[?6h
\e[2;2H
\e[?6l
```

Expected screen:

```text
|_____|
|_____|
|_____|
|_____|
cursor 1,1
```

### DECOM-3: Counted from the left margin, clamped to the right

Input, one step per line:

```text
\e[?69h   # allow left and right margins
\e[2;4s   # columns 2 to 4
\e[?6h
\e[1;1H
X
\e[1;9H   # clamped to the right margin
Y
```

Expected screen:

```text
|_X_Y__|
|______|
```

### DECOM-4: Clamped to the bottom margin

Input, one step per line:

```text
\e[2;3r
\e[?6h
\e[9;9H
X
```

Expected screen:

```text
|_____|
|_____|
|____X|
|_____|
```

### DECOM-5: Still counted from the margins after they move

Input, one step per line:

```text
\e[2;3r
\e[?69h
\e[2;4s
\e[?6h
\e[1;1H
X         # at line 2, column 2
\e[?69l   # the left and right margins go
\e[r      # and the top and bottom ones
\e[1;1H
Y         # origin mode is still set, now at the corner
```

Expected screen:

```text
|Y_____|
|_X____|
|______|
|______|
```

### DECOM-6: Asking about it

Input, one step per line:

```text
\e[?6h
\e[?6$p
\e[?6l
\e[?6$p
```

Expected screen:

```text
|_____|
reply \e[?6;1$y\e[?6;2$y
```

---

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