diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index be9fea82c09..7d4c44002ba 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -648,6 +648,7 @@ "./vs/workbench/parts/terminal/common/terminalMenu.ts", "./vs/workbench/parts/terminal/common/terminalService.ts", "./vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts", + "./vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/parts/terminal/node/terminal.ts", "./vs/workbench/parts/terminal/node/terminalCommandTracker.ts", "./vs/workbench/parts/terminal/node/terminalEnvironment.ts", diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index c978bb94ab1..0f276870ab5 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -124,6 +124,10 @@ export interface ITerminalFont { charHeight?: number; } +export interface ITerminalEnvironment { + [key: string]: string | null; +} + export interface IShellLaunchConfig { /** * The name of the terminal, if this is not set the name of the process will be used. @@ -152,7 +156,7 @@ export interface IShellLaunchConfig { * A custom environment for the terminal, if this is not set the environment will be inherited * from the VS Code process. */ - env?: { [key: string]: string }; + env?: ITerminalEnvironment; /** * Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (eg. if the diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts index a71d05f4b83..2e6dae63eff 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts @@ -37,7 +37,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { public shellProcessId: number; public initialCwd: string; - private _process: ITerminalChildProcess; + private _process: ITerminalChildProcess | null = null; private _preLaunchInputQueue: string[] = []; private _disposables: IDisposable[] = []; @@ -68,7 +68,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { }); } - public dispose(immediate?: boolean): void { + public dispose(immediate: boolean = false): void { if (this._process) { // If the process was still connected this dispose came from // within VS Code, not the process, so mark the process as @@ -108,8 +108,10 @@ export class TerminalProcessManager implements ITerminalProcessManager { const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot); shellLaunchConfig.env = envFromShell; + // Compell type system as process.env should not have any undefined entries + const env: platform.IProcessEnvironment = { ...process.env } as any; + // Merge process env with the env from config and from shellLaunchConfig - const env = { ...process.env }; terminalEnvironment.mergeEnvironments(env, envFromConfig); terminalEnvironment.mergeEnvironments(env, shellLaunchConfig.env); @@ -126,23 +128,26 @@ export class TerminalProcessManager implements ITerminalProcessManager { } this.processState = ProcessState.LAUNCHING; - this._process.onProcessData(data => { + // The process is non-null, but TS isn't clever enough to know + const p = this._process!; + + p.onProcessData(data => { this._onProcessData.fire(data); }); - this._process.onProcessIdReady(pid => { + p.onProcessIdReady(pid => { this.shellProcessId = pid; this._onProcessReady.fire(); // Send any queued data that's waiting if (this._preLaunchInputQueue.length > 0) { - this._process.input(this._preLaunchInputQueue.join('')); + p.input(this._preLaunchInputQueue.join('')); this._preLaunchInputQueue.length = 0; } }); - this._process.onProcessTitleChanged(title => this._onProcessTitle.fire(title)); - this._process.onProcessExit(exitCode => this._onExit(exitCode)); + p.onProcessTitleChanged(title => this._onProcessTitle.fire(title)); + p.onProcessExit(exitCode => this._onExit(exitCode)); setTimeout(() => { if (this.processState === ProcessState.LAUNCHING) { diff --git a/src/vs/workbench/parts/terminal/node/terminalEnvironment.ts b/src/vs/workbench/parts/terminal/node/terminalEnvironment.ts index 4b018a661f1..a412a3daa7e 100644 --- a/src/vs/workbench/parts/terminal/node/terminalEnvironment.ts +++ b/src/vs/workbench/parts/terminal/node/terminalEnvironment.ts @@ -9,14 +9,14 @@ import * as platform from 'vs/base/common/platform'; import pkg from 'vs/platform/node/package'; import { URI as Uri } from 'vs/base/common/uri'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/parts/terminal/common/terminal'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; /** * This module contains utility functions related to the environment, cwd and paths. */ -export function mergeEnvironments(parent: platform.IProcessEnvironment, other: platform.IProcessEnvironment): void { +export function mergeEnvironments(parent: platform.IProcessEnvironment, other: ITerminalEnvironment): void { if (!other) { return; } @@ -43,7 +43,7 @@ export function mergeEnvironments(parent: platform.IProcessEnvironment, other: p } } -function _mergeEnvironmentValue(env: platform.IProcessEnvironment, key: string, value: string | null): void { +function _mergeEnvironmentValue(env: ITerminalEnvironment, key: string, value: string | null): void { if (typeof value === 'string') { env[key] = value; } else { @@ -51,7 +51,7 @@ function _mergeEnvironmentValue(env: platform.IProcessEnvironment, key: string, } } -export function sanitizeEnvironment(env: platform.IProcessEnvironment): void { +export function sanitizeEnvironment(env: ITerminalEnvironment): void { // Remove keys based on strings const keysToRemove = [ 'ELECTRON_ENABLE_STACK_DUMPING', @@ -76,16 +76,17 @@ export function sanitizeEnvironment(env: platform.IProcessEnvironment): void { }); } -export function addTerminalEnvironmentKeys(env: platform.IProcessEnvironment, locale: string | undefined): void { +export function addTerminalEnvironmentKeys(env: ITerminalEnvironment, locale: string | undefined): void { env['TERM_PROGRAM'] = 'vscode'; env['TERM_PROGRAM_VERSION'] = pkg.version; env['LANG'] = _getLangEnvVariable(locale); } -export function resolveConfigurationVariables(configurationResolverService: IConfigurationResolverService, env: platform.IProcessEnvironment, lastActiveWorkspaceRoot: IWorkspaceFolder): platform.IProcessEnvironment { +export function resolveConfigurationVariables(configurationResolverService: IConfigurationResolverService, env: ITerminalEnvironment, lastActiveWorkspaceRoot: IWorkspaceFolder | null): ITerminalEnvironment { Object.keys(env).forEach((key) => { - if (typeof env[key] === 'string') { - env[key] = configurationResolverService.resolve(lastActiveWorkspaceRoot, env[key]); + const value = env[key]; + if (typeof value === 'string' && lastActiveWorkspaceRoot !== null) { + env[key] = configurationResolverService.resolve(lastActiveWorkspaceRoot, value); } }); return env;