diff --git a/app/session.ts b/app/session.ts index ce54321c..e75aca8e 100644 --- a/app/session.ts +++ b/app/session.ts @@ -84,11 +84,11 @@ class DataBatcher extends EventEmitter { interface SessionOptions { uid: string; - rows: number; - cols: number; - cwd: string; - shell: string; - shellArgs: string[]; + rows?: number; + cols?: number; + cwd?: string; + shell?: string; + shellArgs?: string[]; } export default class Session extends EventEmitter { pty: IPty | null; @@ -106,22 +106,23 @@ export default class Session extends EventEmitter { this.init(options); } - init({uid, rows, cols: columns, cwd, shell: _shell, shellArgs: _shellArgs}: SessionOptions) { + init({uid, rows, cols, cwd, shell: _shell, shellArgs: _shellArgs}: SessionOptions) { + const defaultShellArgs = ['--login']; + + const shell = _shell || defaultShell; + const shellArgs = _shellArgs || defaultShellArgs; + const cleanEnv = process.env['APPIMAGE'] && process.env['APPDIR'] ? shellEnv.sync(_shell || defaultShell) : process.env; - const baseEnv = Object.assign( - {}, - cleanEnv, - { - LANG: `${osLocale.sync().replace(/-/, '_')}.UTF-8`, - TERM: 'xterm-256color', - COLORTERM: 'truecolor', - TERM_PROGRAM: productName, - TERM_PROGRAM_VERSION: version - }, - envFromConfig - ); - + const baseEnv: Record = { + ...cleanEnv, + LANG: `${osLocale.sync().replace(/-/, '_')}.UTF-8`, + TERM: 'xterm-256color', + COLORTERM: 'truecolor', + TERM_PROGRAM: productName, + TERM_PROGRAM_VERSION: version, + ...envFromConfig + }; // path to AppImage mount point is added to PATH environment variable automatically // which conflicts with the cli if (baseEnv['APPIMAGE'] && baseEnv['APPDIR']) { @@ -137,10 +138,8 @@ export default class Session extends EventEmitter { delete baseEnv.GOOGLE_API_KEY; } - const defaultShellArgs = ['--login']; - const options: IWindowsPtyForkOptions = { - cols: columns, + cols, rows, cwd, env: getDecoratedEnv(baseEnv) @@ -151,9 +150,6 @@ export default class Session extends EventEmitter { options.useConpty = useConpty; } - const shell = _shell || defaultShell; - const shellArgs = _shellArgs || defaultShellArgs; - try { this.pty = spawn(shell, shellArgs, options); } catch (_err) { @@ -191,7 +187,7 @@ fallback to default shell config: ${JSON.stringify(defaultShellConfig, undefined `; console.warn(msg); this.batcher?.write(msg.replace(/\n/g, '\r\n') as any); - this.init({uid, rows, cols: columns, cwd, ...defaultShellConfig}); + this.init({uid, rows, cols, cwd, ...defaultShellConfig}); } else { this.ended = true; this.emit('exit'); diff --git a/app/ui/window.ts b/app/ui/window.ts index 95be52e4..f239c8f6 100644 --- a/app/ui/window.ts +++ b/app/ui/window.ts @@ -19,6 +19,7 @@ import {enable as remoteEnable} from '@electron/remote/main'; import type {configOptions} from '../../lib/config'; import {getWorkingDirectoryFromPID} from 'native-process-working-directory'; import {existsSync} from 'fs'; +import type {sessionExtraOptions} from '../../common'; export function newWindow( options_: BrowserWindowConstructorOptions, @@ -125,20 +126,23 @@ export function newWindow( } }); - function createSession(extraOptions: any = {}) { + function createSession(extraOptions: sessionExtraOptions = {}) { const uid = uuidv4(); - const extraOptionsFiltered: any = {}; + const extraOptionsFiltered: sessionExtraOptions = {}; Object.keys(extraOptions).forEach((key) => { if (extraOptions[key] !== undefined) extraOptionsFiltered[key] = extraOptions[key]; }); let cwd = ''; if (cfg.preserveCWD === undefined || cfg.preserveCWD) { - const activePID = extraOptionsFiltered.activeUid && sessions.get(extraOptionsFiltered.activeUid)?.pty?.pid; - try { - cwd = activePID && getWorkingDirectoryFromPID(activePID); - } catch (error) { - console.error(error); + const activeUid = extraOptionsFiltered.activeUid; + const activePID = activeUid ? sessions.get(activeUid)?.pty?.pid : undefined; + if (activePID !== undefined) { + try { + cwd = getWorkingDirectoryFromPID(activePID) || ''; + } catch (error) { + console.error(error); + } } cwd = cwd && isAbsolute(cwd) && existsSync(cwd) ? cwd : ''; } @@ -172,7 +176,7 @@ export function newWindow( splitDirection: options.splitDirection, shell: session.shell, pid: session.pty ? session.pty.pid : null, - activeUid: options.activeUid + activeUid: options.activeUid ?? undefined }); session.on('data', (data: string) => { @@ -238,11 +242,12 @@ export function newWindow( // Same deal as above, grabbing the window titlebar when the window // is maximized on Windows results in unmaximize, without hitting any // app buttons - for (const ev of ['maximize', 'unmaximize', 'minimize', 'restore'] as any) { - window.on(ev, () => { - rpc.emit('windowGeometry change', {isMaximized: window.isMaximized()}); - }); - } + const onGeometryChange = () => rpc.emit('windowGeometry change', {isMaximized: window.isMaximized()}); + window.on('maximize', onGeometryChange); + window.on('unmaximize', onGeometryChange); + window.on('minimize', onGeometryChange); + window.on('restore', onGeometryChange); + window.on('move', () => { const position = window.getPosition(); rpc.emit('move', {bounds: {x: position[0], y: position[1]}}); diff --git a/common.d.ts b/common.d.ts index 5995d92f..80813fdc 100644 --- a/common.d.ts +++ b/common.d.ts @@ -4,8 +4,8 @@ import type {ExecFileOptions, ExecOptions} from 'child_process'; export type Session = { uid: string; - rows: number | null; - cols: number | null; + rows?: number | null; + cols?: number | null; splitDirection?: 'HORIZONTAL' | 'VERTICAL'; shell: string | null; pid: number | null; @@ -13,10 +13,14 @@ export type Session = { }; export type sessionExtraOptions = { - cwd: string | undefined; + cwd?: string; splitDirection?: 'HORIZONTAL' | 'VERTICAL'; activeUid?: string | null; isNewGroup?: boolean; + rows?: number; + cols?: number; + shell?: string; + shellArgs?: string[]; }; export type MainEvents = { diff --git a/lib/actions/sessions.ts b/lib/actions/sessions.ts index 4f4d6ec0..d690736d 100644 --- a/lib/actions/sessions.ts +++ b/lib/actions/sessions.ts @@ -15,17 +15,10 @@ import { SESSION_SET_XTERM_TITLE, SESSION_SEARCH } from '../constants/sessions'; -import type {HyperState, session, HyperDispatch, HyperActions} from '../hyper'; +import type {HyperState, HyperDispatch, HyperActions} from '../hyper'; +import type {Session} from '../../common'; -export function addSession({ - uid, - shell, - pid, - cols, - rows, - splitDirection, - activeUid -}: Pick) { +export function addSession({uid, shell, pid, cols = null, rows = null, splitDirection, activeUid}: Session) { return (dispatch: HyperDispatch, getState: () => HyperState) => { const {sessions} = getState(); const now = Date.now();