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

@@ -0,0 +1,293 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI as uri } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
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';
import { IStringDictionary, forEach, fromMap } from 'vs/base/common/collections';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
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/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, 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(
@IWindowService windowService: IWindowService,
@IEditorService editorService: IEditorService,
@IEnvironmentService environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ICommandService private readonly commandService: ICommandService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super({
getFolderUri: (folderName: string): uri => {
const folder = workspaceContextService.getWorkspace().folders.filter(f => f.name === folderName).pop();
return folder ? folder.uri : undefined;
},
getWorkspaceFolderCount: (): number => {
return workspaceContextService.getWorkspace().folders.length;
},
getConfigurationValue: (folderUri: uri, suffix: string) => {
return configurationService.getValue<string>(suffix, folderUri ? { resource: folderUri } : undefined);
},
getExecPath: () => {
return environmentService['execPath'];
},
getFilePath: (): string | undefined => {
let activeEditor = editorService.activeEditor;
if (activeEditor instanceof DiffEditorInput) {
activeEditor = activeEditor.modifiedInput;
}
const fileResource = toResource(activeEditor, { filter: Schemas.file });
if (!fileResource) {
return undefined;
}
return path.normalize(fileResource.fsPath);
},
getSelectedText: (): string | undefined => {
const activeTextEditorWidget = editorService.activeTextEditorWidget;
if (isCodeEditor(activeTextEditorWidget)) {
const editorModel = activeTextEditorWidget.getModel();
const editorSelection = activeTextEditorWidget.getSelection();
if (editorModel && editorSelection) {
return editorModel.getValueInRange(editorSelection);
}
}
return undefined;
},
getLineNumber: (): string => {
const activeTextEditorWidget = editorService.activeTextEditorWidget;
if (isCodeEditor(activeTextEditorWidget)) {
const lineNumber = activeTextEditorWidget.getSelection().positionLineNumber;
return String(lineNumber);
}
return undefined;
}
}, windowService.getConfiguration().userEnv);
}
public resolveWithInteractionReplace(folder: IWorkspaceFolder, config: any, section?: string, variables?: IStringDictionary<string>): Promise<any> {
// resolve any non-interactive variables
config = this.resolveAny(folder, config);
// resolve input variables in the order in which they are encountered
return this.resolveWithInteraction(folder, config, section, variables).then(mapping => {
// finally substitute evaluated command variables (if there are any)
if (!mapping) {
return null;
} else if (mapping.size > 0) {
return this.resolveAny(folder, config, fromMap(mapping));
} else {
return config;
}
});
}
public resolveWithInteraction(folder: IWorkspaceFolder, config: any, section?: string, variables?: IStringDictionary<string>): Promise<Map<string, string>> {
// resolve any non-interactive variables
const resolved = this.resolveAnyMap(folder, config);
config = resolved.newConfig;
const allVariableMapping: Map<string, string> = resolved.resolvedVariables;
// resolve input and command variables in the order in which they are encountered
return this.resolveWithInputAndCommands(folder, config, variables, section).then(inputOrCommandMapping => {
if (this.updateMapping(inputOrCommandMapping, allVariableMapping)) {
return allVariableMapping;
}
return undefined;
});
}
/**
* Add all items from newMapping to fullMapping. Returns false if newMapping is undefined.
*/
private updateMapping(newMapping: IStringDictionary<string>, fullMapping: Map<string, string>): boolean {
if (!newMapping) {
return false;
}
forEach(newMapping, (entry) => {
fullMapping.set(entry.key, entry.value);
});
return true;
}
/**
* Finds and executes all input and command variables in the given configuration and returns their values as a dictionary.
* Please note: this method does not substitute the input or command variables (so the configuration is not modified).
* The returned dictionary can be passed to "resolvePlatform" for the actual substitution.
* See #6569.
*
* @param variableToCommandMap Aliases for commands
*/
private async resolveWithInputAndCommands(folder: IWorkspaceFolder, configuration: any, variableToCommandMap: IStringDictionary<string>, section: string): Promise<IStringDictionary<string>> {
if (!configuration) {
return Promise.resolve(undefined);
}
// get all "inputs"
let inputs: ConfiguredInput[] = undefined;
if (folder && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) {
let result = this.configurationService.getValue<any>(section, { resource: folder.uri });
if (result) {
inputs = result.inputs;
}
}
// extract and dedupe all "input" and "command" variables and preserve their order in an array
const variables: string[] = [];
this.findVariables(configuration, variables);
const variableValues: IStringDictionary<string> = Object.create(null);
for (const variable of variables) {
const [type, name] = variable.split(':', 2);
let result: string | undefined | null;
switch (type) {
case 'input':
result = await this.showUserInput(name, inputs);
break;
case 'command':
// use the name as a command ID #12735
const commandId = (variableToCommandMap ? variableToCommandMap[name] : undefined) || name;
result = await this.commandService.executeCommand(commandId, configuration);
if (typeof result !== 'string' && !Types.isUndefinedOrNull(result)) {
throw new Error(nls.localize('commandVariable.noStringType', "Cannot substitute command variable '{0}' because command did not return a result of type string.", commandId));
}
break;
}
if (typeof result === 'string') {
variableValues[variable] = result;
} else {
return undefined;
}
}
return variableValues;
}
/**
* Recursively finds all command or input variables in object and pushes them into variables.
* @param object object is searched for variables.
* @param variables All found variables are returned in variables.
*/
private findVariables(object: any, variables: string[]) {
if (typeof object === 'string') {
let matches;
while ((matches = ConfigurationResolverService.INPUT_OR_COMMAND_VARIABLES_PATTERN.exec(object)) !== null) {
if (matches.length === 4) {
const command = matches[1];
if (variables.indexOf(command) < 0) {
variables.push(command);
}
}
}
} else if (Types.isArray(object)) {
object.forEach(value => {
this.findVariables(value, variables);
});
} else if (object) {
Object.keys(object).forEach(key => {
const value = object[key];
this.findVariables(value, variables);
});
}
}
/**
* Takes the provided input info and shows the quick pick so the user can provide the value for the input
* @param variable Name of the input variable.
* @param inputInfos Information about each possible input variable.
*/
private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise<string> {
// find info for the given input variable
const info = inputInfos.filter(item => item.id === variable).pop();
if (info) {
const missingAttribute = (attrName: string) => {
throw new Error(nls.localize('inputVariable.missingAttribute', "Input variable '{0}' is of type '{1}' and must include '{2}'.", variable, info.type, attrName));
};
switch (info.type) {
case 'promptString': {
if (!Types.isString(info.description)) {
missingAttribute('description');
}
const inputOptions: IInputOptions = { prompt: info.description };
if (info.default) {
inputOptions.value = info.default;
}
return this.quickInputService.input(inputOptions).then(resolvedInput => {
return resolvedInput ? resolvedInput : undefined;
});
}
case 'pickString': {
if (!Types.isString(info.description)) {
missingAttribute('description');
}
if (!Types.isStringArray(info.options)) {
missingAttribute('options');
}
const picks = new Array<IQuickPickItem>();
info.options.forEach(pickOption => {
const item: IQuickPickItem = { label: pickOption };
if (pickOption === info.default) {
item.description = nls.localize('inputVariable.defaultInputValue', "Default");
picks.unshift(item);
} else {
picks.push(item);
}
});
const pickOptions: IPickOptions<IQuickPickItem> = { placeHolder: info.description };
return this.quickInputService.pick(picks, pickOptions, undefined).then(resolvedInput => {
return resolvedInput ? resolvedInput.label : undefined;
});
}
case 'command': {
if (!Types.isString(info.command)) {
missingAttribute('command');
}
return this.commandService.executeCommand<string>(info.command, info.args).then(result => {
if (typeof result === 'string' || Types.isUndefinedOrNull(result)) {
return result;
}
throw new Error(nls.localize('inputVariable.command.noStringType', "Cannot substitute input variable '{0}' because command '{1}' did not return a result of type string.", variable, info.command));
});
}
default:
throw new Error(nls.localize('inputVariable.unknownType', "Input variable '{0}' can only be of type 'promptString', 'pickString', or 'command'.", variable));
}
}
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);