Vscode merge (#4582)

* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd

* fix issues with merges

* bump node version in azpipe

* replace license headers

* remove duplicate launch task

* fix build errors

* fix build errors

* fix tslint issues

* working through package and linux build issues

* more work

* wip

* fix packaged builds

* working through linux build errors

* wip

* wip

* wip

* fix mac and linux file limits

* iterate linux pipeline

* disable editor typing

* revert series to parallel

* remove optimize vscode from linux

* fix linting issues

* revert testing change

* add work round for new node

* readd packaging for extensions

* fix issue with angular not resolving decorator dependencies
This commit is contained in:
Anthony Dresser
2019-03-19 17:44:35 -07:00
committed by GitHub
parent 833d197412
commit 87765e8673
1879 changed files with 54505 additions and 38058 deletions

View File

@@ -5,8 +5,7 @@
import { URI as uri } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import * as paths from 'vs/base/common/paths';
import * as platform from 'vs/base/common/platform';
import * as path from 'vs/base/common/path';
import * as Types from 'vs/base/common/types';
import { Schemas } from 'vs/base/common/network';
import { toResource } from 'vs/workbench/common/editor';
@@ -16,18 +15,20 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IWorkspaceFolder, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ConfiguredInput, IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class ConfigurationResolverService extends AbstractVariableResolverService {
static INPUT_OR_COMMAND_VARIABLES_PATTERN = /\${((input|command):(.*?))}/g;
constructor(
envVariables: platform.IProcessEnvironment,
@IWindowService windowService: IWindowService,
@IEditorService editorService: IEditorService,
@IEnvironmentService environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@@ -58,7 +59,7 @@ export class ConfigurationResolverService extends AbstractVariableResolverServic
if (!fileResource) {
return undefined;
}
return paths.normalize(fileResource.fsPath, true);
return path.normalize(fileResource.fsPath);
},
getSelectedText: (): string | undefined => {
const activeTextEditorWidget = editorService.activeTextEditorWidget;
@@ -79,7 +80,7 @@ export class ConfigurationResolverService extends AbstractVariableResolverServic
}
return undefined;
}
}, envVariables);
}, windowService.getConfiguration().userEnv);
}
public resolveWithInteractionReplace(folder: IWorkspaceFolder, config: any, section?: string, variables?: IStringDictionary<string>): Promise<any> {
@@ -287,4 +288,6 @@ export class ConfigurationResolverService extends AbstractVariableResolverServic
}
return Promise.reject(new Error(nls.localize('inputVariable.undefinedVariable', "Undefined input variable '{0}' encountered. Remove or define '{0}' to continue.", variable)));
}
}
}
registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true);

View File

@@ -12,15 +12,15 @@ export const IConfigurationResolverService = createDecorator<IConfigurationResol
export interface IConfigurationResolverService {
_serviceBrand: any;
resolve(folder: IWorkspaceFolder, value: string): string;
resolve(folder: IWorkspaceFolder, value: string[]): string[];
resolve(folder: IWorkspaceFolder, value: IStringDictionary<string>): IStringDictionary<string>;
resolve(folder: IWorkspaceFolder | undefined, value: string): string;
resolve(folder: IWorkspaceFolder | undefined, value: string[]): string[];
resolve(folder: IWorkspaceFolder | undefined, value: IStringDictionary<string>): IStringDictionary<string>;
/**
* Recursively resolves all variables in the given config and returns a copy of it with substituted values.
* Command variables are only substituted if a "commandValueMapping" dictionary is given and if it contains an entry for the command.
*/
resolveAny(folder: IWorkspaceFolder, config: any, commandValueMapping?: IStringDictionary<string>): any;
resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary<string>): any;
/**
* Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values.
@@ -29,13 +29,13 @@ export interface IConfigurationResolverService {
* @param section For example, 'tasks' or 'debug'. Used for resolving inputs.
* @param variables Aliases for commands.
*/
resolveWithInteractionReplace(folder: IWorkspaceFolder, config: any, section?: string, variables?: IStringDictionary<string>): Promise<any>;
resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary<string>): Promise<any>;
/**
* Similar to resolveWithInteractionReplace, except without the replace. Returns a map of variables and their resolution.
* Keys in the map will be of the format input:variableName or command:variableName.
*/
resolveWithInteraction(folder: IWorkspaceFolder, config: any, section?: string, variables?: IStringDictionary<string>): Promise<Map<string, string>>;
resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary<string>): Promise<Map<string, string>>;
}
export interface PromptStringInputInfo {

View File

@@ -0,0 +1,277 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as paths from 'vs/base/common/path';
import * as process from 'vs/base/common/process';
import * as types from 'vs/base/common/types';
import * as objects from 'vs/base/common/objects';
import { IStringDictionary } from 'vs/base/common/collections';
import { IProcessEnvironment, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { localize } from 'vs/nls';
import { URI as uri } from 'vs/base/common/uri';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
export interface IVariableResolveContext {
getFolderUri(folderName: string): uri | undefined;
getWorkspaceFolderCount(): number;
getConfigurationValue(folderUri: uri, section: string): string | undefined;
getExecPath(): string | undefined;
getFilePath(): string | undefined;
getSelectedText(): string | undefined;
getLineNumber(): string | undefined;
}
export class AbstractVariableResolverService implements IConfigurationResolverService {
static VARIABLE_REGEXP = /\$\{(.*?)\}/g;
_serviceBrand: any;
constructor(
private _context: IVariableResolveContext,
private _envVariables: IProcessEnvironment
) {
if (isWindows) {
this._envVariables = Object.create(null);
Object.keys(_envVariables).forEach(key => {
this._envVariables[key.toLowerCase()] = _envVariables[key];
});
}
}
public resolve(root: IWorkspaceFolder | undefined, value: string): string;
public resolve(root: IWorkspaceFolder | undefined, value: string[]): string[];
public resolve(root: IWorkspaceFolder | undefined, value: IStringDictionary<string>): IStringDictionary<string>;
public resolve(root: IWorkspaceFolder | undefined, value: any): any {
return this.recursiveResolve(root ? root.uri : undefined, value);
}
public resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary<string>, resolvedVariables?: Map<string, string>): any {
const result = objects.deepClone(config) as any;
// hoist platform specific attributes to top level
if (isWindows && result.windows) {
Object.keys(result.windows).forEach(key => result[key] = result.windows[key]);
} else if (isMacintosh && result.osx) {
Object.keys(result.osx).forEach(key => result[key] = result.osx[key]);
} else if (isLinux && result.linux) {
Object.keys(result.linux).forEach(key => result[key] = result.linux[key]);
}
// delete all platform specific sections
delete result.windows;
delete result.osx;
delete result.linux;
// substitute all variables recursively in string values
return this.recursiveResolve(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables);
}
public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary<string>): any {
return this.resolveAnyBase(workspaceFolder, config, commandValueMapping);
}
public resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary<string>): { newConfig: any, resolvedVariables: Map<string, string> } {
const resolvedVariables = new Map<string, string>();
const newConfig = this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables);
return { newConfig, resolvedVariables };
}
public resolveWithInteractionReplace(folder: IWorkspaceFolder, config: any): Promise<any> {
throw new Error('resolveWithInteractionReplace not implemented.');
}
public resolveWithInteraction(folder: IWorkspaceFolder, config: any): Promise<any> {
throw new Error('resolveWithInteraction not implemented.');
}
private recursiveResolve(folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary<string>, resolvedVariables?: Map<string, string>): any {
if (types.isString(value)) {
return this.resolveString(folderUri, value, commandValueMapping, resolvedVariables);
} else if (types.isArray(value)) {
return value.map(s => this.recursiveResolve(folderUri, s, commandValueMapping, resolvedVariables));
} else if (types.isObject(value)) {
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
Object.keys(value).forEach(key => {
const replaced = this.resolveString(folderUri, key, commandValueMapping, resolvedVariables);
result[replaced] = this.recursiveResolve(folderUri, value[key], commandValueMapping, resolvedVariables);
});
return result;
}
return value;
}
private resolveString(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary<string> | undefined, resolvedVariables?: Map<string, string>): string {
// loop through all variables occurrences in 'value'
const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => {
let resolvedValue = this.evaluateSingleVariable(match, variable, folderUri, commandValueMapping);
if (resolvedVariables) {
resolvedVariables.set(variable, resolvedValue);
}
return resolvedValue;
});
return replaced;
}
private evaluateSingleVariable(match: string, variable: string, folderUri: uri | undefined, commandValueMapping: IStringDictionary<string> | undefined): string {
// try to separate variable arguments from variable name
let argument: string | undefined;
const parts = variable.split(':');
if (parts.length > 1) {
variable = parts[0];
argument = parts[1];
}
// common error handling for all variables that require an open editor
const getFilePath = (): string => {
const filePath = this._context.getFilePath();
if (filePath) {
return filePath;
}
throw new Error(localize('canNotResolveFile', "'{0}' can not be resolved. Please open an editor.", match));
};
// common error handling for all variables that require an open folder and accept a folder name argument
const getFolderUri = (withArg = true): uri => {
if (withArg && argument) {
const folder = this._context.getFolderUri(argument);
if (folder) {
return folder;
}
throw new Error(localize('canNotFindFolder', "'{0}' can not be resolved. No such folder '{1}'.", match, argument));
}
if (folderUri) {
return folderUri;
}
if (this._context.getWorkspaceFolderCount() > 1) {
throw new Error(localize('canNotResolveWorkspaceFolderMultiRoot', "'{0}' can not be resolved in a multi folder workspace. Scope this variable using ':' and a workspace folder name.", match));
}
throw new Error(localize('canNotResolveWorkspaceFolder', "'{0}' can not be resolved. Please open a folder.", match));
};
switch (variable) {
case 'env':
if (argument) {
if (isWindows) {
argument = argument.toLowerCase();
}
const env = this._envVariables[argument];
if (types.isString(env)) {
return env;
}
// For `env` we should do the same as a normal shell does - evaluates missing envs to an empty string #46436
return '';
}
throw new Error(localize('missingEnvVarName', "'{0}' can not be resolved because no environment variable name is given.", match));
case 'config':
if (argument) {
const config = this._context.getConfigurationValue(getFolderUri(false), argument);
if (types.isUndefinedOrNull(config)) {
throw new Error(localize('configNotFound', "'{0}' can not be resolved because setting '{1}' not found.", match, argument));
}
if (types.isObject(config)) {
throw new Error(localize('configNoString', "'{0}' can not be resolved because '{1}' is a structured value.", match, argument));
}
return config;
}
throw new Error(localize('missingConfigName', "'{0}' can not be resolved because no settings name is given.", match));
case 'command':
return this.resolveFromMap(match, argument, commandValueMapping, 'command');
case 'input':
return this.resolveFromMap(match, argument, commandValueMapping, 'input');
default: {
switch (variable) {
case 'workspaceRoot':
case 'workspaceFolder':
return normalizeDriveLetter(getFolderUri().fsPath);
case 'cwd':
return (folderUri ? normalizeDriveLetter(getFolderUri().fsPath) : process.cwd());
case 'workspaceRootFolderName':
case 'workspaceFolderBasename':
return paths.basename(getFolderUri().fsPath);
case 'lineNumber':
const lineNumber = this._context.getLineNumber();
if (lineNumber) {
return lineNumber;
}
throw new Error(localize('canNotResolveLineNumber', "'{0}' can not be resolved. Make sure to have a line selected in the active editor.", match));
case 'selectedText':
const selectedText = this._context.getSelectedText();
if (selectedText) {
return selectedText;
}
throw new Error(localize('canNotResolveSelectedText', "'{0}' can not be resolved. Make sure to have some text selected in the active editor.", match));
case 'file':
return getFilePath();
case 'relativeFile':
if (folderUri) {
return paths.normalize(paths.relative(getFolderUri().fsPath, getFilePath()));
}
return getFilePath();
case 'fileDirname':
return paths.dirname(getFilePath());
case 'fileExtname':
return paths.extname(getFilePath());
case 'fileBasename':
return paths.basename(getFilePath());
case 'fileBasenameNoExtension':
const basename = paths.basename(getFilePath());
return (basename.slice(0, basename.length - paths.extname(basename).length));
case 'execPath':
const ep = this._context.getExecPath();
if (ep) {
return ep;
}
return match;
default:
return match;
}
}
}
}
private resolveFromMap(match: string, argument: string | undefined, commandValueMapping: IStringDictionary<string> | undefined, prefix: string): string {
if (argument && commandValueMapping) {
const v = commandValueMapping[prefix + ':' + argument];
if (typeof v === 'string') {
return v;
}
throw new Error(localize('noValueForCommand', "'{0}' can not be resolved because the command has no value.", match));
}
return match;
}
}

View File

@@ -1,283 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as paths from 'vs/base/common/paths';
import * as types from 'vs/base/common/types';
import * as objects from 'vs/base/common/objects';
import { IStringDictionary } from 'vs/base/common/collections';
import { relative } from 'path';
import { IProcessEnvironment, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { localize } from 'vs/nls';
import { URI as uri } from 'vs/base/common/uri';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
export interface IVariableResolveContext {
getFolderUri(folderName: string): uri | undefined;
getWorkspaceFolderCount(): number;
getConfigurationValue(folderUri: uri, section: string): string | undefined;
getExecPath(): string | undefined;
getFilePath(): string | undefined;
getSelectedText(): string | undefined;
getLineNumber(): string;
}
export class AbstractVariableResolverService implements IConfigurationResolverService {
static VARIABLE_REGEXP = /\$\{(.*?)\}/g;
_serviceBrand: any;
constructor(
private _context: IVariableResolveContext,
private _envVariables: IProcessEnvironment = process.env
) {
if (isWindows) {
this._envVariables = Object.create(null);
Object.keys(_envVariables).forEach(key => {
this._envVariables[key.toLowerCase()] = _envVariables[key];
});
}
}
public resolve(root: IWorkspaceFolder, value: string): string;
public resolve(root: IWorkspaceFolder, value: string[]): string[];
public resolve(root: IWorkspaceFolder, value: IStringDictionary<string>): IStringDictionary<string>;
public resolve(root: IWorkspaceFolder, value: any): any {
return this.recursiveResolve(root ? root.uri : undefined, value);
}
public resolveAnyBase(workspaceFolder: IWorkspaceFolder, config: any, commandValueMapping?: IStringDictionary<string>, resolvedVariables?: Map<string, string>): any {
const result = objects.deepClone(config) as any;
// hoist platform specific attributes to top level
if (isWindows && result.windows) {
Object.keys(result.windows).forEach(key => result[key] = result.windows[key]);
} else if (isMacintosh && result.osx) {
Object.keys(result.osx).forEach(key => result[key] = result.osx[key]);
} else if (isLinux && result.linux) {
Object.keys(result.linux).forEach(key => result[key] = result.linux[key]);
}
// delete all platform specific sections
delete result.windows;
delete result.osx;
delete result.linux;
// substitute all variables recursively in string values
return this.recursiveResolve(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables);
}
public resolveAny(workspaceFolder: IWorkspaceFolder, config: any, commandValueMapping?: IStringDictionary<string>): any {
return this.resolveAnyBase(workspaceFolder, config, commandValueMapping);
}
public resolveAnyMap(workspaceFolder: IWorkspaceFolder, config: any, commandValueMapping?: IStringDictionary<string>): { newConfig: any, resolvedVariables: Map<string, string> } {
const resolvedVariables = new Map<string, string>();
const newConfig = this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables);
return { newConfig, resolvedVariables };
}
public resolveWithInteractionReplace(folder: IWorkspaceFolder, config: any): Promise<any> {
throw new Error('resolveWithInteractionReplace not implemented.');
}
public resolveWithInteraction(folder: IWorkspaceFolder, config: any): Promise<any> {
throw new Error('resolveWithInteraction not implemented.');
}
private recursiveResolve(folderUri: uri, value: any, commandValueMapping?: IStringDictionary<string>, resolvedVariables?: Map<string, string>): any {
if (types.isString(value)) {
const resolved = this.resolveString(folderUri, value, commandValueMapping);
if (resolvedVariables) {
resolvedVariables.set(resolved.variableName, resolved.resolvedValue);
}
return resolved.replaced;
} else if (types.isArray(value)) {
return value.map(s => this.recursiveResolve(folderUri, s, commandValueMapping, resolvedVariables));
} else if (types.isObject(value)) {
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
Object.keys(value).forEach(key => {
const resolvedKey = this.resolveString(folderUri, key, commandValueMapping);
if (resolvedVariables) {
resolvedVariables.set(resolvedKey.variableName, resolvedKey.resolvedValue);
}
result[resolvedKey.replaced] = this.recursiveResolve(folderUri, value[key], commandValueMapping, resolvedVariables);
});
return result;
}
return value;
}
private resolveString(folderUri: uri, value: string, commandValueMapping: IStringDictionary<string>): { replaced: string, variableName: string, resolvedValue: string } {
const filePath = this._context.getFilePath();
let variableName: string;
let resolvedValue: string;
const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => {
variableName = variable;
let argument: string;
const parts = variable.split(':');
if (parts && parts.length > 1) {
variable = parts[0];
argument = parts[1];
}
switch (variable) {
case 'env':
if (argument) {
if (isWindows) {
argument = argument.toLowerCase();
}
const env = this._envVariables[argument];
if (types.isString(env)) {
return resolvedValue = env;
}
// For `env` we should do the same as a normal shell does - evaluates missing envs to an empty string #46436
return resolvedValue = '';
}
throw new Error(localize('missingEnvVarName', "'{0}' can not be resolved because no environment variable name is given.", match));
case 'config':
if (argument) {
const config = this._context.getConfigurationValue(folderUri, argument);
if (types.isUndefinedOrNull(config)) {
throw new Error(localize('configNotFound', "'{0}' can not be resolved because setting '{1}' not found.", match, argument));
}
if (types.isObject(config)) {
throw new Error(localize('configNoString', "'{0}' can not be resolved because '{1}' is a structured value.", match, argument));
}
return resolvedValue = config;
}
throw new Error(localize('missingConfigName', "'{0}' can not be resolved because no settings name is given.", match));
case 'command':
return resolvedValue = this.resolveFromMap(match, argument, commandValueMapping, 'command');
case 'input':
return resolvedValue = this.resolveFromMap(match, argument, commandValueMapping, 'input');
default: {
// common error handling for all variables that require an open folder and accept a folder name argument
switch (variable) {
case 'workspaceRoot':
case 'workspaceFolder':
case 'workspaceRootFolderName':
case 'workspaceFolderBasename':
case 'relativeFile':
if (argument) {
const folder = this._context.getFolderUri(argument);
if (folder) {
folderUri = folder;
} else {
throw new Error(localize('canNotFindFolder', "'{0}' can not be resolved. No such folder '{1}'.", match, argument));
}
}
if (!folderUri) {
if (this._context.getWorkspaceFolderCount() > 1) {
throw new Error(localize('canNotResolveWorkspaceFolderMultiRoot', "'{0}' can not be resolved in a multi folder workspace. Scope this variable using ':' and a workspace folder name.", match));
}
throw new Error(localize('canNotResolveWorkspaceFolder', "'{0}' can not be resolved. Please open a folder.", match));
}
break;
default:
break;
}
// common error handling for all variables that require an open file
switch (variable) {
case 'file':
case 'relativeFile':
case 'fileDirname':
case 'fileExtname':
case 'fileBasename':
case 'fileBasenameNoExtension':
if (!filePath) {
throw new Error(localize('canNotResolveFile', "'{0}' can not be resolved. Please open an editor.", match));
}
break;
default:
break;
}
switch (variable) {
case 'workspaceRoot':
case 'workspaceFolder':
return resolvedValue = normalizeDriveLetter(folderUri.fsPath);
case 'cwd':
return resolvedValue = (folderUri ? normalizeDriveLetter(folderUri.fsPath) : process.cwd());
case 'workspaceRootFolderName':
case 'workspaceFolderBasename':
return resolvedValue = paths.basename(folderUri.fsPath);
case 'lineNumber':
const lineNumber = this._context.getLineNumber();
if (lineNumber) {
return resolvedValue = lineNumber;
}
throw new Error(localize('canNotResolveLineNumber', "'{0}' can not be resolved. Make sure to have a line selected in the active editor.", match));
case 'selectedText':
const selectedText = this._context.getSelectedText();
if (selectedText) {
return resolvedValue = selectedText;
}
throw new Error(localize('canNotResolveSelectedText', "'{0}' can not be resolved. Make sure to have some text selected in the active editor.", match));
case 'file':
return resolvedValue = filePath;
case 'relativeFile':
if (folderUri) {
return resolvedValue = paths.normalize(relative(folderUri.fsPath, filePath));
}
return resolvedValue = filePath;
case 'fileDirname':
return resolvedValue = paths.dirname(filePath);
case 'fileExtname':
return resolvedValue = paths.extname(filePath);
case 'fileBasename':
return resolvedValue = paths.basename(filePath);
case 'fileBasenameNoExtension':
const basename = paths.basename(filePath);
return resolvedValue = (basename.slice(0, basename.length - paths.extname(basename).length));
case 'execPath':
const ep = this._context.getExecPath();
if (ep) {
return resolvedValue = ep;
}
return resolvedValue = match;
default:
return resolvedValue = match;
}
}
}
});
return { replaced, variableName, resolvedValue };
}
private resolveFromMap(match: string, argument: string, commandValueMapping: IStringDictionary<string>, prefix: string): string {
if (argument && commandValueMapping) {
const v = commandValueMapping[prefix + ':' + argument];
if (typeof v === 'string') {
return v;
}
throw new Error(localize('noValueForCommand', "'{0}' can not be resolved because the command has no value.", match));
}
return match;
}
}

View File

@@ -9,18 +9,20 @@ import * as platform from 'vs/base/common/platform';
import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService';
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { TestEnvironmentService, TestEditorService, TestContextService } from 'vs/workbench/test/workbenchTestServices';
import { TestEnvironmentService, TestEditorService, TestContextService, TestWindowService } from 'vs/workbench/test/workbenchTestServices';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { Disposable } from 'vs/base/common/lifecycle';
import { IQuickInputService, IQuickPickItem, QuickPickInput, IPickOptions, Omit, IInputOptions, IQuickInputButton, IQuickPick, IInputBox, IQuickNavigateConfiguration } from 'vs/platform/quickinput/common/quickInput';
import { CancellationToken } from 'vscode';
import { CancellationToken } from 'vs/base/common/cancellation';
import * as Types from 'vs/base/common/types';
import { IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows';
suite('Configuration Resolver Service', () => {
let configurationResolverService: IConfigurationResolverService;
let configurationResolverService: IConfigurationResolverService | null;
let envVariables: { [key: string]: string } = { key1: 'Value for key1', key2: 'Value for key2' };
let windowService: IWindowService;
let mockCommandService: MockCommandService;
let editorService: TestEditorService;
let workspace: IWorkspaceFolder;
@@ -30,13 +32,14 @@ suite('Configuration Resolver Service', () => {
mockCommandService = new MockCommandService();
editorService = new TestEditorService();
quickInputService = new MockQuickInputService();
windowService = new MockWindowService(envVariables);
workspace = {
uri: uri.parse('file:///VSCode/workspaceLocation'),
name: 'hey',
index: 0,
toResource: () => null
};
configurationResolverService = new ConfigurationResolverService(envVariables, editorService, TestEnvironmentService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(), quickInputService);
configurationResolverService = new ConfigurationResolverService(windowService, editorService, TestEnvironmentService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(), quickInputService);
});
teardown(() => {
@@ -45,46 +48,46 @@ suite('Configuration Resolver Service', () => {
test('substitute one', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc \\VSCode\\workspaceLocation xyz');
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc \\VSCode\\workspaceLocation xyz');
} else {
assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc /VSCode/workspaceLocation xyz');
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc /VSCode/workspaceLocation xyz');
}
});
test('workspace root folder name', () => {
assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz');
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz');
});
// TODO@isidor mock the editor service properly
// test('current selected line number', () => {
// assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`);
// assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`);
// });
// test('current selected text', () => {
// assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${selectedText} xyz'), `abc ${editorService.mockSelectedText} xyz`);
// assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${selectedText} xyz'), `abc ${editorService.mockSelectedText} xyz`);
// });
test('substitute many', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation');
assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation');
} else {
assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation');
assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation');
}
});
test('substitute one env variable', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for key1 xyz');
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for key1 xyz');
} else {
assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for key1 xyz');
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for key1 xyz');
}
});
test('substitute many env variable', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2');
assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2');
} else {
assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for key1 - Value for key2');
assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for key1 - Value for key2');
}
});
@@ -93,7 +96,7 @@ suite('Configuration Resolver Service', () => {
// '${workspaceRootFolderName}': '${lineNumber}',
// 'hey ${env:key1} ': '${workspaceRootFolderName}'
// };
// assert.deepEqual(configurationResolverService.resolve(workspace, myObject), {
// assert.deepEqual(configurationResolverService!.resolve(workspace, myObject), {
// 'workspaceLocation': `${editorService.mockLineNumber}`,
// 'hey Value for key1 ': 'workspaceLocation'
// });
@@ -102,15 +105,14 @@ suite('Configuration Resolver Service', () => {
test('substitute one env variable using platform case sensitivity', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - Value for key1');
assert.strictEqual(configurationResolverService!.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - Value for key1');
} else {
assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - ');
assert.strictEqual(configurationResolverService!.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - ');
}
});
test('substitute one configuration variable', () => {
let configurationService: IConfigurationService;
configurationService = new MockConfigurationService({
let configurationService: IConfigurationService = new MockConfigurationService({
editor: {
fontFamily: 'foo'
},
@@ -121,7 +123,7 @@ suite('Configuration Resolver Service', () => {
}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz');
});
@@ -138,7 +140,7 @@ suite('Configuration Resolver Service', () => {
}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz');
});
@@ -155,7 +157,7 @@ suite('Configuration Resolver Service', () => {
}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
if (platform.isWindows) {
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${workspaceFolder} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for key1 xyz');
} else {
@@ -176,7 +178,7 @@ suite('Configuration Resolver Service', () => {
}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
if (platform.isWindows) {
assert.strictEqual(service.resolve(workspace, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2');
} else {
@@ -210,7 +212,7 @@ suite('Configuration Resolver Service', () => {
}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz');
});
@@ -220,7 +222,7 @@ suite('Configuration Resolver Service', () => {
editor: {}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
assert.strictEqual(service.resolve(workspace, 'abc ${unknownVariable} xyz'), 'abc ${unknownVariable} xyz');
assert.strictEqual(service.resolve(workspace, 'abc ${env:unknownVariable} xyz'), 'abc xyz');
});
@@ -233,7 +235,7 @@ suite('Configuration Resolver Service', () => {
}
});
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
let service = new ConfigurationResolverService(windowService, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService(), quickInputService);
assert.throws(() => service.resolve(workspace, 'abc ${env} xyz'));
assert.throws(() => service.resolve(workspace, 'abc ${env:} xyz'));
@@ -256,7 +258,7 @@ suite('Configuration Resolver Service', () => {
'outDir': null
};
return configurationResolverService.resolveWithInteractionReplace(undefined, configuration).then(result => {
return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration).then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -285,7 +287,7 @@ suite('Configuration Resolver Service', () => {
const commandVariables = Object.create(null);
commandVariables['commandVariable1'] = 'command1';
return configurationResolverService.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => {
return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -318,7 +320,7 @@ suite('Configuration Resolver Service', () => {
const commandVariables = Object.create(null);
commandVariables['commandVariable1'] = 'command1';
return configurationResolverService.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => {
return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -349,7 +351,7 @@ suite('Configuration Resolver Service', () => {
const commandVariables = Object.create(null);
commandVariables['commandVariable1'] = 'command1';
return configurationResolverService.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => {
return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -374,7 +376,7 @@ suite('Configuration Resolver Service', () => {
'outDir': null
};
return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -401,7 +403,7 @@ suite('Configuration Resolver Service', () => {
'outDir': null
};
return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -428,7 +430,7 @@ suite('Configuration Resolver Service', () => {
'outDir': null
};
return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
assert.deepEqual(result, {
'name': 'Attach to Process',
@@ -456,7 +458,7 @@ suite('Configuration Resolver Service', () => {
'outDir': null
};
return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => {
assert.deepEqual(result, {
'name': 'resolvedEnterinput3',
@@ -490,15 +492,15 @@ class MockConfigurationService implements IConfigurationService {
const valuePath = (<string>value).split('.');
let object = this.configuration;
while (valuePath.length && object) {
object = object[valuePath.shift()];
object = object[valuePath.shift()!];
}
return object;
}
public updateValue(): Promise<void> { return null; }
public updateValue(): Promise<void> { return Promise.resolve(); }
public getConfigurationData(): any { return null; }
public onDidChangeConfiguration() { return { dispose() { } }; }
public reloadConfiguration() { return null; }
public reloadConfiguration() { return Promise.resolve(); }
}
class MockCommandService implements ICommandService {
@@ -612,3 +614,14 @@ class MockInputsConfigurationService extends TestConfigurationService {
return configuration;
}
}
class MockWindowService extends TestWindowService {
constructor(private env: platform.IProcessEnvironment) {
super();
}
getConfiguration(): IWindowConfiguration {
return { userEnv: this.env } as IWindowConfiguration;
}
}