terminalEnvironment.ts 5.4 KB
Newer Older
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as os from 'os';
D
Daniel Imms 已提交
7
import * as paths from 'vs/base/common/paths';
8 9
import * as platform from 'vs/base/common/platform';
import pkg from 'vs/platform/node/package';
10
import { URI as Uri } from 'vs/base/common/uri';
11
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
12
import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/parts/terminal/common/terminal';
13 14 15 16 17 18
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';

/**
 * This module contains utility functions related to the environment, cwd and paths.
 */

19
export function mergeEnvironments(parent: platform.IProcessEnvironment, other?: ITerminalEnvironment): void {
20 21 22 23 24 25 26
	if (!other) {
		return;
	}

	// On Windows apply the new values ignoring case, while still retaining
	// the case of the original key.
	if (platform.isWindows) {
D
Daniel Imms 已提交
27
		for (const configKey in other) {
28
			let actualKey = configKey;
D
Daniel Imms 已提交
29
			for (const envKey in parent) {
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
				if (configKey.toLowerCase() === envKey.toLowerCase()) {
					actualKey = envKey;
					break;
				}
			}
			const value = other[configKey];
			_mergeEnvironmentValue(parent, actualKey, value);
		}
	} else {
		Object.keys(other).forEach((key) => {
			const value = other[key];
			_mergeEnvironmentValue(parent, key, value);
		});
	}
}

46
function _mergeEnvironmentValue(env: ITerminalEnvironment, key: string, value: string | null): void {
47 48 49 50 51 52 53
	if (typeof value === 'string') {
		env[key] = value;
	} else {
		delete env[key];
	}
}

54
export function sanitizeEnvironment(env: ITerminalEnvironment): void {
55 56 57 58 59 60 61 62 63 64 65 66 67
	// Remove keys based on strings
	const keysToRemove = [
		'ELECTRON_ENABLE_STACK_DUMPING',
		'ELECTRON_ENABLE_LOGGING',
		'ELECTRON_NO_ASAR',
		'ELECTRON_NO_ATTACH_CONSOLE',
		'ELECTRON_RUN_AS_NODE',
		'GOOGLE_API_KEY',
		'VSCODE_CLI',
		'VSCODE_DEV',
		'VSCODE_IPC_HOOK',
		'VSCODE_LOGS',
		'VSCODE_NLS_CONFIG',
68
		'VSCODE_NODE_CACHED_DATA_DIR',
69 70
		'VSCODE_PORTABLE',
		'VSCODE_PID',
71
		'VSCODE_PREVENT_FOREIGN_INSPECT'
72 73 74 75 76 77 78 79
	];
	keysToRemove.forEach((key) => {
		if (env[key]) {
			delete env[key];
		}
	});
}

D
Daniel Imms 已提交
80
export function addTerminalEnvironmentKeys(env: ITerminalEnvironment, locale: string | undefined, setLocaleVariables: boolean): void {
81 82
	env['TERM_PROGRAM'] = 'vscode';
	env['TERM_PROGRAM_VERSION'] = pkg.version;
D
Daniel Imms 已提交
83 84 85
	if (setLocaleVariables) {
		env['LANG'] = _getLangEnvVariable(locale);
	}
86 87
}

88
export function resolveConfigurationVariables(configurationResolverService: IConfigurationResolverService, env: ITerminalEnvironment, lastActiveWorkspaceRoot: IWorkspaceFolder | null): ITerminalEnvironment {
89
	Object.keys(env).forEach((key) => {
90 91 92
		const value = env[key];
		if (typeof value === 'string' && lastActiveWorkspaceRoot !== null) {
			env[key] = configurationResolverService.resolve(lastActiveWorkspaceRoot, value);
93 94 95 96 97
		}
	});
	return env;
}

98
function _getLangEnvVariable(locale?: string) {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	const parts = locale ? locale.split('-') : [];
	const n = parts.length;
	if (n === 0) {
		// Fallback to en_US to prevent possible encoding issues.
		return 'en_US.UTF-8';
	}
	if (n === 1) {
		// app.getLocale can return just a language without a variant, fill in the variant for
		// supported languages as many shells expect a 2-part locale.
		const languageVariants = {
			de: 'DE',
			en: 'US',
			es: 'ES',
			fi: 'FI',
			fr: 'FR',
			it: 'IT',
			ja: 'JP',
			ko: 'KR',
			pl: 'PL',
			ru: 'RU',
			zh: 'CN'
		};
		if (parts[0] in languageVariants) {
			parts.push(languageVariants[parts[0]]);
		}
	} else {
		// Ensure the variant is uppercase
		parts[1] = parts[1].toUpperCase();
	}
	return parts.join('_') + '.UTF-8';
}

131
export function getCwd(shell: IShellLaunchConfig, root?: Uri, customCwd?: string): string {
132
	if (shell.cwd) {
K
kieferrm 已提交
133
		return (typeof shell.cwd === 'object') ? shell.cwd.path : shell.cwd;
134 135
	}

136
	let cwd: string | undefined;
137 138

	// TODO: Handle non-existent customCwd
139 140 141 142 143
	if (!shell.ignoreConfigurationCwd && customCwd) {
		if (paths.isAbsolute(customCwd)) {
			cwd = customCwd;
		} else if (root) {
			cwd = paths.normalize(paths.join(root.fsPath, customCwd));
144 145 146 147 148
		}
	}

	// If there was no custom cwd or it was relative with no workspace
	if (!cwd) {
149
		cwd = root ? root.fsPath : os.homedir();
150 151 152 153 154 155 156 157 158 159 160 161
	}

	return _sanitizeCwd(cwd);
}

function _sanitizeCwd(cwd: string): string {
	// Make the drive letter uppercase on Windows (see #9448)
	if (platform.platform === platform.Platform.Windows && cwd && cwd[1] === ':') {
		return cwd[0].toUpperCase() + cwd.substr(1);
	}
	return cwd;
}
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

/**
 * Adds quotes to a path if it contains whitespaces
 */
export function preparePathForTerminal(path: string): string {
	if (platform.isWindows) {
		if (/\s+/.test(path)) {
			return `"${path}"`;
		}
		return path;
	}
	path = path.replace(/(%5C|\\)/g, '\\\\');
	const charsToEscape = [
		' ', '\'', '"', '?', ':', ';', '!', '*', '(', ')', '{', '}', '[', ']'
	];
	for (let i = 0; i < path.length; i++) {
		const indexOfChar = charsToEscape.indexOf(path.charAt(i));
		if (indexOfChar >= 0) {
			path = `${path.substring(0, i)}\\${path.charAt(i)}${path.substring(i + 1)}`;
			i++; // Skip char due to escape char being added
		}
	}
	return path;
}