Skip to content

Commit 56fa99a

Browse files
committed
Move displaced line of top-anchored scroll region into scroll-back
Full-screen CLIs such as Codex in --no-alt-screen mode render through DECSTBM scroll regions anchored at the top of the screen and scroll by emitting newlines at the region bottom. VT100EmulatorBackend scrolled such a region in place and discarded the displaced top line, so no scroll-back history was created and the output could not be scrolled backwards. Like xterm and VTE, a newline at the bottom of a scroll region whose top margin is the top of the screen now moves the displaced top line into the scroll-back history, while the lines below the region keep their position on the screen. Scroll regions with a top margin below the top of the screen still scroll in place and discard the top line. The characterization test documenting the old behavior is flipped to assert that the history is created; the remaining scrolling guards are unchanged. #2680
1 parent c385363 commit 56fa99a

2 files changed

Lines changed: 41 additions & 13 deletions

File tree

terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackend.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,11 @@ private int doLineWrap() {
354354
*/
355355
private void doNewline() {
356356
if (fCursorLine == fScrollRegion.getBottomLine()) {
357-
scrollUp(1);
357+
if (fScrollRegion.getTopLine() == 0) {
358+
scrollTopAnchoredRegionUpIntoHistory();
359+
} else {
360+
scrollUp(1);
361+
}
358362
} else if (fCursorLine + 1 >= fLines) {
359363
int h = fTerminal.getHeight();
360364
fTerminal.addLine();
@@ -366,6 +370,28 @@ private void doNewline() {
366370
}
367371
}
368372

373+
/**
374+
* Scrolls a scroll region whose top margin is the top of the screen. Like in xterm or VTE,
375+
* the line displaced at the top of the region is moved into the scroll-back history instead
376+
* of being discarded, while the lines below the region keep their position on the screen
377+
* (https://github.com/eclipse-platform/eclipse.platform/issues/2680).
378+
* MUST be called from a synchronized block!
379+
*/
380+
private void scrollTopAnchoredRegionUpIntoHistory() {
381+
// adding a line moves the whole screen window up by one line: the former top line of the
382+
// screen (and of the region) becomes the newest scroll-back line and the new bottom line of
383+
// the screen is blank
384+
fTerminal.addLine();
385+
int regionBottom = fScrollRegion.getBottomLine();
386+
if (regionBottom < fLines - 1) {
387+
// lines below the region must not move: shift them back down by one line, which also
388+
// vacates the new bottom line of the region
389+
fTerminal.scroll(toAbsoluteLine(regionBottom), fLines - regionBottom, 1);
390+
}
391+
// the absolute line of the cursor may have changed
392+
setCursorLine(fCursorLine);
393+
}
394+
369395
@Override
370396
public void processNewline() {
371397
synchronized (fTerminal) {

terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackendTest.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,14 +1061,13 @@ public void testReverseLineFeedAtTopOfRegionScrollsDown() {
10611061
}
10621062

10631063
/**
1064-
* Characterization of the <em>current</em> behavior for a scroll region anchored at the top of
1065-
* the screen: a newline at the region bottom scrolls in place and discards the top line, creating
1066-
* no history. This is the behavior the planned fix for eclipse.platform issue 2680 will change so
1067-
* that the discarded line is added to the scroll-back instead. Until then this documents the
1068-
* status quo.
1064+
* Fix for eclipse.platform issue 2680: for a scroll region anchored at the top of the screen, a
1065+
* newline at the region bottom moves the displaced top line into the scroll-back history (like
1066+
* xterm/VTE) instead of discarding it. The lines below the region keep their position on the
1067+
* screen.
10691068
*/
10701069
@Test
1071-
public void testNewlineInTopAnchoredScrollRegionCurrentlyDiscardsTopLine() {
1070+
public void testNewlineInTopAnchoredScrollRegionMovesTopLineToHistory() {
10721071
ITerminalTextData term = makeITerminalTextData();
10731072
IVT100EmulatorBackend vt100 = makeBakend(term);
10741073
term.setMaxHeight(10);
@@ -1079,11 +1078,14 @@ public void testNewlineInTopAnchoredScrollRegionCurrentlyDiscardsTopLine() {
10791078
vt100.setCursorLine(3);
10801079
vt100.processNewline();
10811080

1082-
assertEquals(5, term.getHeight()); // currently no history is created
1083-
assertEquals("1111", new String(term.getChars(0))); // "0000" was discarded (lost)
1084-
assertEquals("2222", new String(term.getChars(1)));
1085-
assertEquals("3333", new String(term.getChars(2)));
1086-
assertNull(term.getChars(3));
1087-
assertEquals("4444", new String(term.getChars(4))); // footer below the region is untouched
1081+
assertEquals(6, term.getHeight()); // one line of history was created
1082+
assertEquals("0000", new String(term.getChars(0))); // ... holding the displaced top line
1083+
// the screen is now lines 1..5 of the model
1084+
assertEquals("1111", new String(term.getChars(1)));
1085+
assertEquals("2222", new String(term.getChars(2)));
1086+
assertEquals("3333", new String(term.getChars(3)));
1087+
assertNull(term.getChars(4)); // vacated line at the bottom of the region
1088+
assertEquals("4444", new String(term.getChars(5))); // footer below the region is untouched
1089+
assertEquals(3, vt100.getCursorLine()); // cursor stays at the bottom of the region
10881090
}
10891091
}

0 commit comments

Comments
 (0)