Skip to main content
ansicode

CNL / CPL — Cursor next / previous line

Move the cursor to column 1 of the line N below (CNL) or above (CPL).

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x1b[NE (down N lines, col 1) \x1b[NF (up)
\\033[\033[E / \033[F
\\e[\e[E / \e[F
ESC [ESC [ N E / F
hex1b 5b <N> 45 / 46

Description

Two ECMA-48 cursor-positioning primitives that fold "move vertically N rows" and "snap column to 1" into a single round-trip. Final byte E = CNL (Cursor Next Line, ECMA-48 §8.3.13) — move N rows down + column 1. Final byte F = CPL (Cursor Previous Line, §8.3.27) — move N rows up + column 1. Both default to N=1 if omitted (\x1b[E = "next line, column 1"). The key contrast with CUU / CUD (\x1b[NA / \x1b[NB, see cursor-move) is column behaviour: CUU and CUD preserve the current column; CNL and CPL force column 1 as part of the same move, so a redraw loop becomes \x1b[1F\x1b[K<text> (back to start of previous line + erase + write) instead of the three-token \x1b[1A\r\x1b[K<text>.

Portability — every VT100-conformant emulator supports CNL / CPL: xterm, iTerm2, kitty, alacritty, wezterm, gnome-terminal, Konsole, Ghostty, Windows Terminal, ConPTY 1809+, Linux console. Both predate VT220 — they go back to the VT100 spec — so even minimal emulators have them. Out-of-range values clamp at the visible region boundary: CNL past the bottom row stops there without auto-scrolling (unlike a literal LF + CR at the bottom row which *would* scroll the screen up by one), CPL past the top stops at row 1. DECSTBM scrolling regions are respected: CNL will not move past the region's bottom margin and CPL will not move above its top margin, which is the property that makes them safer than \r\n in a redrawing TUI inside a scroll region. terminfo capability names are cnl / cpl but most terminal entries leave them empty — programs that want the behaviour emit the bytes directly rather than going through the terminfo layer.

No "close" — these are stateless cursor moves, not toggles. The non-scrolling behaviour at the region edge is what makes them load-bearing in TUIs: a multi-line progress indicator that needs to redraw line N back to line 1 can issue \x1b[<N>F\x1b[J (up N lines + erase to end of screen) without any risk of triggering a scroll, even if the user resized the terminal between draws. When the absolute row matters (not just a relative jump), cursor-position (CUP, \x1b[r;cH) is more robust because it doesn't depend on knowing the current row. The compound \x1b[1E\x1b[K (next line + erase to end of line) is the spec-correct alternative to \r\n\x1b[K when the writer is inside a scroll region or a raw-mode TTY where \r semantics might surprise. Related: cursor-move (CUU / CUD / CUF / CUB — moves that preserve the orthogonal axis), cursor-position (CUP — absolute row+column), cursor-column (CHA — column-only counterpart with the same "no line feed" property).

Spec citation: ECMA-48 §8.3.13 (CNL) / §8.3.27 (CPL)

Examples

bash
printf 'top\n\033[2Ebottom-of-3rd-line-below\n'
python
import sys; sys.stdout.write('\x1b[3E')
go
fmt.Print("\x1b[3E")
javascript
process.stdout.write('\x1b[3E')
c
printf("\x1b[3E");

Used in

Real-world tools that emit this sequence — anchors the bytes to commands you've already used.

  • vim / neovim `j` / `k` movement in operator-pending pre-stepVim's operator-pending mode (`d`, `y`, `c` then motion) for line-wise operators like `dj` / `yk` emits `\x1b[<n>E` (CNL) or `\x1b[<n>F` (CPL) to position the cursor before applying — `:set verbose=15` then `dj` shows the CNL/CPL in the verbose log distinct from CUD `\x1b[<n>B` used for `<n>j`
  • less line-scroll via `j` / `↓``less` redraws on per-line scroll by emitting CNL `\x1b[E` for the cursor advance + ED `\x1b[J` for partial-screen clear, instead of a full repaint — `script -c 'less /etc/passwd' /tmp/log && strings /tmp/log | grep '\x1b\[E'` after some `j` keypresses
  • tmux copy-mode-vi line movementtmux copy-mode (`prefix [`) with `mode-keys vi` rebinds `j`/`k` to CNL/CPL for cross-pane consistent cursor advancement — `tmux show-options -g mode-keys` shows the binding, trace pane output with `tmux pipe-pane -o 'cat > /tmp/p.log'` then scroll
  • ncurses `wgetnstr()` line-wrap behaviourCurses input function `wgetnstr(WINDOW *, char *, int n)` reads a length-bounded string; when the user types past the visible window, the redraw uses CNL `\x1b[1E` to move to next row plus `wclrtoeol()` (which is EL `\x1b[K`) — `infocmp xterm | grep -E 'nel|cnl'` confirms the `nel` cap maps to CNL
  • GNU readline `next-history` / `previous-history`Bound to `↓` / `↑` by default; recalling history with multi-line entries uses CNL / CPL to advance to the next visual row of the recalled command — `bind -p | grep -E 'next-history|previous-history'` shows the binding, trace via `READLINE_DEBUG=trace`

Frequently asked

Short answers to the questions developers actually search for this sequence.

What's the difference between \x1b[F and \r\x1b[A — both go up one line to column 1?
Two differences that matter inside TUIs. (1) Round-trip cost: CPL is one CSI sequence, \r\x1b[A is two (a C0 control + a CSI). On a slow serial line or under tmux's input throttling, the extra byte and the intermediate state-machine entry sometimes show up as a visible flicker. (2) Scroll-region behaviour: both forms respect DECSTBM and clamp at the region's top margin, so they're equivalent there. The real win for CPL is composability — \x1b[5F jumps 5 rows up + column 1 in one move, whereas the \r\x1b[5A form still needs the explicit \r. For a single-row jump either is fine; for multi-row redraw loops prefer CNL / CPL.
Will \x1b[E at the bottom row scroll the screen the way \n does?
No — CNL clamps at the bottom of the current scrolling region (full screen if DECSTBM hasn't restricted it) without auto-scrolling. A bare \n at the same position emits LF, which the terminal handles as "down one line, scroll if needed" — that's how a shell appends a new prompt line at the bottom of the screen. CNL's no-scroll behaviour is exactly why TUIs that redraw a multi-line panel use \x1b[<N>F\x1b[J (up N + erase to end of screen) instead of \r\n repeated — you stay parked at the panel origin even if the user resized the terminal between draws.

Terminal support

xterm
yes
Linux console (fbcon)
yes
macOS Terminal.app
yes
iTerm2
yes
Windows Terminal
yes
cmd.exe / ConPTY
yes
kitty
yes
alacritty
yes
WezTerm
yes
Ghostty
yes
GNOME Terminal
yes
Konsole
yes
tmux
yes
GNU screen
yes

Related sequences

In the family cookbook

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