further simplify and cleanup pty<->terminal comms

This commit is contained in:
Quinten Kock 2025-11-18 01:43:27 +01:00
parent a437ccebc9
commit 9ec9ff1ab4
4 changed files with 28 additions and 37 deletions

View File

@ -53,21 +53,16 @@ export class Terminal implements Displayable {
// Set up data handling (subscribe/unsubscribe) // Set up data handling (subscribe/unsubscribe)
this.unsubTerminalData = window.electronAPI.onTerminalData( this.unsubTerminalData = window.electronAPI.onTerminalData(
(id, data) => { this.terminalId,
if (id === this.terminalId) { (data) => this.term.write(data),
this.term.write(data);
}
},
); );
this.unsubTerminalExit = window.electronAPI.onTerminalExit( this.unsubTerminalExit = window.electronAPI.onTerminalExit(
(id, exitCode) => { this.terminalId,
if (id === this.terminalId) { (exitCode) =>
this.term.writeln( this.term.writeln(
`\r\n[Process exited with code ${exitCode}]`, `\r\n[Process exited with code ${exitCode}]`,
); ),
}
},
); );
// Handle user input // Handle user input

View File

@ -33,6 +33,7 @@ export class TerminalManager {
}; };
ptyProcess.onData((data) => { ptyProcess.onData((data) => {
console.log(`Terminal ${id} data:`, data);
event.sender.send("terminal:data", id, data); event.sender.send("terminal:data", id, data);
}); });

View File

@ -8,21 +8,20 @@ import type { FolderTree } from "./types/global";
// and forward events to subscribed callbacks. Each `onTerminal*` returns an // and forward events to subscribed callbacks. Each `onTerminal*` returns an
// unsubscribe function so individual renderer components can remove only // unsubscribe function so individual renderer components can remove only
// their own listeners. // their own listeners.
const terminalDataCallbacks = new Set<(id: string, data: string) => void>(); const terminalDataCallbacks = new Map<string, (data: string) => void>();
const terminalExitCallbacks = new Set< const terminalExitCallbacks = new Map<string, (exitCode: number) => void>();
(id: string, exitCode: number, signal: string) => void
>();
ipcRenderer.on("terminal:data", (_ev, id: string, data: string) => { ipcRenderer.on("terminal:data", (_ev, id: string, data: string) => {
for (const cb of terminalDataCallbacks) cb(id, data); const cb = terminalDataCallbacks.get(id);
if (cb) cb(data);
else console.warn(`No data callback for terminal ${id}`);
}); });
ipcRenderer.on( ipcRenderer.on("terminal:exit", (_ev, id: string, exitCode: number) => {
"terminal:exit", const cb = terminalExitCallbacks.get(id);
(_ev, id: string, exitCode: number, signal: string) => { if (cb) cb(exitCode);
for (const cb of terminalExitCallbacks) cb(id, exitCode, signal); else console.warn(`No exit callback for terminal ${id}`);
}, });
);
contextBridge.exposeInMainWorld("electronAPI", { contextBridge.exposeInMainWorld("electronAPI", {
openFolder: () => openFolder: () =>
@ -83,15 +82,13 @@ contextBridge.exposeInMainWorld("electronAPI", {
ipcRenderer.invoke("terminal:close", id) as Promise<boolean>, ipcRenderer.invoke("terminal:close", id) as Promise<boolean>,
// Terminal events (subscribe/unsubscribe) // Terminal events (subscribe/unsubscribe)
onTerminalData: (callback: (id: string, data: string) => void) => { onTerminalData: (id: string, callback: (data: string) => void) => {
terminalDataCallbacks.add(callback); terminalDataCallbacks.set(id, callback);
return () => terminalDataCallbacks.delete(callback); return () => terminalDataCallbacks.delete(id);
}, },
onTerminalExit: ( onTerminalExit: (id: string, callback: (exitCode: number) => void) => {
callback: (id: string, exitCode: number, signal: string) => void, terminalExitCallbacks.set(id, callback);
) => { return () => terminalExitCallbacks.delete(id);
terminalExitCallbacks.add(callback);
return () => terminalExitCallbacks.delete(callback);
}, },
}); });

10
src/types/global.d.ts vendored
View File

@ -48,14 +48,12 @@ declare global {
writeToTerminal: (id: string, data: string) => Promise<boolean>; writeToTerminal: (id: string, data: string) => Promise<boolean>;
closeTerminal: (id: string) => Promise<boolean>; closeTerminal: (id: string) => Promise<boolean>;
onTerminalData: ( onTerminalData: (
callback: (id: string, data: string) => void, id: string,
callback: (data: string) => void,
) => () => void; ) => () => void;
onTerminalExit: ( onTerminalExit: (
callback: ( id: string,
id: string, callback: (exitCode: number) => void,
exitCode: number,
signal: string,
) => void,
) => () => void; ) => () => void;
removeAllTerminalListeners: () => void; removeAllTerminalListeners: () => void;
}; };