# Text Reflow (?2028)

> Say whether lines from the cursor down may be rewrapped when the terminal is resized.

- **Sequence:** `CSI ? 2028 h/l`
- **Specification:** [Line Reflow Reconfiguration, Contour VT extensions](https://github.com/contour-terminal/contour/blob/5a6be846fd8d076e6ae2d6abd0a9b3ef69cab176/docs/vt-extensions/line-reflow-mode.md)

Most terminals now *reflow* when they are resized: a line that wrapped is
rewrapped to the new width, rather than cut off when the window narrows or
left broken when it widens. That suits a shell's output, but not a program
that lays out its own lines and would rather they stayed where it put them.
`CSI ? 2028 l` turns reflow off for the line the cursor is on and the lines
below it, and `CSI ? 2028 h` turns it back on.

It is neither xterm's nor DEC's. Its definition is
[Line Reflow Reconfiguration](https://github.com/contour-terminal/contour/blob/5a6be846fd8d076e6ae2d6abd0a9b3ef69cab176/docs/vt-extensions/line-reflow-mode.md),
kept by the Contour terminal's authors with their other VT extensions, read
at commit `5a6be84`. That is the whole of it: the two settings, and DECRQM
to find out whether a terminal has the mode. It does not say what the mode
is to begin with, what "the following lines" are, or what a line keeps when
the mode changes after it was written.

Contour's own implementation fills some of that in
([`Terminal::setMode`](https://github.com/contour-terminal/contour/blob/v0.8.0.9335/src/vtbackend/screen/Terminal.cpp#L6580-L6589)).
The mode begins as Contour's `allowReflowOnResize` setting, which is on by
default, and [DECSTR](https://control-codes.page/csi/decstr/index.html.md) and [RIS](https://control-codes.page/esc/ris/index.html.md) put it back there
([`Terminal.cpp`](https://github.com/contour-terminal/contour/blob/v0.8.0.9335/src/vtbackend/screen/Terminal.cpp#L6813),
[`Terminal.cpp`](https://github.com/contour-terminal/contour/blob/v0.8.0.9335/src/vtbackend/screen/Terminal.cpp#L6984)).
Reflow is a property of each line rather than of the screen. Resetting the
mode marks the cursor's line and every line below it on the page as not to
be rewrapped, but setting it marks every line of the page, above the cursor
too. Either way only the main screen is affected, and with
`allowReflowOnResize` off the mode can be changed but changes nothing.

A default xterm has no mode `2028`, and does not reflow at all. It answers
DECRQM for the mode with `0`, as it does for any mode it does not know
([`do_dec_rqm`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L5855-L5869)).
The cases follow xterm. A case cannot resize the screen, so they cannot
show reflow either way; they check what DECRQM says and that the mode
changes nothing on the screen.

libghostty-vt does not recognize mode `2028` either, and answers DECRQM for
it with `0`. When it is resized it reflows the main screen if
[DECAWM](https://control-codes.page/modes/decawm/index.html.md) is set, and never the alternate screen, and it
has no way to turn reflow off for some lines and not others.

## Support

| Terminal | Version | Support | Notes |
| --- | --- | --- | --- |
| VT220 | [manual](https://vt100.net/docs/vt220-rm/), 2nd ed., 1984 | No | not in the manual |
| VT510 | [manual](https://vt100.net/docs/vt510-rm/), 1st ed., 1993 | No | not in the manual; not in [Table 5-6](https://vt100.net/docs/vt510-rm/DECRPM.html) |
| xterm | patch 412, [xterm-411a](https://github.com/ThomasDickey/xterm-snapshots/tree/xterm-411a) | No | not recognized; DECRQM reports `0` |
| libghostty-vt | [0f171f6](https://github.com/ghostty-org/ghostty/tree/0f171f650a1cbbd6df4a2573b6b0c7de57cc6d90) | No | not recognized; DECRQM reports `0`; reflows the main screen whenever DECAWM is set |
| VTE | 0.84.1, [source](https://gitlab.gnome.org/GNOME/vte/-/tree/0.84.1) | No | known but fixed: DECRQM reports `4`, permanently reset ([`modes.py`](https://github.com/GNOME/vte/blob/0.84.1/src/modes.py#L1056)) |

## Validation

### REFLOW-1: A default xterm does not recognize it

Input, one step per line:

```text
\e[?2028$p
\e[?2028l
\e[?2028$p
```

Expected screen:

```text
|____|
reply \e[?2028;0$y\e[?2028;0$y
```

### REFLOW-2: The screen does not change

Input, one step per line:

```text
AB
\e[?2028l
CD
\e[?2028h
```

Expected screen:

```text
|ABCD|
|____|
cursor 1,4
pending-wrap yes
```

---

This is the Markdown version of <https://control-codes.page/modes/reflow/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
