From f1334e055c8dcb4cc0bf730ccc183c101a7aeaed Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 24 Mar 2021 11:49:05 -0700 Subject: [PATCH] Polish select default profile quick pick Fixes #119808 --- .../workbench/api/common/extHost.protocol.ts | 1 + .../terminal/browser/terminalService.ts | 64 ++++++++++++------- .../contrib/terminal/common/terminal.ts | 3 + .../contrib/terminal/node/terminalProfiles.ts | 15 +++-- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 159f543de1d..06c7e22777a 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1657,6 +1657,7 @@ export interface ExtHostTerminalServiceShape { $acceptProcessRequestCwd(id: number): void; $acceptProcessRequestLatency(id: number): number; $acceptWorkspacePermissionsChanged(isAllowed: boolean): void; + // TODO: Change quickLaunchOnly to "includeAutoDetected" or something similar $getAvailableProfiles(quickLaunchOnly: boolean): Promise; $getDefaultShellAndArgs(useAutomationShell: boolean): Promise; $provideLinks(id: number, line: string): Promise; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 5c11833dbba..2616c39cbf5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -15,7 +15,7 @@ import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configur import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; -import { IPickOptions, IQuickInputButton, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IPickOptions, IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ILocalTerminalService, IShellLaunchConfig, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalShellType, WindowsShellType } from 'vs/platform/terminal/common/terminal'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -843,11 +843,8 @@ export class TerminalService implements ITerminalService { const profiles = await this._detectProfiles(false); const platformKey = await this._getPlatformKey(); - interface IProfileQuickPickItem extends IQuickPickItem { - profile: ITerminalProfile; - } const options: IPickOptions = { - placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal profile, you can change this later in your settings"), + placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your default terminal profile"), onDidTriggerItemButton: async (context) => { const configKey = `terminal.integrated.profiles.${platformKey}`; const configProfiles = this._configurationService.inspect<{ [key: string]: ITerminalProfileObject }>(configKey); @@ -873,25 +870,20 @@ export class TerminalService implements ITerminalService { await this._configurationService.updateValue(configKey, newConfigValue, ConfigurationTarget.USER); } }; - const quickPickItems = profiles.map((profile): IProfileQuickPickItem => { - const buttons: IQuickInputButton[] = [{ - iconClass: ThemeIcon.asClassName(configureTerminalProfileIcon), - tooltip: nls.localize('createQuickLaunchProfile', "Configure Terminal Profile") - }]; - if (profile.args) { - if (typeof profile.args === 'string') { - return { label: profile.profileName, description: `${profile.path} ${profile.args}`, profile, buttons }; - } - const argsString = profile.args.map(e => { - if (e.includes(' ')) { - return `"${e.replace('/"/g', '\\"')}"`; - } - return e; - }).join(' '); - return { label: profile.profileName, description: `${profile.path} ${argsString}`, profile, buttons }; - } - return { label: profile.profileName, description: profile.path, profile, buttons }; - }); + + // Build quick pick items + const quickPickItems: (IProfileQuickPickItem | IQuickPickSeparator)[] = []; + const configProfiles = profiles.filter(e => !e.isAutoDetected); + const autoDetectedProfiles = profiles.filter(e => e.isAutoDetected); + if (configProfiles.length > 0) { + quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles', "profiles") }); + quickPickItems.push(...configProfiles.map(e => this._createProfileQuickPickItem(e))); + } + if (configProfiles.length > 0) { + quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles.detected', "detected") }); + quickPickItems.push(...autoDetectedProfiles.map(e => this._createProfileQuickPickItem(e))); + } + const value = await this._quickInputService.pick(quickPickItems, options); if (!value) { return; @@ -900,6 +892,26 @@ export class TerminalService implements ITerminalService { await this._configurationService.updateValue(`terminal.integrated.shellArgs.${platformKey}`, value.profile.args, ConfigurationTarget.USER); } + private _createProfileQuickPickItem(profile: ITerminalProfile): IProfileQuickPickItem { + const buttons: IQuickInputButton[] = [{ + iconClass: ThemeIcon.asClassName(configureTerminalProfileIcon), + tooltip: nls.localize('createQuickLaunchProfile', "Configure Terminal Profile") + }]; + if (profile.args) { + if (typeof profile.args === 'string') { + return { label: profile.profileName, description: `${profile.path} ${profile.args}`, profile, buttons }; + } + const argsString = profile.args.map(e => { + if (e.includes(' ')) { + return `"${e.replace('/"/g', '\\"')}"`; + } + return e; + }).join(' '); + return { label: profile.profileName, description: `${profile.path} ${argsString}`, profile, buttons }; + } + return { label: profile.profileName, description: profile.path, profile, buttons }; + } + public createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, this._terminalFocusContextKey, @@ -1003,3 +1015,7 @@ export class TerminalService implements ITerminalService { } } } + +interface IProfileQuickPickItem extends IQuickPickItem { + profile: ITerminalProfile; +} diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index a524f9b364b..54f4163abf2 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -234,6 +234,7 @@ export interface IBeforeProcessDataEvent { export interface ITerminalProfile { profileName: string; path: string; + isAutoDetected?: boolean; isWorkspaceProfile?: boolean; args?: string | string[] | undefined; } @@ -246,10 +247,12 @@ export const enum ProfileSource { export interface ITerminalExecutable { path: string | string[]; args?: string | string[] | undefined; + isAutoDetected?: boolean; } export interface ITerminalProfileSource { source: ProfileSource; + isAutoDetected?: boolean; } export type ProfileName = string; diff --git a/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts b/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts index 07c47fcc800..52ed5e994ec 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts @@ -39,20 +39,22 @@ async function detectAvailableWindowsProfiles(quickLaunchOnly: boolean, statProv const detectedProfiles: Map = new Map(); - // Add non-quick launch profiles + // Add auto detected profiles if (!quickLaunchOnly) { - detectedProfiles.set('PowerShell', { source: ProfileSource.Pwsh }); - detectedProfiles.set('Git Bash', { source: ProfileSource.GitBash }); + detectedProfiles.set('PowerShell', { source: ProfileSource.Pwsh, isAutoDetected: true }); + detectedProfiles.set('Git Bash', { source: ProfileSource.GitBash, isAutoDetected: true }); detectedProfiles.set('Cygwin', { path: [ `${process.env['HOMEDRIVE']}\\cygwin64\\bin\\bash.exe`, `${process.env['HOMEDRIVE']}\\cygwin\\bin\\bash.exe` ], - args: ['--login'] + args: ['--login'], + isAutoDetected: true }); detectedProfiles.set('Command Prompt', { - path: [`${system32Path}\\cmd.exe`] + path: [`${system32Path}\\cmd.exe`], + isAutoDetected: true }, ); } @@ -94,6 +96,7 @@ async function transformToTerminalProfiles(entries: IterableIterator<[string, IT } const validatedProfile = await validateProfilePaths(profileName, paths, statProvider, args, logService); if (validatedProfile) { + validatedProfile.isAutoDetected = profile.isAutoDetected; resultProfiles.push(validatedProfile); } else { logService?.trace('profile not validated', profileName, originalPaths); @@ -197,7 +200,7 @@ async function detectAvailableUnixProfiles(statProvider: IStatProvider, logServi const profiles = testPaths || contents.split('\n').filter(e => e.trim().indexOf('#') !== 0 && e.trim().length > 0); for (const profile of profiles) { const profileName = basename(profile); - detectedProfiles.set(profileName, { path: profile }); + detectedProfiles.set(profileName, { path: profile, isAutoDetected: true }); } }