# Insertion Replacement Mode (IRM)

> Insert characters instead of writing over them.

- **Sequence:** `CSI 4 h`
- **ECMA-48:** [§7.2.10 IRM – Insertion Replacement Mode, p. 24](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n37/mode/1up)
- **DEC STD 070:** [§5.11 Insert/Replacement Mode, p. 5-138](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n392/mode/1up)
- **VT220:** [§4.6.4 Insert/Replace Mode (IRM)](https://vt100.net/docs/vt220-rm/chapter4.html#S4.6.4)
- **VT510:** [IRM—Insert/Replace Mode](https://vt100.net/docs/vt510-rm/IRM.html)
- **xterm:** [Functions using CSI](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)

Mode 4 decides what a printed character does to the one under the cursor.

| State | ECMA-48 calls it | Meaning |
| --- | --- | --- |
| Reset, `CSI 4 l` | REPLACE | the character takes the place of the one under the cursor |
| Set, `CSI 4 h` | INSERT | the character is inserted, and the rest of the line moves right |

Replace is the default. In insert mode, the character under the cursor and
everything right of it move one column right to make room, and whatever is
pushed past the right margin is lost. Only printing is affected: the controls
and the erasing functions work as they always do.

xterm keeps the mode ([`ansi_modes`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L7399-L7424)), and so does libghostty-vt, and both answer
[DECRQM](https://control-codes.page/csi/decrqm/index.html.md) with its state.

## Validation

### IRM-1: Insert mode

Input, one step per line:

```text
abc
\e[1;1H
\e[4h     # IRM
X
```

Expected screen:

```text
|Xabc__|
cursor 1,2
```

### IRM-2: What is pushed off the line is lost

Input, one step per line:

```text
ABCDEF    # fills the line
\e[1;2H
\e[4h     # IRM
X
```

Expected screen:

```text
|AXBCDE|
|______|
cursor 1,3
```

### IRM-3: Back to replace mode

Input, one step per line:

```text
abc
\e[1;1H
\e[4h     # IRM: insert
X
\e[4l     # replace
Y         # over the a
```

Expected screen:

```text
|XYbc__|
```

### IRM-4: Insert stops at the right margin

Input, one step per line:

```text
\e[1;5H
abcdef            # columns 5 to 10
\e[?69h           # allow left and right margins
\e[5;10s          # margins at columns 5 and 10
\e[1;7H
\e[4h             # IRM
X                 # the f is pushed past column 10
```

Expected screen:

```text
|____abXcde__|
```

### IRM-5: Reset by default

Input, one step per line:

```text
\e[4$p
```

Expected screen:

```text
|_____|
reply \e[4;2$y
```

### IRM-6: Set

Input, one step per line:

```text
\e[4h
\e[4$p
```

Expected screen:

```text
|_____|
reply \e[4;1$y
```

---

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