feat(terminal): implement clearTerminalAll function for enhanced terminal management (#579)
- Added the `clearTerminalAll` function to clear the terminal's output while preserving cursor position and handling shell redraws. - Updated the `XTerminal` component to utilize `clearTerminalAll` for resetting the terminal state. - Introduced tests to verify the functionality of `clearTerminalAll`, ensuring it clears scrollback without altering the CMD cursor row and requests redraws for shells that handle Ctrl+L.
This commit is contained in:
1 parent
2ce1972ea3
commit
42364ea0b5
3 files changed
+70
-1
No files matched your search
@@ -134,6 +134,7 @@ import {
|
||||
shouldBlockXTerminalData,
|
||||
} from "./xterminalKeyboardInput";
|
||||
import {
|
||||
clearTerminalAll,
|
||||
markTerminalUserInput,
|
||||
registerTerminalUserInputMarker,
|
||||
} from "@/lib/terminalControlInput";
|
||||
@@ -1752,7 +1753,9 @@ export default function XTerminal({
|
||||
if (appLockedRef.current) return;
|
||||
lineTimestampsRef.current = new Map();
|
||||
gutterLineOffsetRef.current = 0;
|
||||
terminal.reset();
|
||||
clearTerminalAll(terminal, {
|
||||
shellRedraw: sessionTypeRef.current !== "Local" || !isWindows,
|
||||
});
|
||||
focusTerminal();
|
||||
requestGutterRefresh();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Terminal } from "@xterm/xterm";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
clearTerminalAll,
|
||||
registerTerminalUserInputMarker,
|
||||
sendTerminalClearInput,
|
||||
} from "./terminalControlInput";
|
||||
@@ -24,4 +25,54 @@ describe("terminal control input origin", () => {
|
||||
expect(terminal.focus).toHaveBeenCalledOnce();
|
||||
unregister();
|
||||
});
|
||||
|
||||
it("clears scrollback without sending Ctrl+L or changing the CMD cursor row", async () => {
|
||||
const canvas = vi
|
||||
.spyOn(HTMLCanvasElement.prototype, "getContext")
|
||||
.mockReturnValue({
|
||||
measureText: () => ({ width: 10 }),
|
||||
} as unknown as CanvasRenderingContext2D);
|
||||
const { Terminal: XTerminal } = await import("@xterm/xterm");
|
||||
const terminal = new XTerminal({ cols: 20, rows: 3 });
|
||||
await new Promise<void>((resolve) =>
|
||||
terminal.write(
|
||||
"first line\r\nold line\r\nsecond line\r\nprompt> abcdef\x1b[?1h",
|
||||
resolve,
|
||||
),
|
||||
);
|
||||
const input = vi.fn();
|
||||
const disposable = terminal.onData(input);
|
||||
|
||||
expect(terminal.buffer.active.baseY).toBeGreaterThan(0);
|
||||
clearTerminalAll(terminal);
|
||||
await new Promise<void>((resolve) => terminal.write("", resolve));
|
||||
|
||||
expect(terminal.buffer.active.length).toBe(3);
|
||||
expect(terminal.buffer.active.baseY).toBe(0);
|
||||
expect(terminal.buffer.active.cursorY).toBe(2);
|
||||
expect(terminal.buffer.active.cursorX).toBe(14);
|
||||
expect(terminal.buffer.active.getLine(0)?.translateToString(true)).toBe("");
|
||||
expect(terminal.buffer.active.getLine(1)?.translateToString(true)).toBe("");
|
||||
expect(terminal.buffer.active.getLine(2)?.translateToString(true)).toBe("prompt> abcdef");
|
||||
expect(input).not.toHaveBeenCalled();
|
||||
expect(terminal.modes.applicationCursorKeysMode).toBe(true);
|
||||
|
||||
disposable.dispose();
|
||||
terminal.dispose();
|
||||
canvas.mockRestore();
|
||||
});
|
||||
|
||||
it("requests a redraw for shells that handle Ctrl+L", async () => {
|
||||
const { Terminal: XTerminal } = await import("@xterm/xterm");
|
||||
const terminal = new XTerminal({ cols: 20, rows: 3 });
|
||||
await new Promise<void>((resolve) => terminal.write("prompt> ", resolve));
|
||||
const input = vi.fn();
|
||||
const disposable = terminal.onData(input);
|
||||
|
||||
clearTerminalAll(terminal, { shellRedraw: true });
|
||||
|
||||
expect(input).toHaveBeenCalledWith("\x0c");
|
||||
disposable.dispose();
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
@@ -28,3 +28,18 @@ export function sendTerminalClearInput(
|
||||
terminal.focus();
|
||||
}
|
||||
}
|
||||
|
||||
export function clearTerminalAll(
|
||||
terminal: Terminal,
|
||||
options: { shellRedraw?: boolean } = {},
|
||||
): void {
|
||||
const { cursorX, cursorY } = terminal.buffer.active;
|
||||
terminal.clearSelection();
|
||||
terminal.clear();
|
||||
if (options.shellRedraw) {
|
||||
sendTerminalClearInput(terminal);
|
||||
} else if (cursorY > 0) {
|
||||
// Keep ConPTY's viewport cursor coordinates while discarding old output.
|
||||
terminal.write(`\x1b[1;1H\x1b[${cursorY}L\x1b[${cursorY + 1};${cursorX + 1}H`);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user