# Select Character Path (SCP)

> Set which way text in a paragraph runs, left to right or right to left, for a terminal that handles bidirectional text.

- **Sequence:** `CSI Ps1 ; Ps2 SP k`
- **Defaults:** Ps1 = 0, Ps2 = 0 (BiDi recommendation; none in ECMA-48)
- **ECMA-48:** [§8.3.111 SCP – Select Character Path, p. 58](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n71/mode/1up)
- **Specification:** [BiDi in Terminal Emulators, v0.1, The escape sequences](https://gitlab.freedesktop.org/terminal-wg/bidi/-/blob/cc8686a93c8cc2f25a2f68f79c01b4822111509c/docs/30-recommendation/90-escape-sequences.md)

In ECMA-48, SCP sets the *character path*, the direction in which text
runs along a line: `Ps1` is `1` for left to right and `2` for right to
left. `Ps2` says what happens to text already there: `0` leaves it to the
implementation, `1` and `2` rearrange it in the presentation or in the data.
The standard gives neither parameter a default.

[*BiDi in Terminal Emulators*](https://terminal-wg.pages.freedesktop.org/bidi/recommendation/escape-sequences.html),
Egmont Koblinger's recommendation for right-to-left text in terminals, takes
SCP as the way a program sets the direction of a paragraph, the run of lines
between two hard newlines, and changes it a little:

- `Ps1` can also be `0`, the terminal's own default direction, which may be
  left to right or come from the locale or the user's settings. A program
  that set a direction sets `0` again on exit, and never assumes the default
  is left to right.
- Both parameters default to `0`, as [SPD](https://control-codes.page/csi/spd/index.html.md)'s do in ECMA-48, which
  the recommendation takes the missing defaults here to be an oversight
  for.
- `Ps2` `1` and `2` need not be supported. `0` is no longer left to the
  implementation: the direction goes into the terminal's current BiDi
  state, and onto the paragraph the cursor is in only if the cursor is at
  that paragraph's first position, as the
  [BiDi modes](https://control-codes.page/modes/bidi/index.html.md) page describes under "How the sequences
  apply". The cursor does not move.
- It sets the direction in both of [BDSM](https://control-codes.page/ansi/bdsm/index.html.md)'s modes, where
  ECMA TR/53's worked example uses it only in explicit mode, and in implicit
  mode it is the direction autodetection falls back on.

SCP is preferred over SPD, which ECMA-48 also gives a character path,
because SPD sets the line orientation and line progression as well, which
can only be global, while SCP can apply to a paragraph.

BiDi is display only. The terminal keeps the text in the order it arrived,
and the cursor addresses cells in that order, so SCP changes what the user
sees, and nothing that DECRQCRA, a cursor report or the cases below can
read back.

[VTE](https://gitlab.gnome.org/GNOME/vte/-/blob/0.84.1/src/vteseq.cc#L8218-L8267)
implements the recommendation's SCP. It takes `0`, as well as a missing
parameter, as left to right, since it has no other default direction yet,
ignores a `Ps1` greater than `2` and ignores `Ps2`. mintty takes `1` and
`2` the same way and `0` as autodetection falling back on left to right,
according to its
[documentation](https://github.com/mintty/mintty/wiki/CtrlSeqs#bidirectional-rendering).

A default xterm ignores `CSI SP k`: its table for a CSI with a space
intermediate has nothing for `k`
([`csi_sp_table`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/VTPrsTbl.c#L1909)).
libghostty-vt ignores it too, as it ignores any `CSI k` with an
intermediate; without one, `CSI k` is [VPB](https://control-codes.page/csi/vpb/index.html.md). The cases follow
xterm.

## Support

| Terminal | Version | Support | Notes |
| --- | --- | --- | --- |
| VT220 | [manual](https://vt100.net/docs/vt220-rm/), 2nd ed., 1984 | No | not in the manual |
| VT510 | [manual](https://vt100.net/docs/vt510-rm/), 1st ed., 1993 | No | not in the manual |
| xterm | patch 412, [xterm-411a](https://github.com/ThomasDickey/xterm-snapshots/tree/xterm-411a) | No | ignored; `CSI SP k` is not in its parser |
| libghostty-vt | [919dca5](https://github.com/ghostty-org/ghostty/tree/919dca5c848d43a489a4cb2e1feade016f0fa2db) | No | ignored |
| ConEmu | build 230724, its [documentation](https://conemu.github.io/en/AnsiEscapeCodes.html) | No | not in its [ANSI escape codes](https://conemu.github.io/en/AnsiEscapeCodes.html) |
| mintty | 3.8.3, its [documentation](https://github.com/mintty/mintty/wiki/CtrlSeqs) | Yes | `1` and `2`, and `0` for autodetection falling back on left to right ([documentation](https://github.com/mintty/mintty/wiki/CtrlSeqs#bidirectional-rendering)) |
| VTE | 0.84.1, [source](https://gitlab.gnome.org/GNOME/vte/-/tree/0.84.1) | Yes | the BiDi recommendation's SCP; `0` is left to right ([source](https://gitlab.gnome.org/GNOME/vte/-/blob/0.84.1/src/vteseq.cc#L8218-L8267)) |

## Validation

### SCP-1: Ignored, with nothing printed

Input, one step per line:

```text
AB
\e[2 k
C
```

Expected screen:

```text
|ABC___|
cursor 1,4
```

### SCP-2: The default parameters do not move the cursor

Input, one step per line:

```text
AB
\e[ k
\e[0;0 k
C
```

Expected screen:

```text
|ABC___|
cursor 1,4
```

### SCP-3: Nor do ECMA-48's other effects

Input, one step per line:

```text
ABC
\e[2;1 k
\e[1;2 k
D
```

Expected screen:

```text
|ABCD__|
cursor 1,5
```

### SCP-4: Text written after it stays in the order it arrived

Input, one step per line:

```text
\e[2 k
AB\r\n
CD
\e[0 k
```

Expected screen:

```text
|AB____|
|CD____|
cursor 2,3
```

---

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