Horizontal Position Relative (HPR)

Move the cursor forward `n` columns without changing the row.

  1. 0x1B
    ESC
  2. 0x5B
    [
  3. ____
    x
  4. 0x61
    a

The parameter x must be an integer greater than or equal to 1. If x is less than or equal to 0, adjust x to be 1. If x is omitted, x defaults to 1.

This sequence always unsets the pending wrap state.

HPR moves the cursor x columns to the right of its current position. HPR is paired with HPA the same way CUF is paired with CHA: HPA selects an absolute column, HPR selects a column relative to where the cursor is now.

HPR is handled as an absolute move to the current row and the current column plus x. With origin mode off, the result is clamped to the last column of the screen, so HPR runs past a right margin instead of stopping at it. With origin mode on, the clamp is the right margin. The cursor stops at whichever boundary applies regardless of the remaining value of x; this sequence never wraps to the next line and never modifies cell content.

Because the move is absolute, the row goes through the same resolution as the column. It is unchanged with origin mode off, but with origin mode on the current row is offset by the top margin and clamped to the bottom margin, so HPR can move the cursor down a row as well as across.

Note

HPR and CUF (Cursor Forward, CSI Pn C) agree as long as no right margin is set, and both unset pending wrap, but they are not the same handler. CUF always stops at the right margin; HPR only respects the right margin when origin mode is set, and otherwise carries the cursor to the edge of the screen.

Validation

HPR V-1: Normal Usage

printf "\033[1;1H" # move to top-left
printf "\033[0J" # clear screen
printf "A"
printf "\033[3a" # HPR forward 3 columns
printf "X"
|A___Xc____|

HPR V-2: Default Parameter

printf "\033[1;1H" # move to top-left
printf "\033[0J" # clear screen
printf "A"
printf "\033[a" # HPR with default (1)
printf "X"
|A_Xc______|

HPR V-3: Clamps at Right Margin

printf "\033[1;1H" # move to top-left
printf "\033[0J" # clear screen
printf "A"
printf "\033[500a" # HPR way past the edge
printf "X"
|A________Xc

HPR V-4: Pending Wrap is Unset

cols=$(tput cols)
printf "\033[${cols}G" # move to last column
printf "A" # set pending wrap state
printf "\033[1a" # HPR cancels pending wrap
printf "X"
|_________X|

Printing A in the last column leaves the cursor there with pending wrap set, so HPR asks for one column past the screen edge and is clamped back to the column the cursor is already on. The X overwrites the A.