diff --git a/terminal/bundles/org.eclipse.terminal.control/META-INF/MANIFEST.MF b/terminal/bundles/org.eclipse.terminal.control/META-INF/MANIFEST.MF index ff5a3fb72be..0c618bbd154 100644 --- a/terminal/bundles/org.eclipse.terminal.control/META-INF/MANIFEST.MF +++ b/terminal/bundles/org.eclipse.terminal.control/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.terminal.control; singleton:=true -Bundle-Version: 1.1.200.qualifier +Bundle-Version: 1.1.300.qualifier Bundle-Activator: org.eclipse.terminal.internal.control.impl.TerminalPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackend.java b/terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackend.java index 4dfc1f1b560..8559df5fa7c 100644 --- a/terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackend.java +++ b/terminal/bundles/org.eclipse.terminal.control/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackend.java @@ -196,12 +196,37 @@ public void eraseToCursor() { @Override public void eraseAll() { synchronized (fTerminal) { + // What is on the screen goes into the history before it is erased, as in + // Windows Terminal and VTE, so that clearing the screen does not destroy + // what the user was reading. It matters on Windows, where ConPTY clears + // the screen at the start of every connection. Blank lines at the bottom + // of the screen are left out. Where the buffer is capped at the screen, + // as on an alternate screen, the lines simply go. + int used = fLines; + while (used > 0 && isBlank(toAbsoluteLine(used - 1))) { + used--; + } + for (int i = 0; i < used; i++) { + fTerminal.addLine(); + } for (int line = toAbsoluteLine(0); line < toAbsoluteLine(fLines); line++) { fTerminal.cleanLine(line); } } } + private boolean isBlank(int line) { + char[] chars = fTerminal.getChars(line); + if (chars != null) { + for (char c : chars) { + if (c != '\000' && c != ' ') { + return false; + } + } + } + return true; + } + @Override public void eraseLine() { synchronized (fTerminal) { diff --git a/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackendTest.java b/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackendTest.java index aecbc640616..8a7391962e1 100644 --- a/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackendTest.java +++ b/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorBackendTest.java @@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import org.eclipse.terminal.internal.model.TerminalTextData; import org.eclipse.terminal.internal.model.TerminalTextDataStore; import org.eclipse.terminal.internal.model.TerminalTextTestHelper; import org.eclipse.terminal.model.ITerminalTextData; @@ -318,7 +319,30 @@ public void testEraseAll() { vt100.setDimensions(3, 4); fill(term, "0000\n" + "1111\n" + "2222\n" + "3333\n" + "4444\n" + "5555"); vt100.eraseAll(); - assertEqualsTerm("0000\n" + "1111\n" + "2222\n" + " \n" + " \n" + " ", toMultiLineText(term)); + // the screen goes into the history; with no room to grow, the oldest lines make way + assertEqualsTerm("3333\n" + "4444\n" + "5555\n" + " \n" + " \n" + " ", toMultiLineText(term)); + } + + @Test + public void testEraseAllKeepsTheScreenInHistory() { + // also on the buffer the terminal actually uses + for (ITerminalTextData term : new ITerminalTextData[] { makeITerminalTextData(), new TerminalTextData() }) { + IVT100EmulatorBackend vt100 = makeBakend(term); + term.setMaxHeight(100); + vt100.setDimensions(4, 4); + fill(term, "0000\n" + "1111\n" + "2222\n" + "3333\n" + "4444\n" + " "); + vt100.setCursor(2, 1); + vt100.eraseAll(); + // the screen was 2222, 3333, 4444 and a blank line, which is not kept + assertEqualsTerm("0000\n" + "1111\n" + "2222\n" + "3333\n" + "4444\n" + " \n" + " \n" + " \n" + " ", + toMultiLineText(term)); + // erasing does not move the cursor + assertEquals(2, vt100.getCursorLine()); + assertEquals(1, vt100.getCursorColumn()); + // a blank screen adds nothing + vt100.eraseAll(); + assertEquals(9, term.getHeight()); + } } @Test diff --git a/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorTest.java b/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorTest.java index d7c5692f1a9..b1c9ec596a3 100644 --- a/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorTest.java +++ b/terminal/tests/org.eclipse.terminal.test/src/org/eclipse/terminal/internal/emulator/VT100EmulatorTest.java @@ -274,6 +274,21 @@ public void testClear() { assertAll(() -> assertCursorLocation(0, 0), () -> assertTextEquals("")); } + @Test + public void testClearScreenKeepsItInHistory() { + data.setMaxHeight(1000); + for (int i = 0; i < 30; i++) { + run("Hello " + i + "\r\n"); + } + // what ConPTY sends at the start of every connection on Windows + run(CLEAR_ENTIRE_SCREEN + "\u001b[m" + CURSOR_POSITION_TOP_LEFT + "prompt$ "); + int top = data.getHeight() - WINDOW_LINES; // first line of the screen + assertAll(() -> assertEquals("Hello 29", new String(data.getChars(top - 1)).trim()), + () -> assertEquals("Hello 0", new String(data.getChars(0)).trim()), + () -> assertEquals("prompt$", new String(data.getChars(top)).replace('\000', ' ').trim()), + () -> assertCursorLocation(top, 8)); // the top of the screen, counted in the buffer + } + /** * Runs what "up arrow" would send back to terminal in less/man/etc. */