From 9133a45ca7364764e40328911df94ef0bb7c5b45 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 24 Jan 2022 13:14:08 -0600 Subject: [PATCH 01/13] tweak script --- .../browser/media/shellIntegration-bash.sh | 22 ++++- .../terminal/browser/terminalInstance.ts | 24 +---- .../browser/terminalProcessManager.ts | 28 +++++- .../terminal/common/terminalEnvironment.ts | 13 ++- .../test/common/terminalEnvironment.test.ts | 93 +++++++++++-------- 5 files changed, 107 insertions(+), 73 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index ad2322309c3ba..8a2c0079c30d6 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -1,5 +1,19 @@ -# Source .bashrc because --init-file doesn't support it -. ~/.bashrc + +if [ -z "$VSCODE_SHELL_LOGIN"]; then + . ~/.bashrc +else + # Imitate -l because --init-file doesn't support it + if [ -f "~/.bash_profile"]; then + . ~/.bash_profile + fi + elif [ -f "~/.bash_login"]; then + . ~/.bash_login + fi + elif [ -f "~/.profile"]; then + . ~/.profile + fi + VSCODE_SHELL_LOGIN="" +fi IN_COMMAND_EXECUTION="1" prompt_start() { @@ -52,8 +66,8 @@ preexec() { update_prompt prompt_cmd() { - ${ORIGINAL_PROMPT_COMMAND} - precmd + ${ORIGINAL_PROMPT_COMMAND} + precmd } export ORIGINAL_PROMPT_COMMAND=$PROMPT_COMMAND export PROMPT_COMMAND=prompt_cmd diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 77dfbb6978a53..ce253cdf28ff7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -71,8 +71,6 @@ import { fromNow } from 'vs/base/common/date'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { TerminalCapabilityStoreMultiplexer } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore'; import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { injectShellIntegrationArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; const enum Constants { /** @@ -328,8 +326,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, @IEditorService private readonly _editorService: IEditorService, @IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService, - @ICommandService private readonly _commandService: ICommandService, - @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService + @ICommandService private readonly _commandService: ICommandService ) { super(); @@ -1270,13 +1267,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } const hadIcon = !!this.shellLaunchConfig.icon; - const isBackendWindows = await this._backendIsWindows(); - const shellIntegration = injectShellIntegrationArgs(this._logService, this._configHelper.config.enableShellIntegration, this.shellLaunchConfig, isBackendWindows); - this.shellLaunchConfig.args = shellIntegration.args; - const enableShellIntegration = shellIntegration.enableShellIntegration; + await this._processManager.createProcess(this._shellLaunchConfig, this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows, this._accessibilityService.isScreenReaderOptimized()).then(error => { if (error) { - this._onProcessExit(error, enableShellIntegration); + this._onProcessExit(error, error.code === 1337); } }); if (this.xterm?.shellIntegration) { @@ -1287,18 +1281,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } - private async _backendIsWindows(): Promise { - let os = OS; - if (!!this.remoteAuthority) { - const remoteEnv = await this._remoteAgentService.getEnvironment(); - if (!remoteEnv) { - throw new Error(`Failed to get remote environment for remote authority "${this.remoteAuthority}"`); - } - os = remoteEnv.os; - } - return os === OperatingSystem.Windows; - } - private _onProcessData(ev: IProcessDataEvent): void { const messageId = ++this._latestXtermWriteData; if (ev.trackCommit) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 4bbb3ce7fdd5a..69633f9103803 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -63,6 +63,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce isDisconnected: boolean = false; environmentVariableInfo: IEnvironmentVariableInfo | undefined; backend: ITerminalBackend | undefined; + shellIntegrationAttempted: boolean = false; readonly capabilities = new TerminalCapabilityStore(); private _isDisposed: boolean = false; @@ -225,7 +226,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce this.os = remoteEnv.os; // this is a copy of what the merged environment collection is on the remote side - await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); + const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); const shouldPersist = !shellLaunchConfig.isFeatureTerminal && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.disablePersistence; if (shellLaunchConfig.attachPersistentProcess) { @@ -242,13 +243,17 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce os: this.os }); try { + const isBackendWindows = await this._backendIsWindows(); + const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, isBackendWindows); + shellLaunchConfig.args = shellIntegration.args; + this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; newProcess = await backend.createProcess( shellLaunchConfig, '', // TODO: Fix cwd cols, rows, this._configHelper.config.unicodeVersion, - {}, // TODO: Fix env + env, true, // TODO: Fix enable shouldPersist ); @@ -416,6 +421,11 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); + const isBackendWindows = await this._backendIsWindows(); + const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, isBackendWindows); + shellLaunchConfig.args = shellIntegration.args; + this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; + this._logService.debug('integration', shellIntegration); const useConpty = this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled; const shouldPersist = this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isFeatureTerminal; return await backend.createProcess(shellLaunchConfig, initialCwd, cols, rows, this._configHelper.config.unicodeVersion, env, useConpty, shouldPersist); @@ -468,6 +478,18 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce })); } + private async _backendIsWindows(): Promise { + let os = OS; + if (!!this.remoteAuthority) { + const remoteEnv = await this._remoteAgentService.getEnvironment(); + if (!remoteEnv) { + throw new Error(`Failed to get remote environment for remote authority "${this.remoteAuthority}"`); + } + os = remoteEnv.os; + } + return os === OperatingSystem.Windows; + } + setDimensions(cols: number, rows: number): Promise; setDimensions(cols: number, rows: number, sync: false): Promise; setDimensions(cols: number, rows: number, sync: true): void; @@ -570,7 +592,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce this._setProcessState(ProcessState.KilledByProcess); } - this._onProcessExit.fire(exitCode); + this._onProcessExit.fire(this.shellIntegrationAttempted ? 1337 : exitCode); } private _setProcessState(state: ProcessState) { diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index ca209081b5d94..6a56ae791352a 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -414,12 +414,12 @@ shellIntegrationArgs.set(ShellIntegrationExecutable.WindowsPwsh, ['-noexit', ' - shellIntegrationArgs.set(ShellIntegrationExecutable.WindowsPwshLogin, ['-l', '-noexit', ' -command', '. \"${execInstallFolder}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1\"']); shellIntegrationArgs.set(ShellIntegrationExecutable.Pwsh, ['-noexit', '-command', '. "${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1"']); shellIntegrationArgs.set(ShellIntegrationExecutable.PwshLogin, ['-l', '-noexit', '-command', '. "${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1"']); -shellIntegrationArgs.set(ShellIntegrationExecutable.Zsh, ['-c', '"${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/ShellIntegration-zsh.sh"; zsh -i']); -shellIntegrationArgs.set(ShellIntegrationExecutable.ZshLogin, ['-c', '"${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/ShellIntegration-zsh.sh"; zsh -il']); -shellIntegrationArgs.set(ShellIntegrationExecutable.Bash, ['--init-file', '${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/ShellIntegration-bash.sh']); +shellIntegrationArgs.set(ShellIntegrationExecutable.Zsh, ['-c', '"${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-zsh.sh"; zsh -i']); +shellIntegrationArgs.set(ShellIntegrationExecutable.ZshLogin, ['-c', '"${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-zsh.sh"; zsh -il']); +shellIntegrationArgs.set(ShellIntegrationExecutable.Bash, ['--init-file', '${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh']); const loginArgs = ['-login', '-l']; const pwshImpliedArgs = ['-nol', '-nologo']; -export function injectShellIntegrationArgs(logService: ILogService, enableShellIntegration: boolean, shellLaunchConfig: IShellLaunchConfig, isBackendWindows?: boolean): { args: string | string[] | undefined, enableShellIntegration: boolean } { +export function injectShellIntegrationArgs(logService: ILogService, env: IProcessEnvironment, enableShellIntegration: boolean, shellLaunchConfig: IShellLaunchConfig, isBackendWindows?: boolean): { args: string | string[] | undefined, enableShellIntegration: boolean } { // Shell integration arg injection is disabled when: // - The global setting is disabled // - There is no executable (not sure what script to run) @@ -444,7 +444,10 @@ export function injectShellIntegrationArgs(logService: ILogService, enableShellI } else { switch (shell) { case 'bash': - if (!originalArgs || originalArgs.length === 0 || areZshBashLoginArgs(originalArgs)) { + if (!originalArgs || originalArgs.length === 0) { + newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); + } else if (areZshBashLoginArgs(originalArgs)) { + env['VSCODE_SHELL_LOGIN'] = '1'; newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); } break; diff --git a/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts index fbc6520d8cba1..5e0007b11ea01 100644 --- a/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts @@ -6,7 +6,7 @@ import { URI as Uri } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; import { addTerminalEnvironmentKeys, mergeEnvironments, getCwd, getDefaultShell, getLangEnvVariable, shouldSetLangEnvVariable, injectShellIntegrationArgs, shellIntegrationArgs, ShellIntegrationExecutable } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { isWindows, Platform } from 'vs/base/common/platform'; +import { IProcessEnvironment, isWindows, Platform } from 'vs/base/common/platform'; import { deepStrictEqual, strictEqual } from 'assert'; import { NullLogService } from 'vs/platform/log/common/log'; import { terminalProfileArgsMatch } from 'vs/platform/terminal/common/terminalProfiles'; @@ -252,17 +252,17 @@ suite('Workbench - TerminalEnvironment', () => { }); suite('injectShellIntegrationArgs', () => { - + const env = {} as IProcessEnvironment; const logService = new NullLogService(); let shellIntegrationEnabled = true; suite('should not enable', () => { const executable = isWindows ? 'pwsh.exe' : 'pwsh'; test('when isFeatureTerminal or when no executable is provided', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, isWindows); terminalProfileArgsMatch(args, ['-l', '-NoLogo']); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { args: [] }, isWindows)); terminalProfileArgsMatch(args, []); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -275,45 +275,45 @@ suite('Workbench - TerminalEnvironment', () => { suite('should override args', () => { const expectedArgs = isWindows ? shellIntegrationArgs.get(ShellIntegrationExecutable.Pwsh) : shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwsh); test('when undefined, [], empty string, or empty string in array', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: [''] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); suite('when no logo', () => { test('array - case insensitive', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-NoLogo'] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NoLogo'] }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-NOLOGO'] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NOLOGO'] }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-nol'] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-nol'] }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-NOL'] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NOL'] }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('string - case insensitive', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-NoLogo' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-NoLogo' }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-NOLOGO' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-NOLOGO' }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-nol' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-nol' }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-Nol' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-Nol' }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -322,12 +322,12 @@ suite('Workbench - TerminalEnvironment', () => { suite('should incorporate login arg', () => { const expectedArgs = isWindows ? shellIntegrationArgs.get(ShellIntegrationExecutable.PwshLogin) : shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwshLogin); test('when array contains no logo and login', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'] }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -335,20 +335,20 @@ suite('Workbench - TerminalEnvironment', () => { suite('should not modify args', () => { shellIntegrationEnabled = false; test('when shell integration is disabled', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); strictEqual(args, '-l'); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); strictEqual(args, undefined); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom array entry', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo', '-i'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo', '-i'] }, isWindows); terminalProfileArgsMatch(args, ['-l', '-NoLogo', '-i']); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); terminalProfileArgsMatch(args, '-i'); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -363,28 +363,28 @@ suite('Workbench - TerminalEnvironment', () => { suite('should override args', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Zsh); test('when undefined, [], empty string, or empty string in array', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: [''] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); suite('should incorporate login arg', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.ZshLogin); test('when array', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-l'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l'] }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -392,20 +392,20 @@ suite('Workbench - TerminalEnvironment', () => { suite('should not modify args', () => { shellIntegrationEnabled = false; test('when shell integration is disabled', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); strictEqual(args, '-l'); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); strictEqual(args, undefined); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom array entry', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, isWindows); terminalProfileArgsMatch(args, ['-l', '-i']); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); terminalProfileArgsMatch(args, '-i'); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -418,36 +418,49 @@ suite('Workbench - TerminalEnvironment', () => { suite('should override args', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); test('when undefined, [], empty string, or empty string in array', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: [''] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, isWindows); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, isWindows)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); + suite('should set login env variable and not modify args', () => { + const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); + test('when array', () => { + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l'] }, isWindows); + terminalProfileArgsMatch(args, expectedArgs); + strictEqual(enableShellIntegration, shellIntegrationEnabled); + }); + test('when string', () => { + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + terminalProfileArgsMatch(args, expectedArgs); + strictEqual(enableShellIntegration, shellIntegrationEnabled); + }); + }); suite('should not modify args', () => { shellIntegrationEnabled = false; test('when shell integration is disabled', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); strictEqual(args, '-l'); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); strictEqual(args, undefined); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom array entry', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, isWindows); terminalProfileArgsMatch(args, ['-l', '-i']); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); terminalProfileArgsMatch(args, '-i'); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); From c12e86919f16365fc3ea7d3912723d07d90f534e Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 24 Jan 2022 13:45:10 -0600 Subject: [PATCH 02/13] add check --- .../terminal/browser/media/shellIntegration-bash.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index 8a2c0079c30d6..c868f31f9b4ff 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -65,12 +65,17 @@ preexec() { } update_prompt + +if [ -n "$PROMPT_COMMAND" ]; then + export ORIGINAL_PROMPT_COMMAND=$PROMPT_COMMAND +fi + prompt_cmd() { - ${ORIGINAL_PROMPT_COMMAND} + if [ -n "$ORIGINAL_PROMPT_COMMAND" ]; then + ${ORIGINAL_PROMPT_COMMAND} + fi precmd } -export ORIGINAL_PROMPT_COMMAND=$PROMPT_COMMAND export PROMPT_COMMAND=prompt_cmd trap 'preexec' DEBUG - echo -e "\033[01;32mShell integration activated!\033[0m" From 047b1222f1e98c397922fb372cbaf1654dc65eae Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 24 Jan 2022 14:43:20 -0600 Subject: [PATCH 03/13] working --- .../browser/media/shellIntegration-bash.sh | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index c868f31f9b4ff..624d18d6eecfe 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -1,15 +1,14 @@ -if [ -z "$VSCODE_SHELL_LOGIN"]; then +if [ -z "$VSCODE_SHELL_LOGIN" ]; then . ~/.bashrc else - # Imitate -l because --init-file doesn't support it - if [ -f "~/.bash_profile"]; then + # Imitate -l because --init-file doesn't support it: + # run the first of these files that exists + if [ -f "~/.bash_profile" ]; then . ~/.bash_profile - fi - elif [ -f "~/.bash_login"]; then + elif [ -f "~/.bash_login" ]; then . ~/.bash_login - fi - elif [ -f "~/.profile"]; then + elif [ -f "~/.profile" ]; then . ~/.profile fi VSCODE_SHELL_LOGIN="" @@ -65,17 +64,21 @@ preexec() { } update_prompt - -if [ -n "$PROMPT_COMMAND" ]; then - export ORIGINAL_PROMPT_COMMAND=$PROMPT_COMMAND -fi +export ORIGINAL_PROMPT_COMMAND=$PROMPT_COMMAND prompt_cmd() { - if [ -n "$ORIGINAL_PROMPT_COMMAND" ]; then - ${ORIGINAL_PROMPT_COMMAND} - fi - precmd + precmd } -export PROMPT_COMMAND=prompt_cmd +original_cmd() { + ${ORIGINAL_PROMPT_COMMAND} + prompt_cmd +} +if [ -n "$ORIGINAL_PROMPT_COMMAND" ]; then + export PROMPT_COMMAND=original_cmd +else + export PROMPT_COMMAND=prompt_cmd +fi + trap 'preexec' DEBUG + echo -e "\033[01;32mShell integration activated!\033[0m" From 675d64d8d295c6f6b2fd330bfbcf90c03852ada1 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 12:29:56 -0600 Subject: [PATCH 04/13] check os to determine if login --- .../browser/media/shellIntegration-bash.sh | 2 +- .../terminal/browser/terminalInstance.ts | 30 +----- .../browser/terminalProcessManager.ts | 10 +- .../contrib/terminal/common/terminal.ts | 1 + .../terminal/common/terminalEnvironment.ts | 7 +- .../test/common/terminalEnvironment.test.ts | 92 +++++++++---------- 6 files changed, 61 insertions(+), 81 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index 30331afdee7de..25fc3af188ab2 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -1,5 +1,5 @@ -if [ -z "$VSCODE_SHELL_LOGIN" ]; then +if [ -z "$OS_IS_MAC" ]; then . ~/.bashrc else # Imitate -l because --init-file doesn't support it: diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 62dcea527c3d9..5feb96763e3c9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -71,6 +71,7 @@ import { fromNow } from 'vs/base/common/date'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { TerminalCapabilityStoreMultiplexer } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore'; import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; const enum Constants { /** @@ -326,7 +327,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, @IEditorService private readonly _editorService: IEditorService, @IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService, - @ICommandService private readonly _commandService: ICommandService + @ICommandService private readonly _commandService: ICommandService, + @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService ) { super(); @@ -390,7 +392,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Wait for a period to allow a container to be ready await this._containerReadyBarrier.wait(); if (this._configHelper.config.enableShellIntegration && !this.shellLaunchConfig.executable) { - const os = await this._getBackendOS(); + const os = await this._processManager.getBackendOS(); this.shellLaunchConfig.executable = (await this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority: this.remoteAuthority, os })).path; } await this._createProcess(); @@ -1293,30 +1295,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } - private async _backendIsWindows(): Promise { - let os = OS; - if (!!this.remoteAuthority) { - const remoteEnv = await this._remoteAgentService.getEnvironment(); - if (!remoteEnv) { - throw new Error(`Failed to get remote environment for remote authority "${this.remoteAuthority}"`); - } - os = remoteEnv.os; - } - return os === OperatingSystem.Windows; - } - - private async _getBackendOS(): Promise { - let os = OS; - if (!!this.remoteAuthority) { - const remoteEnv = await this._remoteAgentService.getEnvironment(); - if (!remoteEnv) { - throw new Error(`Failed to get remote environment for remote authority "${this.remoteAuthority}"`); - } - os = remoteEnv.os; - } - return os; - } - private _onProcessData(ev: IProcessDataEvent): void { const messageId = ++this._latestXtermWriteData; if (ev.trackCommit) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 69633f9103803..84d7152e35b81 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -243,8 +243,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce os: this.os }); try { - const isBackendWindows = await this._backendIsWindows(); - const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, isBackendWindows); + const os = await this.getBackendOS(); + const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, os); shellLaunchConfig.args = shellIntegration.args; this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; newProcess = await backend.createProcess( @@ -421,7 +421,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); - const isBackendWindows = await this._backendIsWindows(); + const isBackendWindows = await this.getBackendOS(); const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, isBackendWindows); shellLaunchConfig.args = shellIntegration.args; this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; @@ -478,7 +478,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce })); } - private async _backendIsWindows(): Promise { + async getBackendOS(): Promise { let os = OS; if (!!this.remoteAuthority) { const remoteEnv = await this._remoteAgentService.getEnvironment(); @@ -487,7 +487,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce } os = remoteEnv.os; } - return os === OperatingSystem.Windows; + return os; } setDimensions(cols: number, rows: number): Promise; diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 6b77e4f8f8458..60c5146af93b0 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -408,6 +408,7 @@ export interface ITerminalProcessManager extends IDisposable { getLatency(): Promise; refreshProperty(type: T): Promise; updateProperty(property: T, value: IProcessPropertyMap[T]): void; + getBackendOS(): Promise; } export const enum ProcessState { diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 6a56ae791352a..b4707928a3773 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -419,7 +419,7 @@ shellIntegrationArgs.set(ShellIntegrationExecutable.ZshLogin, ['-c', '"${execIns shellIntegrationArgs.set(ShellIntegrationExecutable.Bash, ['--init-file', '${execInstallFolder}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh']); const loginArgs = ['-login', '-l']; const pwshImpliedArgs = ['-nol', '-nologo']; -export function injectShellIntegrationArgs(logService: ILogService, env: IProcessEnvironment, enableShellIntegration: boolean, shellLaunchConfig: IShellLaunchConfig, isBackendWindows?: boolean): { args: string | string[] | undefined, enableShellIntegration: boolean } { +export function injectShellIntegrationArgs(logService: ILogService, env: IProcessEnvironment, enableShellIntegration: boolean, shellLaunchConfig: IShellLaunchConfig, os?: OperatingSystem): { args: string | string[] | undefined, enableShellIntegration: boolean } { // Shell integration arg injection is disabled when: // - The global setting is disabled // - There is no executable (not sure what script to run) @@ -431,7 +431,8 @@ export function injectShellIntegrationArgs(logService: ILogService, env: IProces const originalArgs = shellLaunchConfig.args; const shell = path.basename(shellLaunchConfig.executable); let newArgs: string | string[] | undefined; - if (isBackendWindows) { + + if (os === OperatingSystem.Windows) { if (shell === 'pwsh.exe') { if (!originalArgs || arePwshImpliedArgs(originalArgs)) { newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwsh); @@ -447,7 +448,7 @@ export function injectShellIntegrationArgs(logService: ILogService, env: IProces if (!originalArgs || originalArgs.length === 0) { newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); } else if (areZshBashLoginArgs(originalArgs)) { - env['VSCODE_SHELL_LOGIN'] = '1'; + env['OS_IS_MAC'] = os === OperatingSystem.Macintosh ? '1' : ''; newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); } break; diff --git a/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts index 5e0007b11ea01..ba319cdfd6c39 100644 --- a/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts @@ -6,7 +6,7 @@ import { URI as Uri } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; import { addTerminalEnvironmentKeys, mergeEnvironments, getCwd, getDefaultShell, getLangEnvVariable, shouldSetLangEnvVariable, injectShellIntegrationArgs, shellIntegrationArgs, ShellIntegrationExecutable } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { IProcessEnvironment, isWindows, Platform } from 'vs/base/common/platform'; +import { IProcessEnvironment, isWindows, OS, Platform } from 'vs/base/common/platform'; import { deepStrictEqual, strictEqual } from 'assert'; import { NullLogService } from 'vs/platform/log/common/log'; import { terminalProfileArgsMatch } from 'vs/platform/terminal/common/terminalProfiles'; @@ -257,12 +257,12 @@ suite('Workbench - TerminalEnvironment', () => { let shellIntegrationEnabled = true; suite('should not enable', () => { - const executable = isWindows ? 'pwsh.exe' : 'pwsh'; + const executable = OS ? 'pwsh.exe' : 'pwsh'; test('when isFeatureTerminal or when no executable is provided', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, OS); terminalProfileArgsMatch(args, ['-l', '-NoLogo']); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { args: [] }, OS)); terminalProfileArgsMatch(args, []); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -270,64 +270,64 @@ suite('Workbench - TerminalEnvironment', () => { suite('pwsh', () => { - const executable = isWindows ? 'pwsh.exe' : 'pwsh'; + const executable = OS ? 'pwsh.exe' : 'pwsh'; suite('should override args', () => { - const expectedArgs = isWindows ? shellIntegrationArgs.get(ShellIntegrationExecutable.Pwsh) : shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwsh); + const expectedArgs = OS ? shellIntegrationArgs.get(ShellIntegrationExecutable.Pwsh) : shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwsh); test('when undefined, [], empty string, or empty string in array', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); suite('when no logo', () => { test('array - case insensitive', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NoLogo'] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NoLogo'] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NOLOGO'] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NOLOGO'] }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-nol'] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-nol'] }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NOL'] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-NOL'] }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('string - case insensitive', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-NoLogo' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-NoLogo' }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-NOLOGO' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-NOLOGO' }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-nol' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-nol' }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-Nol' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-Nol' }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); }); }); suite('should incorporate login arg', () => { - const expectedArgs = isWindows ? shellIntegrationArgs.get(ShellIntegrationExecutable.PwshLogin) : shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwshLogin); + const expectedArgs = OS ? shellIntegrationArgs.get(ShellIntegrationExecutable.PwshLogin) : shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwshLogin); test('when array contains no logo and login', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo'] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -335,27 +335,27 @@ suite('Workbench - TerminalEnvironment', () => { suite('should not modify args', () => { shellIntegrationEnabled = false; test('when shell integration is disabled', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, OS); strictEqual(args, '-l'); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, OS)); strictEqual(args, undefined); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom array entry', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo', '-i'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-NoLogo', '-i'] }, OS); terminalProfileArgsMatch(args, ['-l', '-NoLogo', '-i']); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, OS); terminalProfileArgsMatch(args, '-i'); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); }); }); - if (!isWindows) { + if (!OS) { suite('zsh', () => { const executable = 'zsh'; @@ -363,28 +363,28 @@ suite('Workbench - TerminalEnvironment', () => { suite('should override args', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Zsh); test('when undefined, [], empty string, or empty string in array', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); suite('should incorporate login arg', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.ZshLogin); test('when array', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l'] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -392,20 +392,20 @@ suite('Workbench - TerminalEnvironment', () => { suite('should not modify args', () => { shellIntegrationEnabled = false; test('when shell integration is disabled', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, OS); strictEqual(args, '-l'); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, OS)); strictEqual(args, undefined); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom array entry', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, OS); terminalProfileArgsMatch(args, ['-l', '-i']); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, OS); terminalProfileArgsMatch(args, '-i'); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -418,28 +418,28 @@ suite('Workbench - TerminalEnvironment', () => { suite('should override args', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); test('when undefined, [], empty string, or empty string in array', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [''] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: [] }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '' }, OS)); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); suite('should set login env variable and not modify args', () => { const expectedArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); test('when array', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l'] }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, OS); terminalProfileArgsMatch(args, expectedArgs); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); @@ -447,20 +447,20 @@ suite('Workbench - TerminalEnvironment', () => { suite('should not modify args', () => { shellIntegrationEnabled = false; test('when shell integration is disabled', () => { - let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, isWindows); + let { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-l' }, OS); strictEqual(args, '-l'); strictEqual(enableShellIntegration, shellIntegrationEnabled); - ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, isWindows)); + ({ args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: undefined }, OS)); strictEqual(args, undefined); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom array entry', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: ['-l', '-i'] }, OS); terminalProfileArgsMatch(args, ['-l', '-i']); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); test('when custom string', () => { - const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, isWindows); + const { args, enableShellIntegration } = injectShellIntegrationArgs(logService, env, shellIntegrationEnabled, { executable, args: '-i' }, OS); terminalProfileArgsMatch(args, '-i'); strictEqual(enableShellIntegration, shellIntegrationEnabled); }); From d364019d54d8ed4ac6fa0fdcab9c67d205050784 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 12:32:12 -0600 Subject: [PATCH 05/13] remove args --- .../workbench/contrib/terminal/browser/terminalProcessManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 84d7152e35b81..dc53b32816bd5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -425,7 +425,6 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, isBackendWindows); shellLaunchConfig.args = shellIntegration.args; this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; - this._logService.debug('integration', shellIntegration); const useConpty = this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled; const shouldPersist = this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isFeatureTerminal; return await backend.createProcess(shellLaunchConfig, initialCwd, cols, rows, this._configHelper.config.unicodeVersion, env, useConpty, shouldPersist); From b674eb58321c57428cf7add3582464e923dd280e Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 12:50:35 -0600 Subject: [PATCH 06/13] cleanup --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 5feb96763e3c9..fe5aeeed20b92 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -71,7 +71,6 @@ import { fromNow } from 'vs/base/common/date'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { TerminalCapabilityStoreMultiplexer } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore'; import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; const enum Constants { /** @@ -327,8 +326,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, @IEditorService private readonly _editorService: IEditorService, @IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService, - @ICommandService private readonly _commandService: ICommandService, - @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService + @ICommandService private readonly _commandService: ICommandService ) { super(); From 85feedc037b10b320f66bc1cb3436a8c02f74521 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 13:01:30 -0600 Subject: [PATCH 07/13] get it to work --- .../terminal/browser/terminalProcessManager.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index dc53b32816bd5..8180372afa547 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -421,9 +421,16 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); - const isBackendWindows = await this.getBackendOS(); - const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, isBackendWindows); - shellLaunchConfig.args = shellIntegration.args; + const os = await this.getBackendOS(); + const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, os); + if (shellIntegration.enableShellIntegration) { + shellLaunchConfig.args = shellIntegration.args; + // resolve the injected arguments + await this._terminalProfileResolverService.resolveShellLaunchConfig(shellLaunchConfig, { + remoteAuthority: undefined, + os + }); + } this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; const useConpty = this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled; const shouldPersist = this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isFeatureTerminal; From 1479dbfc73b571428e6626fb064cccc552bfbe74 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 13:06:35 -0600 Subject: [PATCH 08/13] fix up --- .../terminal/browser/terminalProcessManager.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 8180372afa547..0f1c7f30c950e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -243,10 +243,16 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce os: this.os }); try { - const os = await this.getBackendOS(); - const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, os); - shellLaunchConfig.args = shellIntegration.args; + const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, this.os); this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; + if (this.shellIntegrationAttempted) { + shellLaunchConfig.args = shellIntegration.args; + // resolve the injected arguments + await this._terminalProfileResolverService.resolveShellLaunchConfig(shellLaunchConfig, { + remoteAuthority: this.remoteAuthority, + os: this.os + }); + } newProcess = await backend.createProcess( shellLaunchConfig, '', // TODO: Fix cwd @@ -421,14 +427,13 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); - const os = await this.getBackendOS(); - const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, os); + const shellIntegration = terminalEnvironment.injectShellIntegrationArgs(this._logService, env, this._configHelper.config.enableShellIntegration, shellLaunchConfig, OS); if (shellIntegration.enableShellIntegration) { shellLaunchConfig.args = shellIntegration.args; // resolve the injected arguments await this._terminalProfileResolverService.resolveShellLaunchConfig(shellLaunchConfig, { remoteAuthority: undefined, - os + os: OS }); } this.shellIntegrationAttempted = shellIntegration.enableShellIntegration; From 959fabfe1e9098ed40a0785261dc83f0755dfa81 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 13:16:29 -0600 Subject: [PATCH 09/13] rename env var --- .../contrib/terminal/browser/media/shellIntegration-bash.sh | 2 +- src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index 25fc3af188ab2..30331afdee7de 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -1,5 +1,5 @@ -if [ -z "$OS_IS_MAC" ]; then +if [ -z "$VSCODE_SHELL_LOGIN" ]; then . ~/.bashrc else # Imitate -l because --init-file doesn't support it: diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index b4707928a3773..f3746ff23a289 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -448,7 +448,7 @@ export function injectShellIntegrationArgs(logService: ILogService, env: IProces if (!originalArgs || originalArgs.length === 0) { newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); } else if (areZshBashLoginArgs(originalArgs)) { - env['OS_IS_MAC'] = os === OperatingSystem.Macintosh ? '1' : ''; + env['VSCODE_SHELL_LOGIN'] = os === OperatingSystem.Macintosh ? '1' : ''; newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash); } break; From e9bdd5f91f2b86d6d0efec7cc6a75aa2f5e547fe Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 13:25:20 -0600 Subject: [PATCH 10/13] use const for exit code and add comment --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 4 ++-- .../contrib/terminal/browser/terminalProcessManager.ts | 4 ++-- src/vs/workbench/contrib/terminal/common/terminal.ts | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index fe5aeeed20b92..389305423a87a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -23,7 +23,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager'; -import { ITerminalProcessManager, ProcessState, TERMINAL_VIEW_ID, INavigationMode, DEFAULT_COMMANDS_TO_SKIP_SHELL, TERMINAL_CREATION_COMMANDS, ITerminalProfileResolverService, TerminalCommandId, ITerminalBackend, ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalProcessManager, ProcessState, TERMINAL_VIEW_ID, INavigationMode, DEFAULT_COMMANDS_TO_SKIP_SHELL, TERMINAL_CREATION_COMMANDS, ITerminalProfileResolverService, TerminalCommandId, ITerminalBackend, ITerminalCommand, ShellIntegrationExitCode } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -1282,7 +1282,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { await this._processManager.createProcess(this._shellLaunchConfig, this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows, this._accessibilityService.isScreenReaderOptimized()).then(error => { if (error) { - this._onProcessExit(error, error.code === 1337); + this._onProcessExit(error, error.code === ShellIntegrationExitCode); } }); if (this.xterm?.shellIntegration) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 0f1c7f30c950e..ac248880d4c03 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { ProcessState, ITerminalProcessManager, ITerminalConfigHelper, IBeforeProcessDataEvent, ITerminalProfileResolverService, ITerminalBackend } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ProcessState, ITerminalProcessManager, ITerminalConfigHelper, IBeforeProcessDataEvent, ITerminalProfileResolverService, ITerminalBackend, ShellIntegrationExitCode } from 'vs/workbench/contrib/terminal/common/terminal'; import { ILogService } from 'vs/platform/log/common/log'; import { Emitter, Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; @@ -603,7 +603,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce this._setProcessState(ProcessState.KilledByProcess); } - this._onProcessExit.fire(this.shellIntegrationAttempted ? 1337 : exitCode); + this._onProcessExit.fire(this.shellIntegrationAttempted ? ShellIntegrationExitCode : exitCode); } private _setProcessState(state: ProcessState) { diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 60c5146af93b0..2540e0e7b20b6 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -58,6 +58,12 @@ export interface ITerminalProfileResolverService { createProfileFromShellAndShellArgs(shell?: unknown, shellArgs?: unknown): Promise; } +/* + * When there were shell integration args injected + * and createProcess returns an error, this exit code will be used. + */ +export const ShellIntegrationExitCode = 633; + export interface IRegisterContributedProfileArgs { extensionIdentifier: string, id: string, title: string, options: ICreateContributedTerminalProfileOptions; } From 609997e624705a6910397defd505cef57a9d3077 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 13:33:03 -0600 Subject: [PATCH 11/13] get scripts to run by removing quotes --- .../contrib/terminal/browser/media/shellIntegration-bash.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index 30331afdee7de..cb725ae4dc686 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -4,11 +4,11 @@ if [ -z "$VSCODE_SHELL_LOGIN" ]; then else # Imitate -l because --init-file doesn't support it: # run the first of these files that exists - if [ -f "~/.bash_profile" ]; then + if [ -f ~/.bash_profile ]; then . ~/.bash_profile - elif [ -f "~/.bash_login" ]; then + elif [ -f ~/.bash_login ]; then . ~/.bash_login - elif [ -f "~/.profile" ]; then + elif [ -f ~/.profile ]; then . ~/.profile fi VSCODE_SHELL_LOGIN="" From db71132d4f77603db43d3bc8bd2cd931cb126b76 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 15:22:51 -0600 Subject: [PATCH 12/13] get it to work for remote with existing env system --- src/vs/base/common/processes.ts | 2 +- .../contrib/terminal/browser/terminalProcessManager.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts index 6c52c3f9ce2bf..094a413cfa117 100644 --- a/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts @@ -108,7 +108,7 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve }, {} as Record); const keysToRemove = [ /^ELECTRON_.+$/, - /^VSCODE_.+$/, + /^VSCODE_^(?!SHELL).+$/, /^SNAP(|_.*)$/, /^GDK_PIXBUF_.+$/, ]; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index ac248880d4c03..364bb0c5c204d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -253,13 +253,19 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce os: this.os }); } + //TODO: fix + if (env?.['VSCODE_SHELL_LOGIN']) { + shellLaunchConfig.env = shellLaunchConfig.env || {} as IProcessEnvironment; + shellLaunchConfig.env['VSCODE_SHELL_LOGIN'] = '1'; + } + newProcess = await backend.createProcess( shellLaunchConfig, '', // TODO: Fix cwd cols, rows, this._configHelper.config.unicodeVersion, - env, + env, // TODO: true, // TODO: Fix enable shouldPersist ); From 307588d83e35acce833dcd2c6d2a3a6904172001 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 25 Jan 2022 16:46:02 -0600 Subject: [PATCH 13/13] fix condition --- src/vs/base/common/processes.ts | 2 +- src/vs/base/test/common/processes.test.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts index 094a413cfa117..1f76d2f722429 100644 --- a/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts @@ -108,7 +108,7 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve }, {} as Record); const keysToRemove = [ /^ELECTRON_.+$/, - /^VSCODE_^(?!SHELL).+$/, + /^VSCODE_(?!SHELL_LOGIN).+$/, /^SNAP(|_.*)$/, /^GDK_PIXBUF_.+$/, ]; diff --git a/src/vs/base/test/common/processes.test.ts b/src/vs/base/test/common/processes.test.ts index 6ef5aa061a841..182ac3979a794 100644 --- a/src/vs/base/test/common/processes.test.ts +++ b/src/vs/base/test/common/processes.test.ts @@ -21,13 +21,15 @@ suite('Processes', () => { VSCODE_NLS_CONFIG: 'x', VSCODE_PORTABLE: 'x', VSCODE_PID: 'x', + VSCODE_SHELL_LOGIN: '1', VSCODE_CODE_CACHE_PATH: 'x', VSCODE_NEW_VAR: 'x', GDK_PIXBUF_MODULE_FILE: 'x', - GDK_PIXBUF_MODULEDIR: 'x', + GDK_PIXBUF_MODULEDIR: 'x' }; processes.sanitizeProcessEnvironment(env); assert.strictEqual(env['FOO'], 'bar'); - assert.strictEqual(Object.keys(env).length, 1); + assert.strictEqual(env['VSCODE_SHELL_LOGIN'], '1'); + assert.strictEqual(Object.keys(env).length, 2); }); });