diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index c4737ed941..6acacfb9a6 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -20,7 +20,7 @@ "button.background": "#75715E", "editor.background": "#272822", "editor.foreground": "#f8f8f2", - "selection.background": "#ccccc7", + "selection.background": "#878b9180", "editor.selectionHighlightBackground": "#575b6180", "editor.selectionBackground": "#878b9180", "minimap.selectionHighlight": "#878b9180", diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.css b/src/vs/platform/actions/browser/menuEntryActionViewItem.css index 71b10ea8c7..d3458647f1 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.css +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.css @@ -8,6 +8,7 @@ height: 16px; background-repeat: no-repeat; background-position: 50%; + background-size: 16px; } .monaco-action-bar .action-item.menu-entry .action-label { diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index 25e5c85fa4..504f8b3b13 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -83,12 +83,6 @@ display: flex; align-items: center; overflow: hidden; - min-width: 16px; /* for flex */ - height: 100%; - margin: 0; - background-repeat: no-repeat; - background-position: center; - background-size: contain; } .scm-view .scm-provider > .actions > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item > .action-label > .codicon { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 307bc77b83..9d2bfaaba9 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -98,7 +98,7 @@ export namespace ConfigureTaskAction { export const TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task"); } -type TaskQuickPickEntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; }); +type TaskQuickPickEntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; }) | (IQuickPickItem & { settingType: string; }); class ProblemReporter implements TaskConfig.IProblemReporter { @@ -2360,7 +2360,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } private async showTwoLevelQuickPick(placeHolder: string, defaultEntry?: TaskQuickPickEntry) { - return TaskQuickPick.show(this, this.configurationService, this.quickInputService, this.notificationService, placeHolder, defaultEntry); + return TaskQuickPick.show(this, this.configurationService, this.quickInputService, this.notificationService, this.dialogService, placeHolder, defaultEntry); } private async showQuickPick(tasks: Promise | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise { @@ -2956,6 +2956,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return candidate && !!candidate.task; } + private isSettingEntry(value: IQuickPickItem): value is IQuickPickItem & { settingType: string } { + let candidate: IQuickPickItem & { settingType: string } = value as any; + return candidate && !!candidate.settingType; + } + private configureTask(task: Task) { if (ContributedTask.is(task)) { this.customize(task, undefined, true); @@ -2972,6 +2977,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } if (this.isTaskEntry(selection)) { this.configureTask(selection.task); + } else if (this.isSettingEntry(selection)) { + const taskQuickPick = new TaskQuickPick(this, this.configurationService, this.quickInputService, this.notificationService, this.dialogService); + taskQuickPick.handleSettingOption(selection.settingType); } else if (selection.folder && (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { this.openTaskFile(selection.folder.toResource('.vscode/tasks.json'), TaskSourceKind.Workspace); } else { @@ -3066,7 +3074,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - this.quickInputService.pick(entries, + const entriesWithSettings = entries.then(resolvedEntries => { + resolvedEntries.push(...TaskQuickPick.allSettingEntries(this.configurationService)); + return resolvedEntries; + }); + + this.quickInputService.pick(entriesWithSettings, { placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure') }, cancellationToken). then(async (selection) => { if (cancellationToken.isCancellationRequested) { diff --git a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts index 69a7cdb190..b90d77a639 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts @@ -14,10 +14,11 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { Disposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { Codicon } from 'vs/base/common/codicons'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; export const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail'; export const QUICKOPEN_SKIP_CONFIG = 'task.quickOpen.skip'; @@ -29,8 +30,10 @@ export function isWorkspaceFolder(folder: IWorkspace | IWorkspaceFolder): folder export interface TaskQuickPickEntry extends IQuickPickItem { task: Task | undefined | null; } + export interface TaskTwoLevelQuickPickEntry extends IQuickPickItem { task: Task | ConfiguringTask | string | undefined | null; + settingType?: string; } const SHOW_ALL: string = nls.localize('taskQuickPick.showAll', "Show All Tasks..."); @@ -45,7 +48,8 @@ export class TaskQuickPick extends Disposable { private taskService: ITaskService, private configurationService: IConfigurationService, private quickInputService: IQuickInputService, - private notificationService: INotificationService) { + private notificationService: INotificationService, + private dialogService: IDialogService) { super(); this.sorter = this.taskService.createSorter(); } @@ -173,6 +177,21 @@ export class TaskQuickPick extends Disposable { return { entries: this.topLevelEntries, isSingleConfigured: configuredTasks.length === 1 ? configuredTasks[0] : undefined }; } + public async handleSettingOption(selectedType: string) { + const noButton = nls.localize('TaskQuickPick.changeSettingNo', "No"); + const yesButton = nls.localize('TaskQuickPick.changeSettingYes', "Yes"); + const changeSettingResult = await this.dialogService.show(Severity.Warning, + nls.localize('TaskQuickPick.changeSettingDetails', + "Task detection for {0} tasks causes files in any workspace you open to be run as code. Enabling {0} task detection is a user setting and will apply to any workspace you open. Do you want to enable {0} task detection for all workspaces?", selectedType), + [noButton, yesButton]); + if (changeSettingResult.choice === 1) { + await this.configurationService.updateValue(`${selectedType}.autoDetect`, 'on'); + await new Promise(resolve => setTimeout(() => resolve(), 100)); + return this.show(nls.localize('TaskService.pickRunTask', 'Select the task to run'), undefined, selectedType); + } + return undefined; + } + public async show(placeHolder: string, defaultEntry?: TaskQuickPickEntry, startAtType?: string): Promise { const picker: IQuickPick = this.quickInputService.createQuickPick(); picker.placeholder = placeHolder; @@ -218,9 +237,12 @@ export class TaskQuickPick extends Disposable { if (Types.isString(firstLevelTask)) { // Proceed to second level of quick pick const selectedEntry = await this.doPickerSecondLevel(picker, firstLevelTask); - if (selectedEntry && selectedEntry.task === null) { + if (selectedEntry && !selectedEntry.settingType && selectedEntry.task === null) { // The user has chosen to go back to the first level firstLevelTask = await this.doPickerFirstLevel(picker, (await this.getTopLevelEntries(defaultEntry)).entries); + } else if (selectedEntry && Types.isString(selectedEntry.settingType)) { + picker.dispose(); + return this.handleSettingOption(selectedEntry.settingType); } else { picker.dispose(); return (selectedEntry?.task && !Types.isString(selectedEntry?.task)) ? this.toTask(selectedEntry?.task) : undefined; @@ -249,7 +271,9 @@ export class TaskQuickPick extends Disposable { private async doPickerSecondLevel(picker: IQuickPick, type: string) { picker.busy = true; if (type === SHOW_ALL) { - picker.items = (await this.taskService.tasks()).sort((a, b) => this.sorter.compare(a, b)).map(task => this.createTaskEntry(task)); + const items = (await this.taskService.tasks()).sort((a, b) => this.sorter.compare(a, b)).map(task => this.createTaskEntry(task)); + items.push(...TaskQuickPick.allSettingEntries(this.configurationService)); + picker.items = items; } else { picker.value = ''; picker.items = await this.getEntriesForProvider(type); @@ -264,6 +288,36 @@ export class TaskQuickPick extends Disposable { return secondLevelPickerResult; } + public static allSettingEntries(configurationService: IConfigurationService): (TaskTwoLevelQuickPickEntry & { settingType: string })[] { + const entries: (TaskTwoLevelQuickPickEntry & { settingType: string })[] = []; + const gruntEntry = TaskQuickPick.getSettingEntry(configurationService, 'grunt'); + if (gruntEntry) { + entries.push(gruntEntry); + } + const gulpEntry = TaskQuickPick.getSettingEntry(configurationService, 'gulp'); + if (gulpEntry) { + entries.push(gulpEntry); + } + const jakeEntry = TaskQuickPick.getSettingEntry(configurationService, 'jake'); + if (jakeEntry) { + entries.push(jakeEntry); + } + return entries; + } + + public static getSettingEntry(configurationService: IConfigurationService, type: string): (TaskTwoLevelQuickPickEntry & { settingType: string }) | undefined { + if (configurationService.getValue(`${type}.autoDetect`) === 'off') { + return { + label: nls.localize('TaskQuickPick.changeSettingsOptions', "$(gear) {0} task detection is turned off. Enable {1} task detection...", + type[0].toUpperCase() + type.slice(1), type), + task: null, + settingType: type, + alwaysShow: true + }; + } + return undefined; + } + private async getEntriesForProvider(type: string): Promise[]> { const tasks = (await this.taskService.tasks({ type })).sort((a, b) => this.sorter.compare(a, b)); let taskQuickPickEntries: QuickPickInput[]; @@ -283,6 +337,11 @@ export class TaskQuickPick extends Disposable { alwaysShow: true }]; } + + const settingEntry = TaskQuickPick.getSettingEntry(this.configurationService, type); + if (settingEntry) { + taskQuickPickEntries.push(settingEntry); + } return taskQuickPickEntries; } @@ -299,8 +358,10 @@ export class TaskQuickPick extends Disposable { return resolvedTask; } - static async show(taskService: ITaskService, configurationService: IConfigurationService, quickInputService: IQuickInputService, notificationService: INotificationService, placeHolder: string, defaultEntry?: TaskQuickPickEntry) { - const taskQuickPick = new TaskQuickPick(taskService, configurationService, quickInputService, notificationService); + static async show(taskService: ITaskService, configurationService: IConfigurationService, + quickInputService: IQuickInputService, notificationService: INotificationService, + dialogService: IDialogService, placeHolder: string, defaultEntry?: TaskQuickPickEntry) { + const taskQuickPick = new TaskQuickPick(taskService, configurationService, quickInputService, notificationService, dialogService); return taskQuickPick.show(placeHolder, defaultEntry); } } diff --git a/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts b/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts index 61ac78ad85..fdf7729cbe 100644 --- a/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts +++ b/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts @@ -16,6 +16,7 @@ import { TaskQuickPick, TaskTwoLevelQuickPickEntry } from 'vs/workbench/contrib/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { isString } from 'vs/base/common/types'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; export class TasksQuickAccessProvider extends PickerQuickAccessProvider { @@ -28,7 +29,8 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider = []; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index fcedae4ecc..e38d4b2c64 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -109,6 +109,12 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro } } + // If either shell or shellArgs are specified, they will take priority for now until we + // allow users to migrate, see https://github.com/microsoft/vscode/issues/123171 + if (this.getSafeConfigValue('shell', options.os) || this.getSafeConfigValue('shellArgs', options.os, false)) { + return this._getFallbackDefaultProfile(options); + } + // Return the real default profile if it exists and is valid const defaultProfile = await this._getRealDefaultProfile(false, options.os); if (defaultProfile) { @@ -137,18 +143,18 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro private async _getFallbackDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise { let executable: string; - let args: string | string[] | undefined; const shellSetting = this.getSafeConfigValue('shell', options.os); if (this._isValidShell(shellSetting)) { executable = shellSetting; - const shellArgsSetting = this.getSafeConfigValue('shellArgs', options.os); - if (this._isValidShellArgs(shellArgsSetting, options.os)) { - args = shellArgsSetting; - } } else { executable = await this._context.getDefaultSystemShell(options.remoteAuthority, options.os); } + let args: string | string[] | undefined; + const shellArgsSetting = this.getSafeConfigValue('shellArgs', options.os); + if (this._isValidShellArgs(shellArgsSetting, options.os)) { + args = shellArgsSetting; + } if (args === undefined) { if (options.os === OperatingSystem.Macintosh && args === undefined) { // macOS should launch a login shell by default @@ -276,21 +282,21 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro } // TODO: Remove when workspace trust is enabled - getSafeConfigValue(key: string, os: OperatingSystem): unknown | undefined { - return this.getSafeConfigValueFullKey(`terminal.integrated.${key}.${this._getOsKey(os)}`); + getSafeConfigValue(key: string, os: OperatingSystem, useDefaultValue: boolean = true): unknown | undefined { + return this.getSafeConfigValueFullKey(`terminal.integrated.${key}.${this._getOsKey(os)}`, useDefaultValue); } - getSafeConfigValueFullKey(key: string): unknown | undefined { + getSafeConfigValueFullKey(key: string, useDefaultValue: boolean = true): unknown | undefined { const isWorkspaceConfigAllowed = this._configurationService.getValue('terminal.integrated.allowWorkspaceConfiguration'); if (isWorkspaceConfigAllowed) { return this._configurationService.getValue(key); } else { const config = this._configurationService.inspect(key); - const value = config.user?.value || config.default?.value; + const value = config.user?.value || (useDefaultValue ? config.default?.value : undefined); // Clone if needed to allow extensibility if (Array.isArray(value)) { return value.slice(); } - if (typeof value === 'object') { + if (value !== null && typeof value === 'object') { return { ...value }; } return value; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index 720a606b1e..db5974e2b8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -475,6 +475,9 @@ export class TerminalTabbedView extends Disposable { } public focusTabs(): void { + if (!this._shouldShowTabs()) { + return; + } this._terminalTabsFocusContextKey.set(true); const selected = this._tabsWidget.getSelection(); this._tabsWidget.domFocus(); diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index 397f670e74..7310d701eb 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -143,10 +143,10 @@ export class RemoteTerminalChannelClient { const lastActiveWorkspace = activeWorkspaceRootUri ? withNullAsUndefined(this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined; let allResolvedVariables: Map | undefined = undefined; try { - allResolvedVariables = await this._resolverService.resolveWithInteraction(lastActiveWorkspace, { + allResolvedVariables = (await this._resolverService.resolveAnyMap(lastActiveWorkspace, { shellLaunchConfig, configuration - }); + })).resolvedVariables; } catch (err) { this._logService.error(err); } diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 0f6786673a..51fad68ec2 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -47,6 +47,10 @@ const terminalProfileSchema: IJSONSchema = { } }; +const shellDeprecationMessageLinux = localize('terminal.integrated.shell.linux.deprecation', "This is deprecated, the new recommended way to configure your default shell is by creating a terminal profile in {0} and setting its profile name as the default in {1}. This will currently take priority over the new profiles settings but that will change in the future.", '`#terminal.integrated.profiles.linux#`', '`#terminal.integrated.defaultProfile.linux#`'); +const shellDeprecationMessageOsx = localize('terminal.integrated.shell.osx.deprecation', "This is deprecated, the new recommended way to configure your default shell is by creating a terminal profile in {0} and setting its profile name as the default in {1}. This will currently take priority over the new profiles settings but that will change in the future.", '`#terminal.integrated.profiles.osx#`', '`#terminal.integrated.defaultProfile.osx#`'); +const shellDeprecationMessageWindows = localize('terminal.integrated.shell.windows.deprecation', "This is deprecated, the new recommended way to configure your default shell is by creating a terminal profile in {0} and setting its profile name as the default in {1}. This will currently take priority over the new profiles settings but that will change in the future.", '`#terminal.integrated.profiles.windows#`', '`#terminal.integrated.defaultProfile.windows#`'); + export const terminalConfiguration: IConfigurationNode = { id: 'terminal', order: 100, @@ -93,7 +97,7 @@ export const terminalConfiguration: IConfigurationNode = { type: 'string' }, default: [], - markdownDeprecationMessage: 'This is deprecated, use `#terminal.integrated.defaultProfile.linux#` instead' + markdownDeprecationMessage: shellDeprecationMessageLinux }, 'terminal.integrated.shellArgs.osx': { restricted: true, @@ -106,7 +110,7 @@ export const terminalConfiguration: IConfigurationNode = { // is the reason terminals on macOS typically run login shells by default which set up // the environment. See http://unix.stackexchange.com/a/119675/115410 default: ['-l'], - markdownDeprecationMessage: 'This is deprecated, use `#terminal.integrated.defaultProfile.osx#` instead' + markdownDeprecationMessage: shellDeprecationMessageOsx }, 'terminal.integrated.shellArgs.windows': { restricted: true, @@ -125,7 +129,7 @@ export const terminalConfiguration: IConfigurationNode = { } ], default: [], - markdownDeprecationMessage: 'This is deprecated, use `#terminal.integrated.defaultProfile.windows#` instead' + markdownDeprecationMessage: shellDeprecationMessageWindows }, 'terminal.integrated.profiles.windows': { restricted: true, @@ -261,19 +265,19 @@ export const terminalConfiguration: IConfigurationNode = { } }, 'terminal.integrated.defaultProfile.linux': { - description: localize('terminal.integrated.defaultProfile.linux', 'The default profile used on Linux. When set to a valid profile name, this will override the values of `terminal.integrated.shell.osx` and `terminal.integrated.shellArgs.osx`.'), + markdownDescription: localize('terminal.integrated.defaultProfile.linux', "The default profile used on Linux. This setting will currently be ignored if either {0} or {1} are set.", '`#terminal.integrated.shell.linux#`', '`#terminal.integrated.shellArgs.linux#`'), type: ['string', 'null'], default: null, scope: ConfigurationScope.APPLICATION // Disallow setting the default in workspace settings }, 'terminal.integrated.defaultProfile.osx': { - description: localize('terminal.integrated.defaultProfile.osx', 'The default profile used on macOS. When set to a valid profile name, this will override the values of `terminal.integrated.shell.osx` and `terminal.integrated.shellArgs.osx`.'), + description: localize('terminal.integrated.defaultProfile.osx', "The default profile used on macOS. This setting will currently be ignored if either {0} or {1} are set.", '`#terminal.integrated.shell.osx#`', '`#terminal.integrated.shellArgs.osx#`'), type: ['string', 'null'], default: null, scope: ConfigurationScope.APPLICATION // Disallow setting the default in workspace settings }, 'terminal.integrated.defaultProfile.windows': { - description: localize('terminal.integrated.defaultProfile.windows', 'The default profile used on Windows. When set to a valid profile name, this will override the values of `terminal.integrated.shell.windows` and `terminal.integrated.shellArgs.windows`.'), + description: localize('terminal.integrated.defaultProfile.windows', "The default profile used on Windows. This setting will currently be ignored if either {0} or {1} are set.", '`#terminal.integrated.shell.windows#`', '`#terminal.integrated.shellArgs.windows#`'), type: ['string', 'null'], default: null, scope: ConfigurationScope.APPLICATION // Disallow setting the default in workspace settings @@ -682,21 +686,21 @@ function getTerminalShellConfigurationStub(linux: string, osx: string, windows: markdownDescription: linux, type: ['string', 'null'], default: null, - markdownDeprecationMessage: 'This is deprecated, use `#terminal.integrated.defaultProfile.linux#` instead' + markdownDeprecationMessage: shellDeprecationMessageLinux }, 'terminal.integrated.shell.osx': { restricted: true, markdownDescription: osx, type: ['string', 'null'], default: null, - markdownDeprecationMessage: 'This is deprecated, use `#terminal.integrated.defaultProfile.osx#` instead' + markdownDeprecationMessage: shellDeprecationMessageOsx }, 'terminal.integrated.shell.windows': { restricted: true, markdownDescription: windows, type: ['string', 'null'], default: null, - markdownDeprecationMessage: 'This is deprecated, use `#terminal.integrated.defaultProfile.windows#` instead' + markdownDeprecationMessage: shellDeprecationMessageOsx } } }; diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index be2eab5f03..4f12e9bd4b 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -26,6 +26,13 @@ export interface IConfigurationResolverService { */ resolveAnyAsync(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise; + /** + * Recursively resolves all variables in the given config. + * Returns a copy of it with substituted values and a map of variables and their resolution. + * Keys in the map will be of the format input:variableName or command:variableName. + */ + resolveAnyMap(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }>; + /** * Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values. * If a "variables" dictionary (with names -> command ids) is given, command variables are first mapped through it before being resolved. diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 47652ad6a1..51bab9107c 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -99,7 +99,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.resolveAnyBase(workspaceFolder, config, commandValueMapping); } - protected async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { + public async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { const resolvedVariables = new Map(); const newConfig = await this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); return { newConfig, resolvedVariables };