Skip to content

Commit 513ce1e

Browse files
committed
feat: save pid of opened terminal and restore it
save the pid of terminal tab in localstorage and restore when app reopened
1 parent 5e97c37 commit 513ce1e

File tree

2 files changed

+139
-1
lines changed

2 files changed

+139
-1
lines changed

src/components/terminal/terminalManager.js

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,116 @@ import EditorFile from "lib/editorFile";
77
import TerminalComponent from "./terminal";
88
import "@xterm/xterm/css/xterm.css";
99
import toast from "components/toast";
10+
import helpers from "utils/helpers";
11+
12+
const TERMINAL_SESSION_STORAGE_KEY = "acodeTerminalSessions";
1013

1114
class TerminalManager {
1215
constructor() {
1316
this.terminals = new Map();
1417
this.terminalCounter = 0;
1518
}
1619

20+
getPersistedSessions() {
21+
try {
22+
const stored = helpers.parseJSON(
23+
localStorage.getItem(TERMINAL_SESSION_STORAGE_KEY),
24+
);
25+
if (!Array.isArray(stored)) return [];
26+
return stored
27+
.map((entry) => {
28+
if (!entry) return null;
29+
if (typeof entry === "string") {
30+
return { pid: entry, name: `Terminal ${entry}` };
31+
}
32+
if (typeof entry === "object" && entry.pid) {
33+
const pid = String(entry.pid);
34+
return {
35+
pid,
36+
name: entry.name || `Terminal ${pid}`,
37+
};
38+
}
39+
return null;
40+
})
41+
.filter(Boolean);
42+
} catch (error) {
43+
console.error("Failed to read persisted terminal sessions:", error);
44+
return [];
45+
}
46+
}
47+
48+
savePersistedSessions(sessions) {
49+
try {
50+
localStorage.setItem(
51+
TERMINAL_SESSION_STORAGE_KEY,
52+
JSON.stringify(sessions),
53+
);
54+
} catch (error) {
55+
console.error("Failed to persist terminal sessions:", error);
56+
}
57+
}
58+
59+
persistTerminalSession(pid, name) {
60+
if (!pid) return;
61+
62+
const pidStr = String(pid);
63+
const sessions = this.getPersistedSessions();
64+
const existingIndex = sessions.findIndex(
65+
(session) => session.pid === pidStr,
66+
);
67+
const sessionData = {
68+
pid: pidStr,
69+
name: name || `Terminal ${pidStr}`,
70+
};
71+
72+
if (existingIndex >= 0) {
73+
sessions[existingIndex] = {
74+
...sessions[existingIndex],
75+
...sessionData,
76+
};
77+
} else {
78+
sessions.push(sessionData);
79+
}
80+
81+
this.savePersistedSessions(sessions);
82+
}
83+
84+
removePersistedSession(pid) {
85+
if (!pid) return;
86+
87+
const pidStr = String(pid);
88+
const sessions = this.getPersistedSessions();
89+
const nextSessions = sessions.filter((session) => session.pid !== pidStr);
90+
91+
if (nextSessions.length !== sessions.length) {
92+
this.savePersistedSessions(nextSessions);
93+
}
94+
}
95+
96+
async restorePersistedSessions() {
97+
const sessions = this.getPersistedSessions();
98+
if (!sessions.length) return;
99+
100+
for (const session of sessions) {
101+
if (!session?.pid) continue;
102+
if (this.terminals.has(session.pid)) continue;
103+
104+
try {
105+
await this.createServerTerminal({
106+
pid: session.pid,
107+
name: session.name,
108+
reconnecting: true,
109+
});
110+
} catch (error) {
111+
console.error(
112+
`Failed to restore terminal session ${session.pid}:`,
113+
error,
114+
);
115+
this.removePersistedSession(session.pid);
116+
}
117+
}
118+
}
119+
17120
/**
18121
* Create a new terminal session
19122
* @param {object} options - Terminal options
@@ -71,7 +174,7 @@ class TerminalManager {
71174

72175
// Connect to session if in server mode
73176
if (terminalComponent.serverMode) {
74-
await terminalComponent.connectToSession();
177+
await terminalComponent.connectToSession(options.pid);
75178
} else {
76179
// For local mode, just write a welcome message
77180
terminalComponent.write(
@@ -98,6 +201,10 @@ class TerminalManager {
98201
};
99202

100203
this.terminals.set(uniqueId, instance);
204+
205+
if (terminalComponent.serverMode && terminalComponent.pid) {
206+
this.persistTerminalSession(terminalComponent.pid, terminalName);
207+
}
101208
resolve(instance);
102209
} catch (error) {
103210
console.error("Failed to initialize terminal:", error);
@@ -368,6 +475,10 @@ class TerminalManager {
368475
const formattedTitle = `Terminal ${this.terminalCounter} - ${title}`;
369476
terminalFile.filename = formattedTitle;
370477

478+
if (terminalComponent.serverMode && terminalComponent.pid) {
479+
this.persistTerminalSession(terminalComponent.pid, formattedTitle);
480+
}
481+
371482
// Refresh the header subtitle if this terminal is active
372483
if (
373484
editorManager.activeFile &&
@@ -421,6 +532,10 @@ class TerminalManager {
421532
if (!terminal) return;
422533

423534
try {
535+
if (terminal.component.serverMode && terminal.component.pid) {
536+
this.removePersistedSession(terminal.component.pid);
537+
}
538+
424539
// Cleanup resize observer
425540
if (terminal.file._resizeObserver) {
426541
terminal.file._resizeObserver.disconnect();

src/main.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import { setKeyBindings } from "ace/commands";
1818
import { initModes } from "ace/modelist";
1919
import Contextmenu from "components/contextmenu";
2020
import Sidebar from "components/sidebar";
21+
import {
22+
DEFAULT_TERMINAL_SETTINGS,
23+
TerminalManager,
24+
} from "components/terminal";
2125
import tile from "components/tile";
2226
import toast from "components/toast";
2327
import tutorial from "components/tutorial";
@@ -33,6 +37,7 @@ import checkPluginsUpdate from "lib/checkPluginsUpdate";
3337
import EditorFile from "lib/editorFile";
3438
import EditorManager from "lib/editorManager";
3539
import { initFileList } from "lib/fileList";
40+
import fonts from "lib/fonts";
3641
import lang from "lib/lang";
3742
import loadPlugins from "lib/loadPlugins";
3843
import Logger from "lib/logger";
@@ -487,6 +492,24 @@ async function loadApp() {
487492

488493
initFileList();
489494

495+
const terminalSettings = settings.value.terminalSettings || {};
496+
const terminalFontFamily =
497+
terminalSettings.fontFamily || DEFAULT_TERMINAL_SETTINGS.fontFamily;
498+
if (terminalFontFamily) {
499+
try {
500+
await fonts.loadFont(terminalFontFamily);
501+
} catch (error) {
502+
console.error(
503+
`Failed to preload terminal font ${terminalFontFamily}:`,
504+
error,
505+
);
506+
}
507+
}
508+
509+
TerminalManager.restorePersistedSessions().catch((error) => {
510+
console.error("Terminal restoration failed:", error);
511+
});
512+
490513
/**
491514
*
492515
* @param {MouseEvent} e

0 commit comments

Comments
 (0)