Skip to content

Terminal: keep the screen in the history when it is cleared - #2973

Merged
akurtakov merged 1 commit into
eclipse-platform:masterfrom
insjang:ed2-scrollback
Nov 4, 2026
Merged

akurtakov merged 1 commit into
eclipse-platform:masterfrom
insjang:ed2-scrollback

Conversation

@insjang

@insjang insjang commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Erase in display (CSI 2 J) destroyed what was on the screen. It now moves it into the history first, the way Windows Terminal and VTE handle it, and then erases.

Why it matters. On Windows the local terminal runs through ConPTY, and ConPTY starts every connection with CSI 2 J followed by CSI H. Reconnecting a terminal therefore erased as many lines of the previous session as the screen was high: after seq 1 200 in a 31-line terminal, a reconnect kept only 1 to 171. The same happens whenever a program clears the screen, taking the user's last screen of output with it. This was captured from a real ConPTY session (wsl.exe) and replayed through the emulator; the loss is the same on current master.

Details:

  • Blank lines at the bottom of the screen are not moved into the history, so clearing an empty or half-empty screen does not pad the history with blank lines.
  • The cursor does not move, as ED requires.
  • Where the buffer is at its maximum, the oldest lines make way. Where the buffer is capped at the screen height nothing is kept, so a screen with no history stays without one.
  • CSI 3 J still clears the history, so clear (CSI H CSI 2 J CSI 3 J) empties everything as before.

xterm itself erases without keeping the screen; this follows the terminals most users on Windows and Linux compare Eclipse's terminal with.

Tests: testEraseAll now expects the screen in the history; testEraseAllKeepsTheScreenInHistory covers the blank lines at the bottom and the cursor, on both TerminalTextDataStore and TerminalTextData; testClearScreenKeepsItInHistory runs the sequence ConPTY sends through the emulator. All three fail without the change.

@insjang

insjang commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

Related work, so the two are not mistaken for duplicates: #2764 by @vogella (for #2680, Codex CLI cannot scroll back) moves the line displaced at the top of a scroll region into the history. This PR covers a different path, erase in display (CSI 2 J), which ConPTY sends at the start of every connection and which programs send to clear the screen. Both feed the history and they complement each other. They touch nearby code in VT100EmulatorBackend, so whichever lands second may need a small rebase, which I am happy to do.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    54 files  ± 0      54 suites  ±0   38m 22s ⏱️ + 1m 40s
 4 973 tests + 5   4 951 ✅ + 5   22 💤 ±0  0 ❌ ±0 
12 810 runs  +15  12 656 ✅ +15  154 💤 ±0  0 ❌ ±0 

Results for commit b66ec72. ± Comparison against base commit 164c81a.

♻️ This comment has been updated with latest results.

@insjang

insjang commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on master, one commit, ea4ad3c; the version bump is no longer needed, master is at 1.1.300 already. All terminal tests pass.

How to test, in a runtime Eclipse with this org.eclipse.terminal.control, Terminal view:

  1. ConPTY reconnect (Windows, local terminal): seq 1 200, then disconnect and connect the terminal again.
    Expected: scrolling back shows 1 to 200. Before this change the last screen's worth of lines (171 to 200 in a 31-line view) was lost.
  2. CSI 2 J alone: seq 1 50; printf '\e[2J'
    Expected: the screen is blank, the cursor did not move, and scrolling back shows 1 to 50.
  3. A half-empty screen adds no blank lines: printf '\e[H\e[2J'; echo one; printf '\e[2J', then scroll back.
    Expected: "one" right above the screen, with no run of empty lines before it.
  4. clear still empties everything (it also sends CSI 3 J): seq 1 50; clear, scroll back: nothing.
  5. On the alternate screen nothing is kept: with Terminal: implement the alternate screen buffer (DEC mode 1049) #2899, less a file and press Ctrl+L, then quit: the history has no pages of the file.

Unit tests: testEraseAll (now expects the screen in the history), testEraseAllKeepsTheScreenInHistory (blank lines at the bottom, the cursor; TerminalTextDataStore and TerminalTextData) and testClearScreenKeepsItInHistory (the sequence ConPTY sends, through the emulator).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Buffer growth leaves the model cursor at its old absolute line, so CSI 2 J can move the visible cursor to the wrong row or into history unless its screen-relative position is restored.

1 open issue
What changed in this PR

This PR preserves Eclipse terminal output in history when CSI 2 J clears the screen, preventing output loss during ConPTY reconnections on Windows.

Changes:

  • Moves screen contents into history before erasing, excluding trailing blank lines.
  • Updates backend tests for history retention, buffer limits, and cursor position.
  • Adds an emulator regression test for the ConPTY startup sequence.
File Description
terminal/​tests/​org.eclipse.terminal.test/​src/​org/​eclipse/​terminal/​internal/​emulator/​VT100EmulatorTest.java Tests history preservation through the ConPTY clear-screen sequence.
terminal/​tests/​org.eclipse.terminal.test/​src/​org/​eclipse/​terminal/​internal/​emulator/​VT100EmulatorBackendTest.java Updates erase expectations and tests blank-line trimming and cursor preservation.
terminal/​bundles/​org.eclipse.terminal.control/​src/​org/​eclipse/​terminal/​internal/​emulator/​VT100EmulatorBackend.java Saves screen contents to history before clearing the display.

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

History handling still merges copied lines at a wrapped boundary and appends alternate-screen redraws to normal scrollback, potentially evicting earlier shell output.

2 open issues
1 resolved since last review

Review effort: Balanced

@insjang

insjang commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Fixed in db6cafb: after the lines go into the history the cursor is set again on its row of the screen, so the model's cursor follows; testEraseAllKeepsTheScreenInHistory now checks it (7, was 4).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Discarding a blank continuation row leaves the preceding history row marked as wrapped, causing copied text to concatenate old output with the new prompt without a newline.

2 open issues

Review effort: Balanced

@akurtakov

Copy link
Copy Markdown
Member

This depends on #2899. On master the alternate screen is still ignored (modes 47/1047/1049), so full screen programs draw on the main buffer and every CSI 2 J they send would now push a screen of their UI into the history, as Copilot noted above. With #2899 the buffer is capped at the screen height while the alternate screen is showing, so these addLine() calls just drop lines there, which is what the code comment already assumes. I'd merge #2899 first and then this one.

@insjang
insjang force-pushed the ed2-scrollback branch 2 times, most recently from 456cf31 to 380c638 Compare November 4, 2026 15:44
@akurtakov
akurtakov requested a balanced review from Copilot November 4, 2026 16:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Screen clearing retains a wrapped spaces-only row without following its continuation, causing copied text across the history boundary to join old output with new text without a newline.

1 open issue
2 resolved since last review

Review effort: Balanced

Erase in display (CSI 2 J) now moves what is on the screen into the
history before erasing it, as Windows Terminal and VTE do, instead of
destroying it. Blank lines at the bottom of the screen are left out,
except the rows a line runs on to, so the history ends where a line
ends, and the cursor does not move. Where the buffer cannot grow, the oldest
lines make way; on a buffer capped at the screen height nothing is kept,
as before.

This matters most on Windows: ConPTY starts every connection with
CSI 2 J CSI H, so reconnecting a terminal erased as many lines of the
previous session as the screen was high, and a program that clears the
screen took the user's last screen of output with it. CSI 3 J still
clears the history, so "clear" empties everything as it did.

The cursor stays on its row of the screen, in the model as well, however
far the screen moved down the buffer.

The alternate screen (modes 47, 1047 and 1049) is capped at the screen
height and keeps no history, so a program redrawing there with CSI 2 J
does not push its old frames into the scrollback: they are gone when the
normal screen comes back.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the change that preserves cleared terminal output in scrollback.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@akurtakov
akurtakov merged commit c49150d into eclipse-platform:master Nov 4, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants