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)
this.unsubTerminalData = window.electronAPI.onTerminalData(
(id, data) => {
if (id === this.terminalId) {
this.term.write(data);
}
},
this.terminalId,
(data) => this.term.write(data),
);
this.unsubTerminalExit = window.electronAPI.onTerminalExit(
(id, exitCode) => {
if (id === this.terminalId) {
this.term.writeln(
`\r\n[Process exited with code ${exitCode}]`,
);
}
},
this.terminalId,
(exitCode) =>
this.term.writeln(
`\r\n[Process exited with code ${exitCode}]`,
),
);
// Handle user input

View File

@ -33,6 +33,7 @@ export class TerminalManager {
};
ptyProcess.onData((data) => {
console.log(`Terminal ${id} data:`, 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
// unsubscribe function so individual renderer components can remove only
// their own listeners.
const terminalDataCallbacks = new Set<(id: string, data: string) => void>();
const terminalExitCallbacks = new Set<
(id: string, exitCode: number, signal: string) => void
>();
const terminalDataCallbacks = new Map<string, (data: string) => void>();
const terminalExitCallbacks = new Map<string, (exitCode: number) => void>();
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(
"terminal:exit",
(_ev, id: string, exitCode: number, signal: string) => {
for (const cb of terminalExitCallbacks) cb(id, exitCode, signal);
},
);
ipcRenderer.on("terminal:exit", (_ev, id: string, exitCode: number) => {
const cb = terminalExitCallbacks.get(id);
if (cb) cb(exitCode);
else console.warn(`No exit callback for terminal ${id}`);
});
contextBridge.exposeInMainWorld("electronAPI", {
openFolder: () =>
@ -83,15 +82,13 @@ contextBridge.exposeInMainWorld("electronAPI", {
ipcRenderer.invoke("terminal:close", id) as Promise<boolean>,
// Terminal events (subscribe/unsubscribe)
onTerminalData: (callback: (id: string, data: string) => void) => {
terminalDataCallbacks.add(callback);
return () => terminalDataCallbacks.delete(callback);
onTerminalData: (id: string, callback: (data: string) => void) => {
terminalDataCallbacks.set(id, callback);
return () => terminalDataCallbacks.delete(id);
},
onTerminalExit: (
callback: (id: string, exitCode: number, signal: string) => void,
) => {
terminalExitCallbacks.add(callback);
return () => terminalExitCallbacks.delete(callback);
onTerminalExit: (id: string, callback: (exitCode: number) => void) => {
terminalExitCallbacks.set(id, callback);
return () => terminalExitCallbacks.delete(id);
},
});

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

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