# How Control Codes Work for Cursor Movement and Screen Clearing in Rich

> Discover how rich implements terminal control codes for cursor movement and screen clearing. Learn how high-level intents translate into precise ANSI escape sequences.

- Repository: [Textualize/rich](https://github.com/Textualize/rich)
- Tags: internals
- Published: 2026-03-06

---

**Rich implements terminal control codes as `Control` renderables that translate high-level intents like cursor positioning and screen clearing into precise ANSI escape sequences.**

The Textualize/rich library provides granular control over terminal output through a specialized `Control` class. Understanding how these **control codes** function is essential for building interactive CLI applications that manipulate cursor position and screen state programmatically.

## Core Architecture

Rich encapsulates ANSI escape sequences through a layered architecture that separates symbolic intents from raw byte generation.

### ControlType Enum

In [`rich/segment.py`](https://github.com/Textualize/rich/blob/main/rich/segment.py) (lines 35-53), the **`ControlType`** `IntEnum` defines every non-printable control operation. This enumeration includes symbolic names for cursor up/down/forward/backward movements, absolute positioning, screen clearing, and alternate screen buffer management.

### CONTROL_CODES_FORMAT Mapping

The [`rich/control.py`](https://github.com/Textualize/rich/blob/main/rich/control.py) file (lines 28-45) defines **`CONTROL_CODES_FORMAT`**, a dictionary mapping each `ControlType` to a callable that constructs the raw escape string. This centralization allows the library to maintain all ANSI sequences in a single location, simplifying extensions and customizations.

### The Control Class

Defined in [`rich/control.py`](https://github.com/Textualize/rich/blob/main/rich/control.py) (lines 48-66, 78-107), the **`Control`** class serves as the public API. Its constructor accepts one or more `(ControlType, ...)` tuples, looks up the corresponding formatters in `CONTROL_CODES_FORMAT`, concatenates the results, and stores the final sequence within a **`Segment`** instance.

### Segment Integration

The **`Segment`** namedtuple in [`rich/segment.py`](https://github.com/Textualize/rich/blob/main/rich/segment.py) (lines 70-79) acts as the basic renderable unit. When a `Segment` contains a `control` payload, the console writes the stored escape string directly to the terminal without applying style processing. This isolation guarantees that control codes emit as atomic, non-styled fragments distinct from text rendering.

### Console.control() Method

The ergonomic entry point resides in [`rich/console.py`](https://github.com/Textualize/rich/blob/main/rich/console.py) (lines 1150-1165). The **`Console.control()`** method queues a `Control` renderable onto the console's output stream, providing the primary interface for users (e.g., `console.control(Control.move(2, 0))`).

## Cursor Movement Control Codes

Rich translates high-level movement intents into standard ANSI cursor positioning codes.

- **Move up `n` rows**: `Control.move(y=-n)` generates `\x1b[{n}A` via `ControlType.CURSOR_UP`
- **Move down `n` rows**: `Control.move(y=n)` generates `\x1b[{n}B` via `ControlType.CURSOR_DOWN`  
- **Move right `n` columns**: `Control.move(x=n)` generates `\x1b[{n}C` via `ControlType.CURSOR_FORWARD`
- **Move left `n` columns**: `Control.move(x=-n)` generates `\x1b[{n}D` via `ControlType.CURSOR_BACKWARD`
- **Jump to column `x`**: `Control.move_to_column(x)` generates `\x1b[{x}G` via `ControlType.CURSOR_MOVE_TO_COLUMN`, using one-based coordinates native to the ANSI `G` command
- **Jump to position `(x, y)`**: `Control.move_to(x, y)` accepts zero-based coordinates and generates `\x1b[{y+1};{x+1}H` via `ControlType.CURSOR_MOVE_TO`, automatically converting to one-based ANSI coordinates
- **Return home**: `Control.home()` generates `\x1b[H` via `ControlType.HOME`

## Screen-Clearing Control Codes

Rich provides declarative methods for manipulating the terminal screen buffer.

- **Clear entire screen**: `Control.clear()` produces `\x1b[2J` via `ControlType.CLEAR`, erasing all visible cells while preserving cursor position
- **Enable alternate screen**: `Control.alt_screen(True)` produces `\x1b[?1049h` via `ControlType.ENABLE_ALT_SCREEN`, switching to an off-screen buffer used by full-screen applications
- **Disable alternate screen**: `Control.alt_screen(False)` produces `\x1b[?1049l` via `ControlType.DISABLE_ALT_SCREEN`, restoring the original buffer

## Practical Code Examples

The following examples demonstrate common control code patterns using `rich.console` and `rich.control`.

```python
from rich.console import Console
from rich.control import Control

console = Console()

# Move cursor down 3 rows and right 5 columns

console.print("First line")
console.control(Control.move(x=5, y=3))
console.print("Below and indented")

```

```python

# Clear the screen then print a heading at the top-left corner

console.control(Control.clear())
console.control(Control.home())
console.print("[bold cyan]Welcome to Rich![/]")

```

```python

# Use absolute positioning to write at column 10, row 5

# Zero-based arguments: (9, 4) maps to column 10, row 5 in ANSI coordinates

console.control(Control.move_to(9, 4))
console.print("Cell content")

```

```python

# Hide cursor during animation, then restore it

console.control(Control.show_cursor(False))

# ... render progress bar ...

console.control(Control.show_cursor(True))

```

```python

# Compose multiple movements into a single control sequence

console.control(
    Control.move(y=-2) + Control.move_to_column(19)
)

```

## Summary

- Rich abstracts ANSI escape sequences through the **`Control`** class, which converts high-level intents into raw byte sequences during instantiation
- The **`ControlType`** enum and **`CONTROL_CODES_FORMAT`** mapping in [`rich/segment.py`](https://github.com/Textualize/rich/blob/main/rich/segment.py) and [`rich/control.py`](https://github.com/Textualize/rich/blob/main/rich/control.py) centralize all terminal operation definitions
- Cursor movement leverages standard ANSI A/B/C/D/G/H codes, while screen clearing and alternate buffer management use J and ?1049h/l sequences
- Control codes are stored in **`Segment`** instances and emitted verbatim by the console, bypassing style processing to ensure terminal compatibility
- The **`Console.control()`** method provides the primary interface for queuing control operations alongside regular output

## Frequently Asked Questions

### What are control codes in Rich?

Control codes are non-printable ANSI escape sequences that instruct the terminal to perform actions like moving the cursor or clearing the screen. In Rich, these are encapsulated as **`Control`** objects that generate the appropriate escape strings when constructed, ensuring type-safe terminal manipulation without manual byte string construction.

### How do I move the cursor to a specific screen position?

Use **`Control.move_to(x, y)`** where `x` and `y` are zero-based coordinates. This method generates the ANSI sequence `\x1b[{y+1};{x+1}H`, translating Rich's zero-based indexing to the terminal's one-based coordinate system. For column-only movement, use **`Control.move_to_column(x)`** which emits `\x1b[{x}G` using the one-based column addressing native to ANSI terminals.

### Are control codes buffered or emitted immediately?

Control codes are queued through **`Console.control()`**, which adds them to the console's output stream buffer. They are emitted during the next render cycle alongside text segments, ensuring proper sequencing with styled output. For immediate emission, ensure the console is not buffering or explicitly flush the output.

### Can I combine multiple cursor movements into one operation?

Yes, **`Control`** objects support concatenation using the `+` operator. This combines multiple control sequences into a single `Segment`, reducing the number of write operations to the terminal. For example, `Control.move(y=-2) + Control.move_to_column(19)` moves the cursor up two rows then to column 20 in one atomic operation.