# Cursor Character Absolute (CHA)

> Move the cursor to column n of the line it is on.

- **Sequence:** `CSI Pn G`
- **Defaults:** Pn = 1
- **ECMA-48:** [§8.3.9 CHA – Cursor Character Absolute, p. 34](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n47/mode/1up)
- **VT510:** [CHA—Cursor Horizontal Absolute](https://vt100.net/docs/vt510-rm/CHA.html)

Move the cursor to column `Pn` of the line it is on, counting from 1. The
line does not change. A `0` is taken as `1`, and a column past the right
edge of the screen is clamped to the last column.

Left and right margins do not limit it: with them set, CHA can still move
the cursor to any column on the line. Origin mode changes where it counts
from, though. With origin mode on, column 1 is the left margin, as it is for
[CUP](https://control-codes.page/csi/cup/index.html.md), and the column is clamped to the right margin.

[HPA](https://control-codes.page/csi/hpa/index.html.md) does the same thing with a different final byte. ECMA-48
defines CHA in terms of the *presentation* component, the image on the
screen, and HPA in terms of the *data* component, the stored text the image
is made from. It also says that for a device with no separate data
component, references to the data component "are to be read as referring
to" the presentation component (§6, p. 14). A terminal is such a device, and
libghostty-vt handles both final bytes with the same code.

## Validation

### CHA-1: To the first column by default

Input, one step per line:

```text
\e[1;4H
\e[G
X
```

Expected screen:

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

### CHA-2: To a column

Input, one step per line:

```text
\e[2;1H
\e[4G
X
```

Expected screen:

```text
|_____|
|___X_|
```

### CHA-3: Clamped to the last column

Input, one step per line:

```text
\e[99G
X
```

Expected screen:

```text
|____X|
pending-wrap yes
```

### CHA-4: Not limited by the left margin

Input, one step per line:

```text
\e[?69h   # allow left and right margins
\e[3;5s   # margins at columns 3 and 5
\e[1;4H
\e[1G
X
```

Expected screen:

```text
|X____|
```

### CHA-5: Counted from the left margin in origin mode

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[2;3r   # region is lines 2 and 3
\e[?69h   # allow left and right margins
\e[3;5s   # margins at columns 3 and 5
\e[?6h    # origin mode
\e[1;2H   # line 2, column 4 of the screen
\e[G
X
\e[?6l
```

Expected screen:

```text
|______|
|__X___|
|______|
```

The `X` should land in the left margin's column on the line the cursor was
on, which is what esctest2's `test_CHA_RespectsOriginMode` checks. In
libghostty-vt it lands a line lower. CHA there is
`setCursorPos(current line + 1, Pn)`, and in origin mode `setCursorPos` adds
the top margin to the line it is given, so the line the cursor is already on
is offset a second time.

---

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