mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-28 09:35:38 -05:00
Merge VS Code 1.23.1 (#1520)
This commit is contained in:
@@ -16,6 +16,6 @@ export interface IConfigurationResolverService {
|
||||
resolve(root: IWorkspaceFolder, value: string): string;
|
||||
resolve(root: IWorkspaceFolder, value: string[]): string[];
|
||||
resolve(root: IWorkspaceFolder, value: IStringDictionary<string>): IStringDictionary<string>;
|
||||
resolveAny<T>(root: IWorkspaceFolder, value: T): T;
|
||||
resolveInteractiveVariables(configuration: any, interactiveVariablesMap: { [key: string]: string }): TPromise<any>;
|
||||
resolveAny<T>(root: IWorkspaceFolder, value: T, commandMapping?: IStringDictionary<string>): T;
|
||||
executeCommandVariables(value: any, variables: IStringDictionary<string>): TPromise<IStringDictionary<string>>;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import uri from 'vs/base/common/uri';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -14,159 +16,11 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { VariableResolver } from 'vs/workbench/services/configurationResolver/node/variableResolver';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { relative } from 'path';
|
||||
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
|
||||
class VariableResolver {
|
||||
static VARIABLE_REGEXP = /\$\{(.*?)\}/g;
|
||||
private envVariables: IProcessEnvironment;
|
||||
|
||||
constructor(
|
||||
envVariables: IProcessEnvironment,
|
||||
private configurationService: IConfigurationService,
|
||||
private editorService: IWorkbenchEditorService,
|
||||
private environmentService: IEnvironmentService,
|
||||
private workspaceContextService: IWorkspaceContextService
|
||||
) {
|
||||
if (isWindows) {
|
||||
this.envVariables = Object.create(null);
|
||||
Object.keys(envVariables).forEach(key => {
|
||||
this.envVariables[key.toLowerCase()] = envVariables[key];
|
||||
});
|
||||
} else {
|
||||
this.envVariables = envVariables;
|
||||
}
|
||||
}
|
||||
|
||||
resolve(context: IWorkspaceFolder, value: string): string {
|
||||
const filePath = this.getFilePath();
|
||||
return value.replace(VariableResolver.VARIABLE_REGEXP, (match: string, variable: string) => {
|
||||
const parts = variable.split(':');
|
||||
let sufix: string;
|
||||
if (parts && parts.length > 1) {
|
||||
variable = parts[0];
|
||||
sufix = parts[1];
|
||||
}
|
||||
|
||||
switch (variable) {
|
||||
case 'env': {
|
||||
if (sufix) {
|
||||
if (isWindows) {
|
||||
sufix = sufix.toLowerCase();
|
||||
}
|
||||
|
||||
const env = this.envVariables[sufix];
|
||||
if (types.isString(env)) {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'config': {
|
||||
if (sufix) {
|
||||
const config = this.configurationService.getValue<string>(sufix, context ? { resource: context.uri } : undefined);
|
||||
if (!types.isUndefinedOrNull(config) && !types.isObject(config)) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
if (sufix) {
|
||||
const folder = this.workspaceContextService.getWorkspace().folders.filter(f => f.name === sufix).pop();
|
||||
if (folder) {
|
||||
context = folder;
|
||||
}
|
||||
}
|
||||
|
||||
switch (variable) {
|
||||
case 'workspaceRoot':
|
||||
case 'workspaceFolder':
|
||||
return context ? normalizeDriveLetter(context.uri.fsPath) : match;
|
||||
case 'cwd':
|
||||
return context ? normalizeDriveLetter(context.uri.fsPath) : process.cwd();
|
||||
case 'workspaceRootFolderName':
|
||||
case 'workspaceFolderBasename':
|
||||
return context ? paths.basename(context.uri.fsPath) : match;
|
||||
case 'lineNumber':
|
||||
return this.getLineNumber() || match;
|
||||
case 'selectedText':
|
||||
return this.getSelectedText() || match;
|
||||
case 'file':
|
||||
return filePath || match;
|
||||
case 'relativeFile':
|
||||
return context ? paths.normalize(relative(context.uri.fsPath, filePath)) : filePath || match;
|
||||
case 'fileDirname':
|
||||
return filePath ? paths.dirname(filePath) : match;
|
||||
case 'fileExtname':
|
||||
return filePath ? paths.extname(filePath) : match;
|
||||
case 'fileBasename':
|
||||
return filePath ? paths.basename(filePath) : match;
|
||||
case 'fileBasenameNoExtension': {
|
||||
if (!filePath) {
|
||||
return match;
|
||||
}
|
||||
|
||||
const basename = paths.basename(filePath);
|
||||
return basename.slice(0, basename.length - paths.extname(basename).length);
|
||||
}
|
||||
case 'execPath':
|
||||
return this.environmentService.execPath;
|
||||
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getSelectedText(): string {
|
||||
const activeEditor = this.editorService.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const editorControl = (<ICodeEditor>activeEditor.getControl());
|
||||
if (editorControl) {
|
||||
const editorModel = editorControl.getModel();
|
||||
const editorSelection = editorControl.getSelection();
|
||||
if (editorModel && editorSelection) {
|
||||
return editorModel.getValueInRange(editorSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getFilePath(): string {
|
||||
let input = this.editorService.getActiveEditorInput();
|
||||
if (input instanceof DiffEditorInput) {
|
||||
input = input.modifiedInput;
|
||||
}
|
||||
|
||||
const fileResource = toResource(input, { filter: Schemas.file });
|
||||
if (!fileResource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return paths.normalize(fileResource.fsPath, true);
|
||||
}
|
||||
|
||||
private getLineNumber(): string {
|
||||
const activeEditor = this.editorService.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const editorControl = (<ICodeEditor>activeEditor.getControl());
|
||||
if (editorControl) {
|
||||
const lineNumber = editorControl.getSelection().positionLineNumber;
|
||||
return String(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigurationResolverService implements IConfigurationResolverService {
|
||||
_serviceBrand: any;
|
||||
@@ -180,78 +34,112 @@ export class ConfigurationResolverService implements IConfigurationResolverServi
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService
|
||||
) {
|
||||
this.resolver = new VariableResolver(envVariables, configurationService, editorService, environmentService, workspaceContextService);
|
||||
this.resolver = new VariableResolver({
|
||||
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 input = editorService.getActiveEditorInput();
|
||||
if (input instanceof DiffEditorInput) {
|
||||
input = input.modifiedInput;
|
||||
}
|
||||
const fileResource = toResource(input, { filter: Schemas.file });
|
||||
if (!fileResource) {
|
||||
return undefined;
|
||||
}
|
||||
return paths.normalize(fileResource.fsPath, true);
|
||||
},
|
||||
getSelectedText: (): string | undefined => {
|
||||
const activeEditor = editorService.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const editorControl = (<ICodeEditor>activeEditor.getControl());
|
||||
if (editorControl) {
|
||||
const editorModel = editorControl.getModel();
|
||||
const editorSelection = editorControl.getSelection();
|
||||
if (editorModel && editorSelection) {
|
||||
return editorModel.getValueInRange(editorSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getLineNumber: (): string => {
|
||||
const activeEditor = editorService.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const editorControl = (<ICodeEditor>activeEditor.getControl());
|
||||
if (editorControl) {
|
||||
const lineNumber = editorControl.getSelection().positionLineNumber;
|
||||
return String(lineNumber);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}, envVariables);
|
||||
}
|
||||
|
||||
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 {
|
||||
if (types.isString(value)) {
|
||||
return this.resolver.resolve(root, value);
|
||||
} else if (types.isArray(value)) {
|
||||
return value.map(s => this.resolver.resolve(root, s));
|
||||
} else if (types.isObject(value)) {
|
||||
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
|
||||
Object.keys(value).forEach(key => {
|
||||
result[key] = this.resolve(root, value[key]);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
return value;
|
||||
return this.resolver.resolveAny(root ? root.uri : undefined, value);
|
||||
}
|
||||
|
||||
public resolveAny(root: IWorkspaceFolder, value: any): any {
|
||||
if (types.isString(value)) {
|
||||
return this.resolver.resolve(root, value);
|
||||
} else if (types.isArray(value)) {
|
||||
return value.map(s => this.resolveAny(root, s));
|
||||
} else if (types.isObject(value)) {
|
||||
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
|
||||
Object.keys(value).forEach(key => {
|
||||
result[key] = this.resolveAny(root, value[key]);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
return value;
|
||||
public resolveAny(root: IWorkspaceFolder, value: any, commandValueMapping?: IStringDictionary<string>): any {
|
||||
return this.resolver.resolveAny(root ? root.uri : undefined, value, commandValueMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve all interactive variables in configuration #6569
|
||||
* Finds and executes all command variables (see #6569)
|
||||
*/
|
||||
public resolveInteractiveVariables(configuration: any, interactiveVariablesMap: { [key: string]: string }): TPromise<any> {
|
||||
public executeCommandVariables(configuration: any, variableToCommandMap: IStringDictionary<string>): TPromise<IStringDictionary<string>> {
|
||||
|
||||
if (!configuration) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
// We need a map from interactive variables to keys because we only want to trigger an command once per key -
|
||||
// even though it might occur multiple times in configuration #7026.
|
||||
const interactiveVariablesToSubstitutes: { [interactiveVariable: string]: { object: any, key: string }[] } = Object.create(null);
|
||||
const findInteractiveVariables = (object: any) => {
|
||||
// use an array to preserve order of first appearance
|
||||
const commands: string[] = [];
|
||||
|
||||
const cmd_var = /\${command:(.*?)}/g;
|
||||
|
||||
const findCommandVariables = (object: any) => {
|
||||
Object.keys(object).forEach(key => {
|
||||
if (object[key] && typeof object[key] === 'object') {
|
||||
findInteractiveVariables(object[key]);
|
||||
} else if (typeof object[key] === 'string') {
|
||||
const matches = /\${command:(.+)}/.exec(object[key]);
|
||||
if (matches && matches.length === 2) {
|
||||
const interactiveVariable = matches[1];
|
||||
if (!interactiveVariablesToSubstitutes[interactiveVariable]) {
|
||||
interactiveVariablesToSubstitutes[interactiveVariable] = [];
|
||||
const value = object[key];
|
||||
if (value && typeof value === 'object') {
|
||||
findCommandVariables(value);
|
||||
} else if (typeof value === 'string') {
|
||||
let matches;
|
||||
while ((matches = cmd_var.exec(value)) !== null) {
|
||||
if (matches.length === 2) {
|
||||
const command = matches[1];
|
||||
if (commands.indexOf(command) < 0) {
|
||||
commands.push(command);
|
||||
}
|
||||
}
|
||||
interactiveVariablesToSubstitutes[interactiveVariable].push({ object, key });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
findInteractiveVariables(configuration);
|
||||
let substitionCanceled = false;
|
||||
|
||||
const factory: { (): TPromise<any> }[] = Object.keys(interactiveVariablesToSubstitutes).map(interactiveVariable => {
|
||||
findCommandVariables(configuration);
|
||||
|
||||
let cancelled = false;
|
||||
const commandValueMapping: IStringDictionary<string> = Object.create(null);
|
||||
|
||||
const factory: { (): TPromise<any> }[] = commands.map(interactiveVariable => {
|
||||
return () => {
|
||||
let commandId: string = null;
|
||||
commandId = interactiveVariablesMap ? interactiveVariablesMap[interactiveVariable] : null;
|
||||
|
||||
let commandId = variableToCommandMap ? variableToCommandMap[interactiveVariable] : null;
|
||||
if (!commandId) {
|
||||
// Just launch any command if the interactive variable is not contributed by the adapter #12735
|
||||
commandId = interactiveVariable;
|
||||
@@ -259,18 +147,14 @@ export class ConfigurationResolverService implements IConfigurationResolverServi
|
||||
|
||||
return this.commandService.executeCommand<string>(commandId, configuration).then(result => {
|
||||
if (result) {
|
||||
interactiveVariablesToSubstitutes[interactiveVariable].forEach(substitute => {
|
||||
if (substitute.object[substitute.key].indexOf(`\${command:${interactiveVariable}}`) >= 0) {
|
||||
substitute.object[substitute.key] = substitute.object[substitute.key].replace(`\${command:${interactiveVariable}}`, result);
|
||||
}
|
||||
});
|
||||
commandValueMapping[interactiveVariable] = result;
|
||||
} else {
|
||||
substitionCanceled = true;
|
||||
cancelled = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return sequence(factory).then(() => substitionCanceled ? null : configuration);
|
||||
return sequence(factory).then(() => cancelled ? null : commandValueMapping);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { relative } from 'path';
|
||||
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { localize } from 'vs/nls';
|
||||
import uri from 'vs/base/common/uri';
|
||||
|
||||
export interface IVariableAccessor {
|
||||
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 VariableResolver {
|
||||
|
||||
static VARIABLE_REGEXP = /\$\{(.*?)\}/g;
|
||||
|
||||
private envVariables: IProcessEnvironment;
|
||||
|
||||
constructor(
|
||||
private accessor: IVariableAccessor,
|
||||
envVariables: IProcessEnvironment
|
||||
) {
|
||||
if (isWindows) {
|
||||
this.envVariables = Object.create(null);
|
||||
Object.keys(envVariables).forEach(key => {
|
||||
this.envVariables[key.toLowerCase()] = envVariables[key];
|
||||
});
|
||||
} else {
|
||||
this.envVariables = envVariables;
|
||||
}
|
||||
}
|
||||
|
||||
resolveAny(folderUri: uri, value: any, commandValueMapping?: IStringDictionary<string>): any {
|
||||
if (types.isString(value)) {
|
||||
return this.resolve(folderUri, value, commandValueMapping);
|
||||
} else if (types.isArray(value)) {
|
||||
return value.map(s => this.resolveAny(folderUri, s, commandValueMapping));
|
||||
} else if (types.isObject(value)) {
|
||||
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
|
||||
Object.keys(value).forEach(key => {
|
||||
result[key] = this.resolveAny(folderUri, value[key], commandValueMapping);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
resolve(folderUri: uri, value: string, commandValueMapping: IStringDictionary<string>): string {
|
||||
|
||||
const filePath = this.accessor.getFilePath();
|
||||
|
||||
return value.replace(VariableResolver.VARIABLE_REGEXP, (match: string, variable: string) => {
|
||||
|
||||
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 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.accessor.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 config;
|
||||
}
|
||||
throw new Error(localize('missingConfigName', "'{0}' can not be resolved because no settings name is given.", match));
|
||||
|
||||
case 'command':
|
||||
if (argument && commandValueMapping) {
|
||||
const v = commandValueMapping[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;
|
||||
|
||||
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.accessor.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.accessor.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 normalizeDriveLetter(folderUri.fsPath);
|
||||
|
||||
case 'cwd':
|
||||
return folderUri ? normalizeDriveLetter(folderUri.fsPath) : process.cwd();
|
||||
|
||||
case 'workspaceRootFolderName':
|
||||
case 'workspaceFolderBasename':
|
||||
return paths.basename(folderUri.fsPath);
|
||||
|
||||
case 'lineNumber':
|
||||
const lineNumber = this.accessor.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.accessor.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 filePath;
|
||||
|
||||
case 'relativeFile':
|
||||
if (folderUri) {
|
||||
return paths.normalize(relative(folderUri.fsPath, filePath));
|
||||
}
|
||||
return filePath;
|
||||
|
||||
case 'fileDirname':
|
||||
return paths.dirname(filePath);
|
||||
|
||||
case 'fileExtname':
|
||||
return paths.extname(filePath);
|
||||
|
||||
case 'fileBasename':
|
||||
return paths.basename(filePath);
|
||||
|
||||
case 'fileBasenameNoExtension':
|
||||
const basename = paths.basename(filePath);
|
||||
return basename.slice(0, basename.length - paths.extname(basename).length);
|
||||
|
||||
case 'execPath':
|
||||
const ep = this.accessor.getExecPath();
|
||||
if (ep) {
|
||||
return ep;
|
||||
}
|
||||
return match;
|
||||
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import assert = require('assert');
|
||||
import * as assert from 'assert';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import platform = require('vs/base/common/platform');
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -86,7 +86,7 @@ suite('Configuration Resolver Service', () => {
|
||||
if (platform.isWindows) {
|
||||
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 - ${env:Key1}');
|
||||
assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - ');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -196,18 +196,6 @@ suite('Configuration Resolver Service', () => {
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz');
|
||||
});
|
||||
|
||||
test('configuration should not evaluate Javascript', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
editor: {
|
||||
abc: 'foo'
|
||||
}
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService());
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor[\'abc\'.substr(0)]} xyz'), 'abc ${config:editor[\'abc\'.substr(0)]} xyz');
|
||||
});
|
||||
|
||||
test('uses original variable as fallback', () => {
|
||||
let configurationService: IConfigurationService;
|
||||
configurationService = new MockConfigurationService({
|
||||
@@ -215,10 +203,8 @@ suite('Configuration Resolver Service', () => {
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService());
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${invalidVariable} xyz'), 'abc ${invalidVariable} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${env:invalidVariable} xyz'), 'abc ${env:invalidVariable} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.abc.def} xyz'), 'abc ${config:editor.abc.def} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:panel.abc} xyz'), 'abc ${config:panel.abc} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${unknownVariable} xyz'), 'abc ${unknownVariable} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${env:unknownVariable} xyz'), 'abc xyz');
|
||||
});
|
||||
|
||||
test('configuration variables with invalid accessor', () => {
|
||||
@@ -230,9 +216,14 @@ suite('Configuration Resolver Service', () => {
|
||||
});
|
||||
|
||||
let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService());
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:} xyz'), 'abc ${config:} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor..fontFamily} xyz'), 'abc ${config:editor..fontFamily} xyz');
|
||||
assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.none.none2} xyz'), 'abc ${config:editor.none.none2} xyz');
|
||||
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${env} xyz'));
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${env:} xyz'));
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${config} xyz'));
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${config:} xyz'));
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${config:editor} xyz'));
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${config:editor..fontFamily} xyz'));
|
||||
assert.throws(() => service.resolve(workspace, 'abc ${config:editor.none.none2} xyz'));
|
||||
});
|
||||
|
||||
test('interactive variable simple', () => {
|
||||
@@ -249,8 +240,11 @@ suite('Configuration Resolver Service', () => {
|
||||
interactiveVariables['interactiveVariable1'] = 'command1';
|
||||
interactiveVariables['interactiveVariable2'] = 'command2';
|
||||
|
||||
configurationResolverService.resolveInteractiveVariables(configuration, interactiveVariables).then(resolved => {
|
||||
assert.deepEqual(resolved, {
|
||||
configurationResolverService.executeCommandVariables(configuration, interactiveVariables).then(mapping => {
|
||||
|
||||
const result = configurationResolverService.resolveAny(undefined, configuration, mapping);
|
||||
|
||||
assert.deepEqual(result, {
|
||||
'name': 'Attach to Process',
|
||||
'type': 'node',
|
||||
'request': 'attach',
|
||||
@@ -281,8 +275,11 @@ suite('Configuration Resolver Service', () => {
|
||||
interactiveVariables['interactiveVariable1'] = 'command1';
|
||||
interactiveVariables['interactiveVariable2'] = 'command2';
|
||||
|
||||
configurationResolverService.resolveInteractiveVariables(configuration, interactiveVariables).then(resolved => {
|
||||
assert.deepEqual(resolved, {
|
||||
configurationResolverService.executeCommandVariables(configuration, interactiveVariables).then(mapping => {
|
||||
|
||||
const result = configurationResolverService.resolveAny(undefined, configuration, mapping);
|
||||
|
||||
assert.deepEqual(result, {
|
||||
'name': 'Attach to Process',
|
||||
'type': 'node',
|
||||
'request': 'attach',
|
||||
|
||||
Reference in New Issue
Block a user