Skip to main content
ansicode
CSI (cursor & erase)

CSI escape codes — cursor, erase, scroll, position

Control Sequence Introducer. The `ESC [` family minus its SGR sub-set — cursor movement (up / down / forward / back / column / absolute position), erase (line / display), scroll, save / restore, and the handful of CSI sequences for window and cursor reporting.

60 sequences

CSI cookbook — six purposes the family covers

CSI (Control Sequence Introducer) is the largest active corner of the escape-code dialect — over 60 finals doing everything except palette and chrome (those are SGR and OSC). Six stops, top to bottom: the envelope syntax itself, cursor movement, screen / line erase, the round-trip queries terminals answer on stdin, scroll-region and margin setup that TUIs use to carve out fixed regions, and local insert / delete / cursor-shape ops that avoid the cost of a full repaint.

  1. 1. The envelope — \x1b[<final-byte>

    Every CSI sequence is \x1b[ (ESC [), an optional **private-marker** (? for DEC private modes, < / = / > for xterm-defined variants), zero or more numeric parameters separated by ;, and a **final byte** in the \x40\x7E range that picks the action. Unlike OSC there's no terminator — the final byte ends the sequence. SGR uses m (\x1b[31m), ED uses J, EL uses K, CUP (cursor position) uses H, DSR uses n, DA uses c — over 60 finals in active use across ECMA-48 + xterm. Parameters default to 1 or 0 depending on the action; omitted is equivalent to the default, so \x1b[A (move up 1) is identical to \x1b[1A. There's also an 8-bit CSI form \x9b … you'll see in old VT manuals but never in the wild.

  2. 2. Cursor movement — CUU / CUD / CUF / CUB + CUP + CHA / VPA

    The eight cursor primitives every TUI lives on. **CUU / CUD / CUF / CUB** (\x1b[NA / B / C / D) move the cursor up / down / forward / backward by N cells (default 1) without crossing the screen edge. **CUP** (\x1b[r;cH, alias f) jumps to absolute row r, column c (1-indexed). **CHA** (\x1b[NG) and **VPA** (\x1b[Nd) jump to absolute column / row keeping the other axis. **CNL / CPL** (\x1b[NE / F) move N lines down / up but also reset column to 1 — useful for paragraph-style cursor flow. **SCOSC / SCORC** (\x1b[s / \x1b[u) save / restore one cursor slot — older than DECSC \x1b7 / DECRC \x1b8 but identical in effect on every modern emulator.

  3. 3. Erase — ED J and EL K

    Two finals do all the erasing: **J** for screen, **K** for line. Each takes a parameter selecting the range: 0 (default) from cursor to end, 1 from start to cursor, 2 the whole screen / line, and 3 for J also wipes scrollback (xterm extension, supported by most modern emulators). The canonical "clear screen and home" combo every TUI emits on launch is \x1b[2J\x1b[H — erase whole screen, then move cursor to row 1 column 1. **ECH** \x1b[NX (covered in section 6) is the in-place alternative that overwrites N cells with blanks without moving anything else. For partial repaints, \x1b[K (erase to end of line) after a CUP jump is the cheapest way to wipe a row before redrawing it.

  4. 4. Queries — DA, DA2, DSR, DECRQM

    Round-trip queries where the terminal replies back on **stdin** — programs that emit a query must read the response or it leaks into the next user input. **DA** \x1b[c (Primary Device Attributes) asks "what are you?" — modern emulators reply \x1b[?<id>;<feature>;<feature>c advertising VT100 / VT200 / VT400 base + supported features (sixel, regis, colour, etc.). **DA2** \x1b[>c returns model + firmware version — useful for distinguishing iTerm2 from kitty from xterm. **DSR** \x1b[6n (cursor position) returns \x1b[r;cR; \x1b[5n returns terminal-OK status. **DECRQM** \x1b[?<n>$p reads whether DEC private mode n is currently set / reset / permanent / unsupported (one of 0 / 1 / 2 / 3 / 4 in the reply). Use case: feature-detect alt-screen support before emitting \x1b[?1049h.

  5. 5. Margins & scroll region — DECSTBM r and DECSLRM s

    **DECSTBM** \x1b[<top>;<bottom>r sets the scrolling region to rows topbottom (1-indexed, inclusive). Inside this region scroll-up / scroll-down (\x1b[NS / \x1b[NT) and IL / DL only affect those rows; the rest of the screen stays put. The classic use is a stationary status bar at the bottom — set \x1b[1;<screenrows-1>r and the status row never scrolls away. To reset to full-screen scrolling, emit \x1b[r with no arguments. **DECSLRM** \x1b[<left>;<right>s sets horizontal margins the same way, but only takes effect when DECLRMM (\x1b[?69h) is enabled first — most TUIs skip horizontal margins entirely. Without DECLRMM, \x1b[s is interpreted as SCOSC (save cursor) — a classic mode-confusion trap when porting code between terminals.

  6. 6. Insert / delete / cursor shape — IL / DL / ICH / DCH / ECH + DECSCUSR

    Local edits that don't need a full repaint. **IL** \x1b[NL inserts N blank lines at the cursor, pushing existing content down (off the scroll region). **DL** \x1b[NM deletes N lines, pulling content up. **ICH** \x1b[N@ and **DCH** \x1b[NP do the same on the column axis within a single line. **ECH** \x1b[NX erases N cells in place — overwrites with blanks without shifting anything else, the right primitive for clearing a known-width field. **DECSCUSR** \x1b[N q picks cursor shape: 1 blinking block (default), 2 steady block, 3 blinking underline, 4 steady underline, 5 blinking bar, 6 steady bar — vim's terminal-mode toggles between 2 and 6 to show insert vs normal. Honoured by xterm, kitty, iTerm2, wezterm, alacritty, ghostty, Windows Terminal, gnome-terminal 3.16+, konsole; Linux console ignores.

All sequences in this family

Browse other families