SL, SR Scroll Left and Right
Move the contents of the scrolling region left or right by n columns.
SL Scroll Left
CSI Pn SP @
SR Scroll Right
CSI Pn SP A
- Defaults
- Pn = 1
- ECMA-48
- §8.3.121 SL – Scroll Left, p. 63
- xterm
- Functions using CSI
CSI Pn SP @ (SL) moves what is on the screen Pn columns to the left, and CSI Pn SP A (SR) moves it Pn columns to the right. They are SU and SD turned on their side. ECMA-48 defines SR at §8.3.135, p. 68. Neither is in DEC STD 070 or the VT510 manual: DEC’s terminals scroll sideways with DECIC and DECDC and DECBI and DECFI instead.
xterm implements both (CASE_SL, CASE_SR), and calls them “from ISO 6429, not found in any of DEC’s terminals” (xtermScrollLR). It does the same as DECDC or DECIC with the cursor at the left margin (xtermColScroll):
- every line of the scrolling region moves, and only the part of it between the left and right margins;
- SL loses the columns that pass the left margin and brings in blank ones at the right margin, SR the other way round;
- a
0is taken as1, and a count larger than the region empties it; - the cursor does not move;
- if the cursor is outside the margins, top, bottom, left or right, nothing happens.
libghostty-vt ignores SL and SR. Its CSI dispatch in stream.zig has no case for @ or A with a space intermediate, so the cases below that change the screen are marked as known differences.
The space matters: CSI Pn @ is ICH and CSI Pn A is CUU.
Support
| Terminal | Version | Support | Notes |
|---|---|---|---|
| VT220 | manual, 2nd ed., 1984 | No | not in the manual; DEC terminals use DECIC and DECDC |
| VT510 | manual, 1st ed., 1993 | No | not in the manual; DEC terminals use DECIC, DECDC, DECBI and DECFI |
| xterm | patch 412, xterm-411a | Yes | SL and SR |
| libghostty-vt | 0f171f6 | No | ignored: no case for SP @ or SP A (SL-1 to SL-7) |
| kitty | 0.49.1, run in a VM | No | fails the 7 cases that show it working |
| foot | 1.28.0, run in a VM | No | fails the 7 cases that show it working |
| pyte | 0.8.2, run as a library | No | fails the 7 cases that show it working |
| xterm.js headless | 6.0.0, run as a library | Partly | fails SL-6, SL-7 of the 7 cases that show it working |
| alacritty_terminal | 0.26.0, run as a library | No | fails the 7 cases that show it working |
| ConEmu | build 230724, its documentation | No | not in ConEmu’s list; ANSI escape codes |
| rxvt-unicode | 9.31, run in a VM | No | fails the 7 cases that show it working |
| VTE | 0.84.1, run as a library | Yes | passes the 7 cases that show it working |
Validation
SL-1: Scroll left
ABCDE\r\n
FGHIJ
\e[1;3H
\e[\s@ # SL by one column
|BCDE____|
|GHIJ____|
cursor 1,3
SL-2: Scroll right
ABCDE\r\n
FGHIJ
\e[1;3H
\e[2\sA # SR by two columns
|__ABCDE_|
|__FGHIJ_|
cursor 1,3
SL-3: Zero is one
ABCDE
\e[1;1H
\e[0\s@
|BCDE_|
cursor 1,1
SL-4: More than the width empties the region
ABCDE\r\n
FGHIJ
\e[2;2H
\e[9\sA
|_____|
|_____|
cursor 2,2
SL-5: Only the scrolling region moves
ABCDE\r\n
FGHIJ\r\n
KLMNO\r\n
PQRST
\e[2;3r # scrolling region: lines 2 and 3
\e[2;1H
\e[\s@
|ABCDE|
|GHIJ_|
|LMNO_|
|PQRST|
cursor 2,1
SL-6: Between the left and right margins
ABCDEF\r\n
GHIJKL
\e[?69h # allow left and right margins
\e[2;5s # margins at columns 2 and 5
\e[1;3H
\e[\s@ # SL: in from the right margin
|ACDE_F|
|GIJK_L|
cursor 1,3
SL-7: SR between the margins
ABCDEF\r\n
GHIJKL
\e[?69h
\e[2;5s
\e[1;3H
\e[2\sA # SR by two: lost past the right margin
|A__BCF|
|G__HIL|
cursor 1,3
SL-8: Nothing happens with the cursor outside the margins
ABCDEF\r\n
GHIJKL
\e[?69h
\e[3;5s
\e[1;1H # left of the left margin
\e[\s@
\e[2\sA
|ABCDEF|
|GHIJKL|
cursor 1,1
SL-9: Nor above the scrolling region
ABCDE\r\n
FGHIJ\r\n
KLMNO
\e[2;3r
\e[1;3H # above the top margin
\e[\s@
|ABCDE|
|FGHIJ|
|KLMNO|
cursor 1,3