^[control-codes live in libghostty-vt

Control sequences

SCP Select Character Path

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

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
Specification
BiDi in Terminal Emulators, v0.1, The escape sequences

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, 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’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 page describes under “How the sequences apply”. The cursor does not move.
  • It sets the direction in both of BDSM’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 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.

A default xterm ignores CSI SP k: its table for a CSI with a space intermediate has nothing for k (csi_sp_table). libghostty-vt ignores it too, as it ignores any CSI k with an intermediate; without one, CSI k is VPB. The cases follow xterm.

Support

TerminalVersionSupportNotes
VT220manual, 2nd ed., 1984Nonot in the manual
VT510manual, 1st ed., 1993Nonot in the manual
xtermpatch 412, xterm-411aNoignored; CSI SP k is not in its parser
libghostty-vt919dca5Noignored
ConEmubuild 230724, its documentationNonot in its ANSI escape codes
mintty3.8.3, its documentationYes1 and 2, and 0 for autodetection falling back on left to right (documentation)
VTE0.84.1, sourceYesthe BiDi recommendation’s SCP; 0 is left to right (source)

Validation

SCP-1: Ignored, with nothing printed

AB
\e[2 k
C
|ABC___|
cursor 1,4

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

AB
\e[ k
\e[0;0 k
C
|ABC___|
cursor 1,4

SCP-3: Nor do ECMA-48’s other effects

ABC
\e[2;1 k
\e[1;2 k
D
|ABCD__|
cursor 1,5

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

\e[2 k
AB\r\n
CD
\e[0 k
|AB____|
|CD____|
cursor 2,3
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.