Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 44 additions & 16 deletions components/terminal/TerminalSurface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
const terminalRef = useRef<Terminal | null>(null);
const fitAddonRef = useRef<FitAddon | null>(null);
const activeSessionIdRef = useRef<string | null>(null);
const pendingInputRef = useRef<string[]>([]);
const resizeObserverRef = useRef<ResizeObserver | null>(null);
const inputListenerRef = useRef<IDisposable | null>(null);
const onInputRef = useRef<TerminalSurfaceProps["onInput"] | null>(
Expand All @@ -77,6 +78,26 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
| null
>(null);

const dispatchInput = useCallback((sessionId: string, chunk: string) => {
if (!chunk) {
return;
}

const processed = onInputRef.current?.({ sessionId, input: chunk });

if (processed === null) {
return;
}

const outbound = typeof processed === "string" ? processed : chunk;

if (!outbound) {
return;
}

sendTerminalInputRef.current?.({ sessionId, input: outbound });
}, []);

const runFitAndEmit = useCallback(() => {
pendingFitFrameRef.current = null;

Expand Down Expand Up @@ -224,25 +245,17 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
let dataDisposable: IDisposable | undefined;
let binaryDisposable: IDisposable | undefined;

const handleInput = (input: string) => {
const sessionId = activeSessionIdRef.current;
if (!sessionId) {
return;
}

const processed = onInputRef.current?.({ sessionId, input });

if (processed === null) {
const handleInput = (chunk: string) => {
if (!chunk) {
return;
}

const outbound = typeof processed === "string" ? processed : input;

if (!outbound) {
const sessionId = activeSessionIdRef.current;
if (!sessionId) {
pendingInputRef.current.push(chunk);
return;
}

sendTerminalInputRef.current?.({ sessionId, input: outbound });
dispatchInput(sessionId, chunk);
};

if (containerRef.current) {
Expand Down Expand Up @@ -292,7 +305,7 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
fitAddonRef.current = null;
resizeObserverRef.current = null;
};
}, [scheduleFitAndEmit]);
}, [scheduleFitAndEmit, dispatchInput]);

useEffect(() => {
if (!terminalRef.current) {
Expand Down Expand Up @@ -328,6 +341,12 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
const handleReady = (payload: { sessionId: string }) => {
activeSessionIdRef.current = payload.sessionId;
lastKnownGeometryRef.current = null;
if (pendingInputRef.current.length > 0) {
for (const chunk of pendingInputRef.current) {
dispatchInput(payload.sessionId, chunk);
}
pendingInputRef.current = [];
}
queueMicrotask(() => {
scheduleFitAndEmit();
});
Expand Down Expand Up @@ -375,6 +394,7 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
}
activeSessionIdRef.current = null;
lastKnownGeometryRef.current = null;
pendingInputRef.current = [];
onExit?.(payload);
};

Expand All @@ -389,7 +409,15 @@ const TerminalSurface = forwardRef<TerminalSurfaceHandle, TerminalSurfaceProps>(
socket.off("terminal:error", handleError);
socket.off("terminal:exit", handleExit);
};
}, [socket, onReady, onData, onError, onExit, scheduleFitAndEmit]);
}, [
socket,
onReady,
onData,
onError,
onExit,
scheduleFitAndEmit,
dispatchInput,
]);

useImperativeHandle(
ref,
Expand Down