Merge pull request #184743 from microsoft/tyriar/183423

Remove deprecated shell/shellArgs/automationShell settings
This commit is contained in:
Daniel Imms
2023-06-14 12:33:39 -07:00
committed by GitHub
11 changed files with 29 additions and 451 deletions
@@ -17,26 +17,15 @@ import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
export const terminalTabFocusContextKey = new RawContextKey<boolean>('terminalTabFocusMode', false, true);
export const enum TerminalSettingPrefix {
Shell = 'terminal.integrated.shell.',
ShellArgs = 'terminal.integrated.shellArgs.',
DefaultProfile = 'terminal.integrated.defaultProfile.',
Profiles = 'terminal.integrated.profiles.'
}
export const enum TerminalSettingId {
ShellLinux = 'terminal.integrated.shell.linux',
ShellMacOs = 'terminal.integrated.shell.osx',
ShellWindows = 'terminal.integrated.shell.windows',
SendKeybindingsToShell = 'terminal.integrated.sendKeybindingsToShell',
AutomationShellLinux = 'terminal.integrated.automationShell.linux',
AutomationShellMacOs = 'terminal.integrated.automationShell.osx',
AutomationShellWindows = 'terminal.integrated.automationShell.windows',
AutomationProfileLinux = 'terminal.integrated.automationProfile.linux',
AutomationProfileMacOs = 'terminal.integrated.automationProfile.osx',
AutomationProfileWindows = 'terminal.integrated.automationProfile.windows',
ShellArgsLinux = 'terminal.integrated.shellArgs.linux',
ShellArgsMacOs = 'terminal.integrated.shellArgs.osx',
ShellArgsWindows = 'terminal.integrated.shellArgs.windows',
ProfilesWindows = 'terminal.integrated.profiles.windows',
ProfilesMacOs = 'terminal.integrated.profiles.osx',
ProfilesLinux = 'terminal.integrated.profiles.linux',
@@ -108,52 +108,15 @@ function createTerminalProfileMarkdownDescription(platform: Platform.Linux | Pla
);
}
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#`');
const automationShellDeprecationMessageLinux = localize('terminal.integrated.automationShell.linux.deprecation', "This is deprecated, the new recommended way to configure your automation shell is by creating a terminal automation profile with {0}. This will currently take priority over the new automation profile settings but that will change in the future.", '`#terminal.integrated.automationProfile.linux#`');
const automationShellDeprecationMessageOsx = localize('terminal.integrated.automationShell.osx.deprecation', "This is deprecated, the new recommended way to configure your automation shell is by creating a terminal automation profile with {0}. This will currently take priority over the new automation profile settings but that will change in the future.", '`#terminal.integrated.automationProfile.osx#`');
const automationShellDeprecationMessageWindows = localize('terminal.integrated.automationShell.windows.deprecation', "This is deprecated, the new recommended way to configure your automation shell is by creating a terminal automation profile with {0}. This will currently take priority over the new automation profile settings but that will change in the future.", '`#terminal.integrated.automationProfile.windows#`');
const terminalPlatformConfiguration: IConfigurationNode = {
id: 'terminal',
order: 100,
title: localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"),
type: 'object',
properties: {
[TerminalSettingId.AutomationShellLinux]: {
restricted: true,
markdownDescription: localize({
key: 'terminal.integrated.automationShell.linux',
comment: ['{0} and {1} are the `shell` and `shellArgs` settings keys']
}, "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.linux`', '`shellArgs`'),
type: ['string', 'null'],
default: null,
markdownDeprecationMessage: automationShellDeprecationMessageLinux
},
[TerminalSettingId.AutomationShellMacOs]: {
restricted: true,
markdownDescription: localize({
key: 'terminal.integrated.automationShell.osx',
comment: ['{0} and {1} are the `shell` and `shellArgs` settings keys']
}, "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.osx`', '`shellArgs`'),
type: ['string', 'null'],
default: null,
markdownDeprecationMessage: automationShellDeprecationMessageOsx
},
[TerminalSettingId.AutomationShellWindows]: {
restricted: true,
markdownDescription: localize({
key: 'terminal.integrated.automationShell.windows',
comment: ['{0} and {1} are the `shell` and `shellArgs` settings keys']
}, "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.windows`', '`shellArgs`'),
type: ['string', 'null'],
default: null,
markdownDeprecationMessage: automationShellDeprecationMessageWindows
},
[TerminalSettingId.AutomationProfileLinux]: {
restricted: true,
markdownDescription: localize('terminal.integrated.automationProfile.linux', "The terminal profile to use on Linux for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} (now deprecated) is set.", '`terminal.integrated.automationShell.linux`'),
markdownDescription: localize('terminal.integrated.automationProfile.linux', "The terminal profile to use on Linux for automation-related terminal usage like tasks and debug."),
type: ['object', 'null'],
default: null,
'anyOf': [
@@ -171,7 +134,7 @@ const terminalPlatformConfiguration: IConfigurationNode = {
},
[TerminalSettingId.AutomationProfileMacOs]: {
restricted: true,
markdownDescription: localize('terminal.integrated.automationProfile.osx', "The terminal profile to use on macOS for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} (now deprecated) is set.", '`terminal.integrated.automationShell.osx`'),
markdownDescription: localize('terminal.integrated.automationProfile.osx', "The terminal profile to use on macOS for automation-related terminal usage like tasks and debug."),
type: ['object', 'null'],
default: null,
'anyOf': [
@@ -205,69 +168,6 @@ const terminalPlatformConfiguration: IConfigurationNode = {
}
]
},
[TerminalSettingId.ShellLinux]: {
restricted: true,
markdownDescription: localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles)."),
type: ['string', 'null'],
default: null,
markdownDeprecationMessage: shellDeprecationMessageLinux
},
[TerminalSettingId.ShellMacOs]: {
restricted: true,
markdownDescription: localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles)."),
type: ['string', 'null'],
default: null,
markdownDeprecationMessage: shellDeprecationMessageOsx
},
[TerminalSettingId.ShellWindows]: {
restricted: true,
markdownDescription: localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles)."),
type: ['string', 'null'],
default: null,
markdownDeprecationMessage: shellDeprecationMessageWindows
},
[TerminalSettingId.ShellArgsLinux]: {
restricted: true,
markdownDescription: localize('terminal.integrated.shellArgs.linux', "The command line arguments to use when on the Linux terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles)."),
type: 'array',
items: {
type: 'string'
},
default: [],
markdownDeprecationMessage: shellDeprecationMessageLinux
},
[TerminalSettingId.ShellArgsMacOs]: {
restricted: true,
markdownDescription: localize('terminal.integrated.shellArgs.osx', "The command line arguments to use when on the macOS terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles)."),
type: 'array',
items: {
type: 'string'
},
// Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This
// 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: shellDeprecationMessageOsx
},
[TerminalSettingId.ShellArgsWindows]: {
restricted: true,
markdownDescription: localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles)."),
'anyOf': [
{
type: 'array',
items: {
type: 'string',
markdownDescription: localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles).")
},
},
{
type: 'string',
markdownDescription: localize('terminal.integrated.shellArgs.windows.string', "The command line arguments in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6) to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_terminal-profiles).")
}
],
default: [],
markdownDeprecationMessage: shellDeprecationMessageWindows
},
[TerminalSettingId.ProfilesWindows]: {
restricted: true,
markdownDescription: createTerminalProfileMarkdownDescription(Platform.Windows),
@@ -495,7 +395,7 @@ export function registerTerminalDefaultProfileConfiguration(detectedProfiles?: {
properties: {
[TerminalSettingId.DefaultProfileLinux]: {
restricted: true,
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`'),
markdownDescription: localize('terminal.integrated.defaultProfile.linux', "The default terminal profile on Linux."),
type: ['string', 'null'],
default: null,
enum: detectedProfiles?.os === OperatingSystem.Linux ? profileEnum?.values : undefined,
@@ -503,7 +403,7 @@ export function registerTerminalDefaultProfileConfiguration(detectedProfiles?: {
},
[TerminalSettingId.DefaultProfileMacOs]: {
restricted: true,
markdownDescription: 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`'),
markdownDescription: localize('terminal.integrated.defaultProfile.osx', "The default terminal profile on macOS."),
type: ['string', 'null'],
default: null,
enum: detectedProfiles?.os === OperatingSystem.Macintosh ? profileEnum?.values : undefined,
@@ -511,7 +411,7 @@ export function registerTerminalDefaultProfileConfiguration(detectedProfiles?: {
},
[TerminalSettingId.DefaultProfileWindows]: {
restricted: true,
markdownDescription: 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`'),
markdownDescription: localize('terminal.integrated.defaultProfile.windows', "The default terminal profile on Windows."),
type: ['string', 'null'],
default: null,
enum: detectedProfiles?.os === OperatingSystem.Windows ? profileEnum?.values : undefined,
@@ -14,15 +14,6 @@ export interface ISingleTerminalConfiguration<T> {
}
export interface ICompleteTerminalConfiguration {
'terminal.integrated.automationShell.windows': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.automationShell.osx': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.automationShell.linux': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shell.windows': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shell.osx': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shell.linux': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shellArgs.windows': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shellArgs.osx': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shellArgs.linux': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.env.windows': ISingleTerminalConfiguration<ITerminalEnvironment>;
'terminal.integrated.env.osx': ISingleTerminalConfiguration<ITerminalEnvironment>;
'terminal.integrated.env.linux': ISingleTerminalConfiguration<ITerminalEnvironment>;
@@ -1921,8 +1921,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this._modelService, this._configurationResolverService,
this._contextService, this._environmentService,
AbstractTaskService.OutputChannelId, this._fileService, this._terminalProfileResolverService,
this._pathService, this._viewDescriptorService, this._logService, this._configurationService, this._notificationService,
this, this._instantiationService,
this._pathService, this._viewDescriptorService, this._logService, this._notificationService,
this._instantiationService,
(workspaceFolder: IWorkspaceFolder | undefined) => {
if (workspaceFolder) {
return this._getTaskSystemInfo(workspaceFolder.uri.scheme);
@@ -28,10 +28,9 @@ import { ProblemMatcher, ProblemMatcherRegistry /*, ProblemPattern, getResource
import { Codicon } from 'vs/base/common/codicons';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IShellLaunchConfig, TerminalSettingId, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfig, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings';
import { ThemeIcon } from 'vs/base/common/themables';
import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
@@ -39,7 +38,6 @@ import { TaskTerminalStatus } from 'vs/workbench/contrib/tasks/browser/taskTermi
import { ProblemCollectorEventKind, ProblemHandlingStrategy, StartStopProblemCollector, WatchingProblemCollector } from 'vs/workbench/contrib/tasks/common/problemCollectors';
import { GroupKind } from 'vs/workbench/contrib/tasks/common/taskConfiguration';
import { CommandOptions, CommandString, ContributedTask, CustomTask, DependsOrder, ICommandConfiguration, IConfigurationProperties, IExtensionTaskSource, InMemoryTask, IPresentationOptions, IShellConfiguration, IShellQuotingOptions, ITaskEvent, PanelKind, RevealKind, RevealProblemKind, RuntimeType, ShellQuoting, Task, TaskEvent, TaskEventKind, TaskScope, TaskSourceKind } from 'vs/workbench/contrib/tasks/common/tasks';
import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService';
import { IResolvedVariables, IResolveSet, ITaskExecuteResult, ITaskResolver, ITaskSummary, ITaskSystem, ITaskSystemInfo, ITaskSystemInfoResolver, ITaskTerminateResponse, TaskError, TaskErrors, TaskExecuteKind, Triggers } from 'vs/workbench/contrib/tasks/common/taskSystem';
import { ITerminalGroupService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { VSCodeOscProperty, VSCodeOscPt, VSCodeSequence } from 'vs/workbench/contrib/terminal/browser/terminalEscapeSequences';
@@ -232,9 +230,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem {
private _pathService: IPathService,
private _viewDescriptorService: IViewDescriptorService,
private _logService: ILogService,
private _configurationService: IConfigurationService,
private _notificationService: INotificationService,
taskService: ITaskService,
instantiationService: IInstantiationService,
taskSystemInfoResolver: ITaskSystemInfoResolver,
) {
@@ -1157,17 +1153,18 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem {
// Under Mac remove -l to not start it as a login shell.
if (platform === Platform.Platform.Mac) {
// Background on -l on osx https://github.com/microsoft/vscode/issues/107563
const osxShellArgs = this._configurationService.inspect(TerminalSettingId.ShellArgsMacOs);
if ((osxShellArgs.user === undefined) && (osxShellArgs.userLocal === undefined) && (osxShellArgs.userLocalValue === undefined)
&& (osxShellArgs.userRemote === undefined) && (osxShellArgs.userRemoteValue === undefined)
&& (osxShellArgs.userValue === undefined) && (osxShellArgs.workspace === undefined)
&& (osxShellArgs.workspaceFolder === undefined) && (osxShellArgs.workspaceFolderValue === undefined)
&& (osxShellArgs.workspaceValue === undefined)) {
const index = shellArgs.indexOf('-l');
if (index !== -1) {
shellArgs.splice(index, 1);
}
}
// TODO: Handle by pulling the default terminal profile?
// const osxShellArgs = this._configurationService.inspect(TerminalSettingId.ShellArgsMacOs);
// if ((osxShellArgs.user === undefined) && (osxShellArgs.userLocal === undefined) && (osxShellArgs.userLocalValue === undefined)
// && (osxShellArgs.userRemote === undefined) && (osxShellArgs.userRemoteValue === undefined)
// && (osxShellArgs.userValue === undefined) && (osxShellArgs.workspace === undefined)
// && (osxShellArgs.workspaceFolder === undefined) && (osxShellArgs.workspaceFolderValue === undefined)
// && (osxShellArgs.workspaceValue === undefined)) {
// const index = shellArgs.indexOf('-l');
// if (index !== -1) {
// shellArgs.splice(index, 1);
// }
// }
}
toAdd.push('-c');
}
@@ -185,15 +185,6 @@ class RemoteTerminalBackend extends BaseTerminalBackend implements ITerminalBack
const terminalConfig = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
const configuration: ICompleteTerminalConfiguration = {
'terminal.integrated.automationShell.windows': this._configurationService.getValue(TerminalSettingId.AutomationShellWindows) as string,
'terminal.integrated.automationShell.osx': this._configurationService.getValue(TerminalSettingId.AutomationShellMacOs) as string,
'terminal.integrated.automationShell.linux': this._configurationService.getValue(TerminalSettingId.AutomationShellLinux) as string,
'terminal.integrated.shell.windows': this._configurationService.getValue(TerminalSettingId.ShellWindows) as string,
'terminal.integrated.shell.osx': this._configurationService.getValue(TerminalSettingId.ShellMacOs) as string,
'terminal.integrated.shell.linux': this._configurationService.getValue(TerminalSettingId.ShellLinux) as string,
'terminal.integrated.shellArgs.windows': this._configurationService.getValue(TerminalSettingId.ShellArgsWindows) as string | string[],
'terminal.integrated.shellArgs.osx': this._configurationService.getValue(TerminalSettingId.ShellArgsMacOs) as string | string[],
'terminal.integrated.shellArgs.linux': this._configurationService.getValue(TerminalSettingId.ShellArgsLinux) as string | string[],
'terminal.integrated.env.windows': this._configurationService.getValue(TerminalSettingId.EnvWindows) as ITerminalEnvironment,
'terminal.integrated.env.osx': this._configurationService.getValue(TerminalSettingId.EnvMacOs) as ITerminalEnvironment,
'terminal.integrated.env.linux': this._configurationService.getValue(TerminalSettingId.EnvLinux) as ITerminalEnvironment,
@@ -12,7 +12,7 @@ import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspac
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IProcessEnvironment, OperatingSystem, OS } from 'vs/base/common/platform';
import { IShellLaunchConfig, ITerminalProfile, ITerminalProfileObject, TerminalIcon, TerminalSettingId, TerminalSettingPrefix } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfig, ITerminalProfile, TerminalIcon, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfigResolveOptions, ITerminalProfileResolverService, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal';
import * as path from 'vs/base/common/path';
import { Codicon } from 'vs/base/common/codicons';
@@ -22,10 +22,6 @@ import { debounce } from 'vs/base/common/decorators';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI } from 'vs/base/common/uri';
import { equals } from 'vs/base/common/arrays';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import Severity from 'vs/base/common/severity';
import { INotificationService, IPromptChoice, NeverShowAgainScope } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
import { deepClone } from 'vs/base/common/objects';
import { terminalProfileArgsMatch, isUriComponents } from 'vs/platform/terminal/common/terminalProfiles';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
@@ -37,12 +33,6 @@ export interface IProfileContextProvider {
const generatedProfileName = 'Generated';
const enum StorageKeys {
ShouldPromptForProfileMigration = 'terminals.integrated.profile-migration'
}
let migrationMessageShown = false;
/*
* Resolves terminal shell launch config and terminal profiles for the given operating system,
* environment, and user configuration.
@@ -65,9 +55,7 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro
private readonly _logService: ILogService,
private readonly _terminalProfileService: ITerminalProfileService,
private readonly _workspaceContextService: IWorkspaceContextService,
private readonly _remoteAgentService: IRemoteAgentService,
private readonly _storageService: IStorageService,
private readonly _notificationService: INotificationService
private readonly _remoteAgentService: IRemoteAgentService
) {
if (this._remoteAgentService.getConnection()) {
this._remoteAgentService.getEnvironment().then(env => this._primaryBackendOs = env?.os || OS);
@@ -82,7 +70,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro
}
});
this._terminalProfileService.onDidChangeAvailableProfiles(() => this._refreshDefaultProfileName());
this.showProfileMigrationNotification();
}
@debounce(200)
@@ -213,13 +200,6 @@ 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
const shellSettingProfile = await this._getUnresolvedShellSettingDefaultProfile(options);
if (shellSettingProfile) {
return this._setIconForAutomation(options, shellSettingProfile);
}
// Return the real default profile if it exists and is valid, wait for profiles to be ready
// if the window just opened
await this._terminalProfileService.profilesReady;
@@ -246,46 +226,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro
return this._terminalProfileService.getDefaultProfile(os);
}
private async _getUnresolvedShellSettingDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile | undefined> {
let executable = this._configurationService.getValue<string>(`${TerminalSettingPrefix.Shell}${this._getOsKey(options.os)}`);
if (!this._isValidShell(executable)) {
const shellArgs = this._configurationService.inspect(`${TerminalSettingPrefix.ShellArgs}${this._getOsKey(options.os)}`);
// && !this.getSafeConfigValue('shellArgs', options.os, false)) {
if (!shellArgs.userValue && !shellArgs.workspaceValue) {
return undefined;
}
}
if (!executable || !this._isValidShell(executable)) {
executable = await this._context.getDefaultSystemShell(options.remoteAuthority, options.os);
}
let args: string | string[] | undefined;
const shellArgsSetting = this._configurationService.getValue(`${TerminalSettingPrefix.ShellArgs}${this._getOsKey(options.os)}`);
if (this._isValidShellArgs(shellArgsSetting, options.os)) {
args = shellArgsSetting;
}
if (args === undefined) {
if (options.os === OperatingSystem.Macintosh && args === undefined && path.parse(executable).name.match(/(zsh|bash|fish)/)) {
// macOS should launch a login shell by default
args = ['--login'];
} else {
// Resolve undefined to []
args = [];
}
}
const icon = this._guessProfileIcon(executable);
return {
profileName: generatedProfileName,
path: executable,
args,
icon,
isDefault: false
};
}
private async _getUnresolvedFallbackDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> {
const executable = await this._context.getDefaultSystemShell(options.remoteAuthority, options.os);
@@ -325,17 +265,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro
}
private _getUnresolvedAutomationShellProfile(options: IShellLaunchConfigResolveOptions): ITerminalProfile | undefined {
const automationShell = this._configurationService.getValue(`terminal.integrated.automationShell.${this._getOsKey(options.os)}`);
if (automationShell && typeof automationShell === 'string') {
return {
path: automationShell,
profileName: generatedProfileName,
isDefault: false,
icon: Codicon.tools
};
}
// Use automationProfile second
const automationProfile = this._configurationService.getValue(`terminal.integrated.automationProfile.${this._getOsKey(options.os)}`);
if (this._isValidAutomationProfile(automationProfile, options.os)) {
automationProfile.icon = this._getCustomIcon(automationProfile.icon) || Codicon.tools;
@@ -418,13 +347,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro
}
}
private _isValidShell(shell: unknown): shell is string {
if (!shell) {
return false;
}
return typeof shell === 'string';
}
private _isValidShellArgs(shellArgs: unknown, os: OperatingSystem): shellArgs is string | string[] | undefined {
if (shellArgs === undefined) {
return true;
@@ -476,48 +398,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro
}
return false;
}
async showProfileMigrationNotification(): Promise<void> {
const shouldMigrateToProfile = (!!this._configurationService.getValue(TerminalSettingPrefix.Shell + this._primaryBackendOs) ||
!!this._configurationService.inspect(TerminalSettingPrefix.ShellArgs + this._primaryBackendOs).userValue) &&
!!this._configurationService.getValue(TerminalSettingPrefix.DefaultProfile + this._primaryBackendOs);
if (shouldMigrateToProfile && this._storageService.getBoolean(StorageKeys.ShouldPromptForProfileMigration, StorageScope.WORKSPACE, true) && !migrationMessageShown) {
this._notificationService.prompt(
Severity.Info,
localize('terminalProfileMigration', "The terminal is using deprecated shell/shellArgs settings, do you want to migrate it to a profile?"),
[
{
label: localize('migrateToProfile', "Migrate"),
run: async () => {
const shell = this._configurationService.getValue(TerminalSettingPrefix.Shell + this._primaryBackendOs);
const shellArgs = this._configurationService.getValue(TerminalSettingPrefix.ShellArgs + this._primaryBackendOs);
const profile = await this.createProfileFromShellAndShellArgs(shell, shellArgs);
if (typeof profile === 'string') {
await this._configurationService.updateValue(TerminalSettingPrefix.DefaultProfile + this._primaryBackendOs, profile);
this._logService.trace(`migrated from shell/shellArgs, using existing profile ${profile}`);
} else {
const profiles = { ...this._configurationService.inspect<Readonly<{ [key: string]: ITerminalProfileObject }>>(TerminalSettingPrefix.Profiles + this._primaryBackendOs).userValue };
const profileConfig: ITerminalProfileObject = { path: profile.path };
if (profile.args) {
profileConfig.args = profile.args;
}
profiles[profile.profileName] = profileConfig;
await this._configurationService.updateValue(TerminalSettingPrefix.Profiles + this._primaryBackendOs, profiles);
await this._configurationService.updateValue(TerminalSettingPrefix.DefaultProfile + this._primaryBackendOs, profile.profileName);
this._logService.trace(`migrated from shell/shellArgs, ${shell} ${shellArgs} to profile ${JSON.stringify(profile)}`);
}
await this._configurationService.updateValue(TerminalSettingPrefix.Shell + this._primaryBackendOs, undefined);
await this._configurationService.updateValue(TerminalSettingPrefix.ShellArgs + this._primaryBackendOs, undefined);
}
} as IPromptChoice,
],
{
neverShowAgain: { id: StorageKeys.ShouldPromptForProfileMigration, scope: NeverShowAgainScope.WORKSPACE }
}
);
migrationMessageShown = true;
}
}
}
export class BrowserTerminalProfileResolverService extends BaseTerminalProfileResolverService {
@@ -530,9 +410,7 @@ export class BrowserTerminalProfileResolverService extends BaseTerminalProfileRe
@ITerminalInstanceService terminalInstanceService: ITerminalInstanceService,
@ITerminalProfileService terminalProfileService: ITerminalProfileService,
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@IStorageService storageService: IStorageService,
@INotificationService notificationService: INotificationService
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
super(
{
@@ -558,9 +436,7 @@ export class BrowserTerminalProfileResolverService extends BaseTerminalProfileRe
logService,
terminalProfileService,
workspaceContextService,
remoteAgentService,
storageService,
notificationService
remoteAgentService
);
}
}
@@ -197,15 +197,6 @@ export type ConfirmOnKill = 'never' | 'always' | 'editor' | 'panel';
export type ConfirmOnExit = 'never' | 'always' | 'hasChildProcesses';
export interface ICompleteTerminalConfiguration {
'terminal.integrated.automationShell.windows': string;
'terminal.integrated.automationShell.osx': string;
'terminal.integrated.automationShell.linux': string;
'terminal.integrated.shell.windows': string;
'terminal.integrated.shell.osx': string;
'terminal.integrated.shell.linux': string;
'terminal.integrated.shellArgs.windows': string | string[];
'terminal.integrated.shellArgs.osx': string | string[];
'terminal.integrated.shellArgs.linux': string | string[];
'terminal.integrated.env.windows': ITerminalEnvironment;
'terminal.integrated.env.osx': ITerminalEnvironment;
'terminal.integrated.env.linux': ITerminalEnvironment;
@@ -13,8 +13,8 @@ import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspac
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { sanitizeProcessEnvironment } from 'vs/base/common/processes';
import { ILogService } from 'vs/platform/log/common/log';
import { IShellLaunchConfig, ITerminalEnvironment, TerminalSettingId, TerminalSettingPrefix, TerminalShellType, WindowsShellType } from 'vs/platform/terminal/common/terminal';
import { IProcessEnvironment, isWindows, language, OperatingSystem, platform, Platform } from 'vs/base/common/platform';
import { IShellLaunchConfig, ITerminalEnvironment, TerminalShellType, WindowsShellType } from 'vs/platform/terminal/common/terminal';
import { IProcessEnvironment, isWindows, language, OperatingSystem } from 'vs/base/common/platform';
import { escapeNonWindowsPath, sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment';
import { isString, withNullAsUndefined } from 'vs/base/common/types';
import { ITerminalBackend } from 'vs/workbench/contrib/terminal/common/terminal';
@@ -232,21 +232,6 @@ async function _resolveCwd(cwd: string, variableResolver: VariableResolver | und
return cwd;
}
export type TerminalShellSetting = (
TerminalSettingId.AutomationShellWindows
| TerminalSettingId.AutomationShellMacOs
| TerminalSettingId.AutomationShellLinux
| TerminalSettingId.ShellWindows
| TerminalSettingId.ShellMacOs
| TerminalSettingId.ShellLinux
);
export type TerminalShellArgsSetting = (
TerminalSettingId.ShellArgsWindows
| TerminalSettingId.ShellArgsMacOs
| TerminalSettingId.ShellArgsLinux
);
export type VariableResolver = (str: string) => Promise<string>;
export function createVariableResolver(lastActiveWorkspace: IWorkspaceFolder | undefined, env: IProcessEnvironment, configurationResolverService: IConfigurationResolverService | undefined): VariableResolver | undefined {
@@ -256,103 +241,6 @@ export function createVariableResolver(lastActiveWorkspace: IWorkspaceFolder | u
return (str) => configurationResolverService.resolveWithEnvironment(env, lastActiveWorkspace, str);
}
/**
* @deprecated Use ITerminalProfileResolverService
*/
export async function getDefaultShell(
fetchSetting: (key: TerminalShellSetting) => string | undefined,
defaultShell: string,
isWoW64: boolean,
windir: string | undefined,
variableResolver: VariableResolver | undefined,
logService: ILogService,
useAutomationShell: boolean,
platformOverride: Platform = platform
): Promise<string> {
let maybeExecutable: string | undefined;
if (useAutomationShell) {
// If automationShell is specified, this should override the normal setting
maybeExecutable = getShellSetting(fetchSetting, 'automationShell', platformOverride) as string | undefined;
}
if (!maybeExecutable) {
maybeExecutable = getShellSetting(fetchSetting, 'shell', platformOverride) as string | undefined;
}
let executable: string = maybeExecutable || defaultShell;
// Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's
// safe to assume that this was used by accident as Sysnative does not
// exist and will break the terminal in non-WoW64 environments.
if ((platformOverride === Platform.Windows) && !isWoW64 && windir) {
const sysnativePath = path.join(windir, 'Sysnative').replace(/\//g, '\\').toLowerCase();
if (executable && executable.toLowerCase().indexOf(sysnativePath) === 0) {
executable = path.join(windir, 'System32', executable.substr(sysnativePath.length + 1));
}
}
// Convert / to \ on Windows for convenience
if (executable && platformOverride === Platform.Windows) {
executable = executable.replace(/\//g, '\\');
}
if (variableResolver) {
try {
executable = await variableResolver(executable);
} catch (e) {
logService.error(`Could not resolve shell`, e);
}
}
return executable;
}
/**
* @deprecated Use ITerminalProfileResolverService
*/
export async function getDefaultShellArgs(
fetchSetting: (key: TerminalShellSetting | TerminalShellArgsSetting) => string | string[] | undefined,
useAutomationShell: boolean,
variableResolver: VariableResolver | undefined,
logService: ILogService,
platformOverride: Platform = platform,
): Promise<string | string[]> {
if (useAutomationShell) {
if (!!getShellSetting(fetchSetting, 'automationShell', platformOverride)) {
return [];
}
}
const platformKey = platformOverride === Platform.Windows ? 'windows' : platformOverride === Platform.Mac ? 'osx' : 'linux';
let args = fetchSetting(<TerminalShellArgsSetting>`${TerminalSettingPrefix.ShellArgs}${platformKey}`);
if (!args) {
return [];
}
if (typeof args === 'string' && platformOverride === Platform.Windows) {
return variableResolver ? await variableResolver(args) : args;
}
if (variableResolver) {
const resolvedArgs: string[] = [];
for (const arg of args) {
try {
resolvedArgs.push(await variableResolver(arg));
} catch (e) {
logService.error(`Could not resolve ${TerminalSettingPrefix.ShellArgs}${platformKey}`, e);
resolvedArgs.push(arg);
}
}
args = resolvedArgs;
}
return args;
}
function getShellSetting(
fetchSetting: (key: TerminalShellSetting) => string | string[] | undefined,
type: 'automationShell' | 'shell',
platformOverride: Platform = platform,
): string | string[] | undefined {
const platformKey = platformOverride === Platform.Windows ? 'windows' : platformOverride === Platform.Mac ? 'osx' : 'linux';
return fetchSetting(<TerminalShellSetting>`terminal.integrated.${type}.${platformKey}`);
}
export async function createTerminalEnvironment(
shellLaunchConfig: IShellLaunchConfig,
envFromConfig: ITerminalEnvironment | undefined,
@@ -6,8 +6,6 @@
import { ErrorNoTelemetry } from 'vs/base/common/errors';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { BaseTerminalProfileResolverService } from 'vs/workbench/contrib/terminal/browser/terminalProfileResolverService';
@@ -26,8 +24,6 @@ export class ElectronTerminalProfileResolverService extends BaseTerminalProfileR
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
@ITerminalProfileService terminalProfileService: ITerminalProfileService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@IStorageService storageService: IStorageService,
@INotificationService notificationService: INotificationService,
@ITerminalInstanceService terminalInstanceService: ITerminalInstanceService
) {
super(
@@ -53,9 +49,7 @@ export class ElectronTerminalProfileResolverService extends BaseTerminalProfileR
logService,
terminalProfileService,
workspaceContextService,
remoteAgentService,
storageService,
notificationService
remoteAgentService
);
}
}
@@ -5,9 +5,9 @@
import { deepStrictEqual, strictEqual } from 'assert';
import { IStringDictionary } from 'vs/base/common/collections';
import { isWindows, OperatingSystem, Platform } from 'vs/base/common/platform';
import { isWindows, OperatingSystem } from 'vs/base/common/platform';
import { URI as Uri } from 'vs/base/common/uri';
import { addTerminalEnvironmentKeys, createTerminalEnvironment, getCwd, getDefaultShell, getLangEnvVariable, mergeEnvironments, preparePathForShell, shouldSetLangEnvVariable } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { addTerminalEnvironmentKeys, createTerminalEnvironment, getCwd, getLangEnvVariable, mergeEnvironments, preparePathForShell, shouldSetLangEnvVariable } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { PosixShellType, WindowsShellType } from 'vs/platform/terminal/common/terminal';
suite('Workbench - TerminalEnvironment', () => {
@@ -210,45 +210,6 @@ suite('Workbench - TerminalEnvironment', () => {
});
});
suite('getDefaultShell', () => {
test('should change Sysnative to System32 in non-WoW64 systems', async () => {
const shell = await getDefaultShell(key => {
return ({ 'terminal.integrated.shell.windows': 'C:\\Windows\\Sysnative\\cmd.exe' } as any)[key];
}, 'DEFAULT', false, 'C:\\Windows', undefined, {} as any, false, Platform.Windows);
strictEqual(shell, 'C:\\Windows\\System32\\cmd.exe');
});
test('should not change Sysnative to System32 in WoW64 systems', async () => {
const shell = await getDefaultShell(key => {
return ({ 'terminal.integrated.shell.windows': 'C:\\Windows\\Sysnative\\cmd.exe' } as any)[key];
}, 'DEFAULT', true, 'C:\\Windows', undefined, {} as any, false, Platform.Windows);
strictEqual(shell, 'C:\\Windows\\Sysnative\\cmd.exe');
});
test('should use automationShell when specified', async () => {
const shell1 = await getDefaultShell(key => {
return ({
'terminal.integrated.shell.windows': 'shell',
'terminal.integrated.automationShell.windows': undefined
} as any)[key];
}, 'DEFAULT', false, 'C:\\Windows', undefined, {} as any, false, Platform.Windows);
strictEqual(shell1, 'shell', 'automationShell was false');
const shell2 = await getDefaultShell(key => {
return ({
'terminal.integrated.shell.windows': 'shell',
'terminal.integrated.automationShell.windows': undefined
} as any)[key];
}, 'DEFAULT', false, 'C:\\Windows', undefined, {} as any, true, Platform.Windows);
strictEqual(shell2, 'shell', 'automationShell was true');
const shell3 = await getDefaultShell(key => {
return ({
'terminal.integrated.shell.windows': 'shell',
'terminal.integrated.automationShell.windows': 'automationShell'
} as any)[key];
}, 'DEFAULT', false, 'C:\\Windows', undefined, {} as any, true, Platform.Windows);
strictEqual(shell3, 'automationShell', 'automationShell was true and specified in settings');
});
});
suite('preparePathForShell', () => {
const wslPathBackend = {
getWslPath: async (original: string, direction: 'unix-to-win' | 'win-to-unix') => {