Fix terminal resize after splitting panes (#1249)

This commit is contained in:
Mohamed Boudra
2026-05-31 15:42:39 +08:00
committed by GitHub
parent d1f37b5d72
commit 67133e3ebc
10 changed files with 250 additions and 103 deletions
+58 -52
View File
@@ -214,6 +214,7 @@ export function TerminalPane({
const pendingTerminalInputRef = useRef<PendingTerminalInput[]>([]);
const keyboardRefitTimeoutsRef = useRef<Array<ReturnType<typeof setTimeout>>>([]);
const lastAutoFocusKeyRef = useRef<string | null>(null);
const lastPaneFocusResizeKeyRef = useRef<string | null>(null);
const initialSnapshot = workspaceTerminalSession.snapshots.get({ terminalId });
useEffect(() => {
@@ -252,7 +253,7 @@ export function TerminalPane({
);
useEffect(() => {
if (isMobile || !isWorkspaceFocused || !isPaneFocused || !terminalId) {
if (isMobile || !isPaneFocused || !terminalId) {
lastAutoFocusKeyRef.current = null;
return;
}
@@ -263,15 +264,36 @@ export function TerminalPane({
}
lastAutoFocusKeyRef.current = nextFocusKey;
if (!isWorkspaceFocused) {
return;
}
requestTerminalFocus();
}, [isMobile, isPaneFocused, isWorkspaceFocused, requestTerminalFocus, scopeKey, terminalId]);
useEffect(() => {
if (isPaneFocused && isWorkspaceFocused && isAppVisible && terminalId) {
lastSentTerminalSizeRef.current = null;
requestTerminalReflow();
if (!isPaneFocused || !terminalId) {
lastPaneFocusResizeKeyRef.current = null;
return;
}
}, [isAppVisible, isPaneFocused, isWorkspaceFocused, requestTerminalReflow, terminalId]);
const focusResizeKey = `${scopeKey}:${terminalId}`;
if (lastPaneFocusResizeKeyRef.current === focusResizeKey) {
return;
}
lastPaneFocusResizeKeyRef.current = focusResizeKey;
if (!isWorkspaceFocused) {
return;
}
lastSentTerminalSizeRef.current = null;
requestTerminalReflow();
}, [isPaneFocused, isWorkspaceFocused, requestTerminalReflow, scopeKey, terminalId]);
const handleTerminalFocus = useCallback(() => {
lastSentTerminalSizeRef.current = null;
requestTerminalReflow();
}, [requestTerminalReflow]);
const clearKeyboardRefitTimeouts = useCallback(() => {
if (keyboardRefitTimeoutsRef.current.length === 0) {
@@ -308,25 +330,6 @@ export function TerminalPane({
[pulseKeyboardRefits],
);
useEffect(() => {
if (!isWorkspaceFocused || !terminalId) {
return;
}
// Focus transitions can temporarily report stale dimensions.
// Pulse forced refits so xterm fills the pane when returning to a terminal.
const timeoutHandles = TERMINAL_REFIT_DELAYS_MS.map((delayMs) =>
setTimeout(() => {
requestTerminalReflow();
}, delayMs),
);
return () => {
for (const handle of timeoutHandles) {
clearTimeout(handle);
}
};
}, [isWorkspaceFocused, requestTerminalReflow, terminalId]);
useEffect(() => {
if (!client || !isConnected || !isWorkspaceFocused) {
return;
@@ -375,7 +378,7 @@ export function TerminalPane({
const controller = new TerminalStreamController({
client,
getPreferredSize: () => measuredTerminalSizeRef.current,
getPreferredSize: () => lastSentTerminalSizeRef.current,
onOutput: ({ terminalId: outputTerminalId, data }) => {
if (!isWorkspaceFocused || terminalIdRef.current !== outputTerminalId) {
return;
@@ -605,33 +608,35 @@ export function TerminalPane({
],
);
const handleTerminalResize = useStableEvent((input: { rows: number; cols: number }) => {
const { rows, cols } = input;
if (rows <= 0 || cols <= 0) {
return;
}
const normalizedRows = Math.floor(rows);
const normalizedCols = Math.floor(cols);
const nextSize = { rows: normalizedRows, cols: normalizedCols };
measuredTerminalSizeRef.current = nextSize;
if (!client || !terminalId || !isPaneFocused || !isWorkspaceFocused || !isAppVisible) {
return;
}
const previousSent = lastSentTerminalSizeRef.current;
if (
previousSent &&
previousSent.rows === normalizedRows &&
previousSent.cols === normalizedCols
) {
return;
}
lastSentTerminalSizeRef.current = nextSize;
client.sendTerminalInput(terminalId, {
type: "resize",
rows: normalizedRows,
cols: normalizedCols,
});
});
const handleTerminalResize = useStableEvent(
(input: { rows: number; cols: number; shouldClaim: boolean }) => {
const { rows, cols } = input;
if (rows <= 0 || cols <= 0) {
return;
}
const normalizedRows = Math.floor(rows);
const normalizedCols = Math.floor(cols);
const nextSize = { rows: normalizedRows, cols: normalizedCols };
measuredTerminalSizeRef.current = nextSize;
if (!input.shouldClaim || !client || !terminalId || !isWorkspaceFocused || !isAppVisible) {
return;
}
const previousSent = lastSentTerminalSizeRef.current;
if (
previousSent &&
previousSent.rows === normalizedRows &&
previousSent.cols === normalizedCols
) {
return;
}
lastSentTerminalSizeRef.current = nextSize;
client.sendTerminalInput(terminalId, {
type: "resize",
rows: normalizedRows,
cols: normalizedCols,
});
},
);
const handleTerminalKey = useCallback(
async (input: { key: string; ctrl: boolean; shift: boolean; alt: boolean; meta: boolean }) => {
@@ -764,6 +769,7 @@ export function TerminalPane({
onSwipeRight={handleSwipeRight}
onSwipeLeft={handleSwipeLeft}
onInput={handleTerminalData}
onFocus={handleTerminalFocus}
onResize={handleTerminalResize}
onTerminalKey={handleTerminalKey}
onInputModeChange={handleInputModeChange}