fix: fix WebGL addon dispose error and add Ctrl+W shortcut to close tab
This commit is contained in:
parent
2387e6e5f4
commit
0e20b0df3a
48
src/App.js
48
src/App.js
@ -54,13 +54,44 @@ function App() {
|
|||||||
checkRemoteStatus();
|
checkRemoteStatus();
|
||||||
}, [loadHosts, checkRemoteStatus]);
|
}, [loadHosts, checkRemoteStatus]);
|
||||||
|
|
||||||
|
// 关闭标签页 (需要在 useEffect 之前定义)
|
||||||
|
const closeTab = useCallback((tabId) => {
|
||||||
|
setActiveTabs((prev) => {
|
||||||
|
const newTabs = prev.filter((t) => t.id !== tabId);
|
||||||
|
return newTabs;
|
||||||
|
});
|
||||||
|
setActiveTabId((prevActiveId) => {
|
||||||
|
if (prevActiveId === tabId) {
|
||||||
|
// 找到要关闭的标签的索引
|
||||||
|
const tabIndex = activeTabs.findIndex(t => t.id === tabId);
|
||||||
|
const remainingTabs = activeTabs.filter((t) => t.id !== tabId);
|
||||||
|
if (remainingTabs.length > 0) {
|
||||||
|
// 优先切换到右边的标签,否则切换到左边的
|
||||||
|
const newIndex = Math.min(tabIndex, remainingTabs.length - 1);
|
||||||
|
return remainingTabs[newIndex].id;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return prevActiveId;
|
||||||
|
});
|
||||||
|
}, [activeTabs]);
|
||||||
|
|
||||||
// 键盘快捷键
|
// 键盘快捷键
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (e) => {
|
const handleKeyDown = (e) => {
|
||||||
|
// Ctrl+K: 打开命令面板
|
||||||
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setShowCommandPalette(true);
|
setShowCommandPalette(true);
|
||||||
}
|
}
|
||||||
|
// Ctrl+W: 关闭当前标签页
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === 'w') {
|
||||||
|
e.preventDefault();
|
||||||
|
if (activeTabId) {
|
||||||
|
closeTab(activeTabId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Escape: 关闭弹窗
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
setShowCommandPalette(false);
|
setShowCommandPalette(false);
|
||||||
setShowHostManager(false);
|
setShowHostManager(false);
|
||||||
@ -70,7 +101,7 @@ function App() {
|
|||||||
|
|
||||||
window.addEventListener('keydown', handleKeyDown);
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||||
}, []);
|
}, [activeTabId, closeTab]);
|
||||||
|
|
||||||
// 连接主机
|
// 连接主机
|
||||||
const connectHost = useCallback((host) => {
|
const connectHost = useCallback((host) => {
|
||||||
@ -90,21 +121,6 @@ function App() {
|
|||||||
setSelectedHost(null); // 关闭右侧编辑面板
|
setSelectedHost(null); // 关闭右侧编辑面板
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 关闭标签页
|
|
||||||
const closeTab = useCallback((tabId) => {
|
|
||||||
setActiveTabs((prev) => {
|
|
||||||
const newTabs = prev.filter((t) => t.id !== tabId);
|
|
||||||
return newTabs;
|
|
||||||
});
|
|
||||||
setActiveTabId((prevActiveId) => {
|
|
||||||
if (prevActiveId === tabId) {
|
|
||||||
const remainingTabs = activeTabs.filter((t) => t.id !== tabId);
|
|
||||||
return remainingTabs.length > 0 ? remainingTabs[remainingTabs.length - 1].id : null;
|
|
||||||
}
|
|
||||||
return prevActiveId;
|
|
||||||
});
|
|
||||||
}, [activeTabs]);
|
|
||||||
|
|
||||||
// 更新连接状态
|
// 更新连接状态
|
||||||
const handleConnectionChange = useCallback((tabId, connected) => {
|
const handleConnectionChange = useCallback((tabId, connected) => {
|
||||||
setActiveTabs((prev) =>
|
setActiveTabs((prev) =>
|
||||||
|
|||||||
@ -319,16 +319,19 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
|
|||||||
connectionIdRef.current = null;
|
connectionIdRef.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理 WebGL 渲染器
|
// 安全清理终端及其插件
|
||||||
if (webglAddonRef.current) {
|
// 注意:必须先 dispose terminal,它会自动清理所有加载的 addon
|
||||||
webglAddonRef.current.dispose();
|
try {
|
||||||
webglAddonRef.current = null;
|
if (xtermRef.current) {
|
||||||
|
xtermRef.current.dispose();
|
||||||
|
xtermRef.current = null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('终端清理时出错:', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xtermRef.current) {
|
// 清理引用
|
||||||
xtermRef.current.dispose();
|
webglAddonRef.current = null;
|
||||||
xtermRef.current = null;
|
|
||||||
}
|
|
||||||
fitAddonRef.current = null;
|
fitAddonRef.current = null;
|
||||||
};
|
};
|
||||||
}, [initTerminal, connect]);
|
}, [initTerminal, connect]);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user