Skip to content

Commit

Permalink
close tab when shell exits (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
atinylittleshell committed Jan 19, 2024
1 parent fba7269 commit 5285593
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 17 deletions.
16 changes: 14 additions & 2 deletions apps/app/src/nativeBridge/modules/terminalModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ class PTYInstance {
public onData(handler: (_: string) => void): void {
this.ptyProcess.onData(handler);
}

public onExit(handler: () => void): void {
this.ptyProcess.onExit(handler);
}
}

@nativeBridgeModule('terminal')
Expand All @@ -78,7 +82,7 @@ export class TerminalModule extends NativeBridgeModule {

@moduleFunction()
public async createTerminalIfNotExist(
_mainWindow: BrowserWindow,
mainWindow: BrowserWindow,
id: string,
cols: number,
rows: number,
Expand All @@ -97,7 +101,10 @@ export class TerminalModule extends NativeBridgeModule {
startupDirectory,
);
ptyInstance.onData((data: string) => {
this.onData(_mainWindow, ptyInstance.id, data);
this.onData(mainWindow, ptyInstance.id, data);
});
ptyInstance.onExit(() => {
this.onExit(mainWindow, ptyInstance.id);
});

this.ptyInstances[ptyInstance.id] = ptyInstance;
Expand Down Expand Up @@ -149,4 +156,9 @@ export class TerminalModule extends NativeBridgeModule {
public onData(_mainWindow: BrowserWindow, _id: string, _data: string): void {
return;
}

@moduleEvent('on')
public onExit(_mainWindow: BrowserWindow, _id: string): void {
return;
}
}
1 change: 1 addition & 0 deletions apps/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"**/*.tsx"
],
"exclude": [
"dist",
"node_modules"
]
}
31 changes: 22 additions & 9 deletions apps/terminal/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,21 @@ const Page = () => {
setTabId(newTabId);
}, [userTabs, config]);

const closeTab = useCallback(() => {
const newTabs = userTabs.filter((t) => t.tabId !== tabId);
setUserTabs(newTabs);
setTabId(_.max(newTabs.map((t) => t.tabId)) || 0);
}, [userTabs, tabId]);
const closeTab = useCallback(
(targetTabId: number) => {
const newTabs = userTabs.filter((t) => t.tabId !== targetTabId);
if (newTabs.length === 0) {
window.TerminalOne?.app.quit();
} else {
setUserTabs(newTabs);
setTabId(_.max(newTabs.map((t) => t.tabId)) || 0);
}
},
[userTabs],
);
const closeCurrentTab = useCallback(() => {
closeTab(tabId);
}, [closeTab, tabId]);

const nextTab = useCallback(() => {
const currentTabIndex = userTabs.findIndex((t) => t.tabId === tabId);
Expand Down Expand Up @@ -126,7 +136,7 @@ const Page = () => {

useEffect(() => {
commands.on('createTab', createTab);
commands.on('closeTab', closeTab);
commands.on('closeTab', closeCurrentTab);
commands.on('nextTab', nextTab);
commands.on('previousTab', previousTab);
commands.on('tab1', switchToTab1);
Expand All @@ -141,7 +151,7 @@ const Page = () => {

return () => {
commands.off('createTab', createTab);
commands.off('closeTab', closeTab);
commands.off('closeTab', closeCurrentTab);
commands.off('nextTab', nextTab);
commands.off('previousTab', previousTab);
commands.off('tab1', switchToTab1);
Expand All @@ -157,7 +167,7 @@ const Page = () => {
}, [
commands,
createTab,
closeTab,
closeCurrentTab,
nextTab,
previousTab,
switchToTab1,
Expand Down Expand Up @@ -229,7 +239,7 @@ const Page = () => {
<button
className="btn btn-ghost btn-square btn-xs opacity-50 hover:bg-transparent hover:opacity-100 ml-2"
onClick={() => {
closeTab();
closeTab(tabId);
}}
>
<FiX />
Expand Down Expand Up @@ -265,6 +275,9 @@ const Page = () => {
key={userTab.tabId}
active={tabId === userTab.tabId}
tabId={userTab.tabId}
close={() => {
closeTab(userTab.tabId);
}}
/>
);
})}
Expand Down
12 changes: 10 additions & 2 deletions apps/terminal/components/Tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ import _ from 'lodash';
import { TabContextProvider } from '../../hooks/TabContext';
import { TerminalTreeNode } from '../TerminalTreeNode';

const Tab = ({ tabId, active }: { tabId: number; active: boolean }) => {
const Tab = ({
tabId,
active,
close,
}: {
tabId: number;
active: boolean;
close: () => void;
}) => {
return (
<div
className={`w-full h-full absolute ${active ? 'visible' : 'invisible'}`}
>
<TabContextProvider active={active} tabId={tabId}>
<TabContextProvider active={active} tabId={tabId} close={close}>
<TerminalTreeNode data={null} />
</TabContextProvider>
</div>
Expand Down
9 changes: 8 additions & 1 deletion apps/terminal/components/Terminal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const Terminal = ({
const [shellName, setShellName] = useState<string | null | undefined>(
undefined,
);
const { handleKey } = useKeybindContext();
const { handleKey, commands } = useKeybindContext();
const terminalRef = useRef<HTMLDivElement>(null);
const xtermRef = useRef<XTerm | null>(null);
const { root, activeTerminalId, onTerminalActive, onTerminalCreated } =
Expand Down Expand Up @@ -129,6 +129,12 @@ const Terminal = ({
}
xterm.write(data);
});
window.TerminalOne?.terminal?.onExit((_e, id: string) => {
if (id !== terminalId) {
return;
}
commands.emit('closePane', terminalId);
});

// make backend pty size consistent with xterm on the frontend
fitAddon.fit();
Expand Down Expand Up @@ -194,6 +200,7 @@ const Terminal = ({
terminalId,
config,
handleKey,
commands,
onTerminalActive,
onTerminalCreated,
]);
Expand Down
9 changes: 7 additions & 2 deletions apps/terminal/hooks/TabContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const lookupTerminalById = (root: TerminalTreeNodeData, terminalId: string) => {
const createCloseHandler = (
root: TerminalTreeNodeData,
setRoot: (root: TerminalTreeNodeData) => void,
closeRoot: () => void,
) => {
return (terminalId: string) => {
const node = lookupTerminalById(root, terminalId);
Expand All @@ -44,6 +45,7 @@ const createCloseHandler = (

const replaceTarget = node.parent;
if (!replaceTarget) {
closeRoot();
return;
}
if (replaceTarget.nodeType === 'terminal') {
Expand Down Expand Up @@ -248,6 +250,7 @@ export const TabContextProvider = (
props: React.PropsWithChildren<{
active: boolean;
tabId: number;
close: () => void;
}>,
) => {
const { commands } = useKeybindContext();
Expand Down Expand Up @@ -293,7 +296,9 @@ export const TabContextProvider = (
onTerminalActive,
'right',
);
const closePane = createCloseHandler(root, setRoot);
const closePane = createCloseHandler(root, setRoot, () => {
props.close();
});

commands.on('splitVertical', splitVertical);
commands.on('splitHorizontal', splitHorizontal);
Expand All @@ -316,7 +321,7 @@ export const TabContextProvider = (

commands.off('closePane', closePane);
};
}, [commands, onTerminalActive, root]);
}, [commands, onTerminalActive, root, props]);

return (
<TabContext.Provider
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@terminalone/monorepo",
"productName": "Terminal One",
"version": "1.4.2",
"version": "1.5.0",
"description": "A fast, elegant and intelligent cross-platform terminal.",
"author": "atinylittleshell <[email protected]>",
"license": "MIT",
Expand Down
3 changes: 3 additions & 0 deletions packages/types/nativeBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export type INativeBridge = {
_data: string,
) => void,
) => void;
onExit: (
_callback: (_event: ElectronOpaqueEvent, _id: string) => void,
) => void;
};
config: {
getConfig: () => Promise<ResolvedConfig>;
Expand Down

0 comments on commit 5285593

Please sign in to comment.