提交 dc1c2c7e 编写于 作者: D Daniel Imms

Remove shell notification in favor of dropdown entry

Fixes #74019
上级 f57f8ca7
...@@ -94,7 +94,7 @@ CommandsRegistry.registerCommand({ ...@@ -94,7 +94,7 @@ CommandsRegistry.registerCommand({
const directoriesToOpen = distinct(stats.filter(data => data.success).map(({ stat }) => stat!.isDirectory ? stat!.resource.fsPath : paths.dirname(stat!.resource.fsPath))); const directoriesToOpen = distinct(stats.filter(data => data.success).map(({ stat }) => stat!.isDirectory ? stat!.resource.fsPath : paths.dirname(stat!.resource.fsPath)));
return directoriesToOpen.map(dir => { return directoriesToOpen.map(dir => {
if (configurationService.getValue<IExternalTerminalConfiguration>().terminal.explorerKind === 'integrated') { if (configurationService.getValue<IExternalTerminalConfiguration>().terminal.explorerKind === 'integrated') {
const instance = integratedTerminalService.createTerminal({ cwd: dir }, true); const instance = integratedTerminalService.createTerminal({ cwd: dir });
if (instance && (resources.length === 1 || !resource || dir === resource.fsPath || dir === paths.dirname(resource.fsPath))) { if (instance && (resources.length === 1 || !resource || dir === resource.fsPath || dir === paths.dirname(resource.fsPath))) {
integratedTerminalService.setActiveInstance(instance); integratedTerminalService.setActiveInstance(instance);
integratedTerminalService.showPanel(true); integratedTerminalService.showPanel(true);
......
...@@ -35,6 +35,7 @@ import { Schemas } from 'vs/base/common/network'; ...@@ -35,6 +35,7 @@ import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform'; import { isWindows } from 'vs/base/common/platform';
import { withNullAsUndefined } from 'vs/base/common/types'; import { withNullAsUndefined } from 'vs/base/common/types';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export const TERMINAL_PICKER_PREFIX = 'term '; export const TERMINAL_PICKER_PREFIX = 'term ';
...@@ -85,7 +86,7 @@ export class ToggleTerminalAction extends TogglePanelAction { ...@@ -85,7 +86,7 @@ export class ToggleTerminalAction extends TogglePanelAction {
if (this.terminalService.terminalInstances.length === 0) { if (this.terminalService.terminalInstances.length === 0) {
// If there is not yet an instance attempt to create it here so that we can suggest a // If there is not yet an instance attempt to create it here so that we can suggest a
// new shell on Windows (and not do so when the panel is restored on reload). // new shell on Windows (and not do so when the panel is restored on reload).
const newTerminalInstance = this.terminalService.createTerminal(undefined, true); const newTerminalInstance = this.terminalService.createTerminal(undefined);
const toDispose = newTerminalInstance.onProcessIdReady(() => { const toDispose = newTerminalInstance.onProcessIdReady(() => {
newTerminalInstance.focus(); newTerminalInstance.focus();
toDispose.dispose(); toDispose.dispose();
...@@ -329,7 +330,7 @@ export class CreateNewTerminalAction extends Action { ...@@ -329,7 +330,7 @@ export class CreateNewTerminalAction extends Action {
if (folders.length <= 1) { if (folders.length <= 1) {
// Allow terminal service to handle the path when there is only a // Allow terminal service to handle the path when there is only a
// single root // single root
instancePromise = Promise.resolve(this.terminalService.createTerminal(undefined, true)); instancePromise = Promise.resolve(this.terminalService.createTerminal(undefined));
} else { } else {
const options: IPickOptions<IQuickPickItem> = { const options: IPickOptions<IQuickPickItem> = {
placeHolder: nls.localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal") placeHolder: nls.localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal")
...@@ -339,7 +340,7 @@ export class CreateNewTerminalAction extends Action { ...@@ -339,7 +340,7 @@ export class CreateNewTerminalAction extends Action {
// Don't create the instance if the workspace picker was canceled // Don't create the instance if the workspace picker was canceled
return null; return null;
} }
return this.terminalService.createTerminal({ cwd: workspace.uri }, true); return this.terminalService.createTerminal({ cwd: workspace.uri });
}); });
} }
...@@ -366,7 +367,7 @@ export class CreateNewInActiveWorkspaceTerminalAction extends Action { ...@@ -366,7 +367,7 @@ export class CreateNewInActiveWorkspaceTerminalAction extends Action {
} }
public run(event?: any): Promise<any> { public run(event?: any): Promise<any> {
const instance = this.terminalService.createTerminal(undefined, true); const instance = this.terminalService.createTerminal(undefined);
if (!instance) { if (!instance) {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
...@@ -720,6 +721,14 @@ export class SwitchTerminalAction extends Action { ...@@ -720,6 +721,14 @@ export class SwitchTerminalAction extends Action {
if (!item || !item.split) { if (!item || !item.split) {
return Promise.resolve(null); return Promise.resolve(null);
} }
if (item === SwitchTerminalActionViewItem.SEPARATOR) {
this.terminalService.refreshActiveTab();
return Promise.resolve(null);
}
if (item === SelectDefaultShellWindowsTerminalAction.LABEL) {
this.terminalService.refreshActiveTab();
return this.terminalService.selectDefaultWindowsShell();
}
const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1; const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1;
this.terminalService.setActiveTabByIndex(selectedTabIndex); this.terminalService.setActiveTabByIndex(selectedTabIndex);
return this.terminalService.showPanel(true); return this.terminalService.showPanel(true);
...@@ -728,11 +737,14 @@ export class SwitchTerminalAction extends Action { ...@@ -728,11 +737,14 @@ export class SwitchTerminalAction extends Action {
export class SwitchTerminalActionViewItem extends SelectActionViewItem { export class SwitchTerminalActionViewItem extends SelectActionViewItem {
public static readonly SEPARATOR = '─────────';
constructor( constructor(
action: IAction, action: IAction,
@ITerminalService private readonly terminalService: ITerminalService, @ITerminalService private readonly terminalService: ITerminalService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@IContextViewService contextViewService: IContextViewService @IContextViewService contextViewService: IContextViewService,
@IWorkbenchEnvironmentService private workbenchEnvironmentService: IWorkbenchEnvironmentService
) { ) {
super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') }); super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
...@@ -743,7 +755,13 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem { ...@@ -743,7 +755,13 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
} }
private _updateItems(): void { private _updateItems(): void {
this.setOptions(this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), this.terminalService.activeTabIndex); const items = this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
let enableSelectDefaultShell = this.workbenchEnvironmentService.configuration.remoteAuthority ? false : isWindows;
if (enableSelectDefaultShell) {
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR });
items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL });
}
this.setOptions(items, this.terminalService.activeTabIndex);
} }
} }
......
...@@ -3,21 +3,19 @@ ...@@ -3,21 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as platform from 'vs/base/common/platform'; import * as platform from 'vs/base/common/platform';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService'; import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files'; import { IFileService } from 'vs/platform/files/common/files';
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
...@@ -36,7 +34,6 @@ export abstract class TerminalService extends CommonTerminalService implements I ...@@ -36,7 +34,6 @@ export abstract class TerminalService extends CommonTerminalService implements I
@INotificationService notificationService: INotificationService, @INotificationService notificationService: INotificationService,
@IDialogService dialogService: IDialogService, @IDialogService dialogService: IDialogService,
@IInstantiationService protected readonly _instantiationService: IInstantiationService, @IInstantiationService protected readonly _instantiationService: IInstantiationService,
@IWorkbenchEnvironmentService private _environmentService: IWorkbenchEnvironmentService,
@IExtensionService extensionService: IExtensionService, @IExtensionService extensionService: IExtensionService,
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService @IRemoteAgentService remoteAgentService: IRemoteAgentService
...@@ -52,7 +49,7 @@ export abstract class TerminalService extends CommonTerminalService implements I ...@@ -52,7 +49,7 @@ export abstract class TerminalService extends CommonTerminalService implements I
return instance; return instance;
} }
public createTerminal(shell: IShellLaunchConfig = {}, wasNewTerminalAction?: boolean): ITerminalInstance { public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance {
const terminalTab = this._instantiationService.createInstance(TerminalTab, const terminalTab = this._instantiationService.createInstance(TerminalTab,
this._terminalFocusContextKey, this._terminalFocusContextKey,
this.configHelper, this.configHelper,
...@@ -68,74 +65,9 @@ export abstract class TerminalService extends CommonTerminalService implements I ...@@ -68,74 +65,9 @@ export abstract class TerminalService extends CommonTerminalService implements I
this.setActiveInstanceByIndex(0); this.setActiveInstanceByIndex(0);
} }
this._onInstancesChanged.fire(); this._onInstancesChanged.fire();
this._suggestShellChange(wasNewTerminalAction);
return instance; return instance;
} }
private _suggestShellChange(wasNewTerminalAction?: boolean): void {
// Only suggest on Windows since $SHELL works great for macOS/Linux
if (!platform.isWindows) {
return;
}
if (this._environmentService.configuration.remoteAuthority) {
// Don't suggest if the opened workspace is remote
return;
}
// Only suggest when the terminal instance is being created by an explicit user action to
// launch a terminal, as opposed to something like tasks, debug, panel restore, etc.
if (!wasNewTerminalAction) {
return;
}
if (this._environmentService.configuration.remoteAuthority) {
// Don't suggest if the opened workspace is remote
return;
}
// Don't suggest if the user has explicitly opted out
const neverSuggest = this._storageService.getBoolean(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, StorageScope.GLOBAL, false);
if (neverSuggest) {
return;
}
// Never suggest if the setting is non-default already (ie. they set the setting manually)
if (this.configHelper.config.shell.windows !== this.getDefaultShell(platform.Platform.Windows)) {
this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL);
return;
}
this._notificationService.prompt(
Severity.Info,
nls.localize('terminal.integrated.chooseWindowsShellInfo', "You can change the default terminal shell by selecting the customize button."),
[{
label: nls.localize('customize', "Customize"),
run: () => {
this.selectDefaultWindowsShell().then(shell => {
if (!shell) {
return Promise.resolve(null);
}
// Launch a new instance with the newly selected shell
const instance = this.createTerminal({
executable: shell,
args: this.configHelper.config.shellArgs.windows
});
if (instance) {
this.setActiveInstance(instance);
}
return Promise.resolve(null);
});
}
},
{
label: nls.localize('never again', "Don't Show Again"),
isSecondary: true,
run: () => this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL)
}]
);
}
public focusFindWidget(): Promise<void> { public focusFindWidget(): Promise<void> {
return this.showPanel(false).then(() => { return this.showPanel(false).then(() => {
const panel = this._panelService.getActivePanel() as TerminalPanel; const panel = this._panelService.getActivePanel() as TerminalPanel;
......
...@@ -37,7 +37,6 @@ export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED = new RawContextKey ...@@ -37,7 +37,6 @@ export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED = new RawContextKey
export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED.toNegated(); export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED.toNegated();
export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWorkspaceShellAllowed'; export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWorkspaceShellAllowed';
export const NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY = 'terminal.integrated.neverSuggestSelectWindowsShell';
export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverMeasureRenderTime'; export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverMeasureRenderTime';
// The creation of extension host terminals is delayed by this value (milliseconds). The purpose of // The creation of extension host terminals is delayed by this value (milliseconds). The purpose of
...@@ -216,10 +215,8 @@ export interface ITerminalService { ...@@ -216,10 +215,8 @@ export interface ITerminalService {
/** /**
* Creates a terminal. * Creates a terminal.
* @param shell The shell launch configuration to use. * @param shell The shell launch configuration to use.
* @param wasNewTerminalAction Whether this was triggered by a new terminal action, if so a
* default shell selection dialog may display.
*/ */
createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; createTerminal(shell?: IShellLaunchConfig): ITerminalInstance;
/** /**
* Creates a terminal renderer. * Creates a terminal renderer.
...@@ -245,6 +242,12 @@ export interface ITerminalService { ...@@ -245,6 +242,12 @@ export interface ITerminalService {
setActiveTabToPrevious(): void; setActiveTabToPrevious(): void;
setActiveTabByIndex(tabIndex: number): void; setActiveTabByIndex(tabIndex: number): void;
/**
* Fire the onActiveTabChanged event, this will trigger the terminal dropdown to be updated,
* among other things.
*/
refreshActiveTab(): void;
showPanel(focus?: boolean): Promise<void>; showPanel(focus?: boolean): Promise<void>;
hidePanel(): void; hidePanel(): void;
focusFindWidget(): Promise<void>; focusFindWidget(): Promise<void>;
......
...@@ -41,7 +41,7 @@ export abstract class TerminalService implements ITerminalService { ...@@ -41,7 +41,7 @@ export abstract class TerminalService implements ITerminalService {
public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; } public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; }
public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; } public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; }
private readonly _onActiveTabChanged = new Emitter<void>(); protected readonly _onActiveTabChanged = new Emitter<void>();
public get onActiveTabChanged(): Event<void> { return this._onActiveTabChanged.event; } public get onActiveTabChanged(): Event<void> { return this._onActiveTabChanged.event; }
protected readonly _onInstanceCreated = new Emitter<ITerminalInstance>(); protected readonly _onInstanceCreated = new Emitter<ITerminalInstance>();
public get onInstanceCreated(): Event<ITerminalInstance> { return this._onInstanceCreated.event; } public get onInstanceCreated(): Event<ITerminalInstance> { return this._onInstanceCreated.event; }
...@@ -104,6 +104,7 @@ export abstract class TerminalService implements ITerminalService { ...@@ -104,6 +104,7 @@ export abstract class TerminalService implements ITerminalService {
protected abstract _getWslPath(path: string): Promise<string>; protected abstract _getWslPath(path: string): Promise<string>;
protected abstract _getWindowsBuildNumber(): number; protected abstract _getWindowsBuildNumber(): number;
public abstract refreshActiveTab(): void;
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;
public abstract getDefaultShell(platform: Platform): string; public abstract getDefaultShell(platform: Platform): string;
......
...@@ -20,7 +20,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; ...@@ -20,7 +20,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { ipcRenderer as ipc } from 'electron'; import { ipcRenderer as ipc } from 'electron';
import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
import { coalesce } from 'vs/base/common/arrays'; import { coalesce } from 'vs/base/common/arrays';
...@@ -45,11 +44,10 @@ export class TerminalService extends BrowserTerminalService implements ITerminal ...@@ -45,11 +44,10 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
@INotificationService notificationService: INotificationService, @INotificationService notificationService: INotificationService,
@IDialogService dialogService: IDialogService, @IDialogService dialogService: IDialogService,
@IExtensionService extensionService: IExtensionService, @IExtensionService extensionService: IExtensionService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService @IRemoteAgentService remoteAgentService: IRemoteAgentService
) { ) {
super(contextKeyService, panelService, layoutService, lifecycleService, storageService, notificationService, dialogService, instantiationService, environmentService, extensionService, fileService, remoteAgentService); super(contextKeyService, panelService, layoutService, lifecycleService, storageService, notificationService, dialogService, instantiationService, extensionService, fileService, remoteAgentService);
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro); this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro);
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => { ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => {
...@@ -102,6 +100,11 @@ export class TerminalService extends BrowserTerminalService implements ITerminal ...@@ -102,6 +100,11 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
return getDefaultShell(p); return getDefaultShell(p);
} }
public refreshActiveTab(): void {
// Fire active instances changed
this._onActiveTabChanged.fire();
}
public selectDefaultWindowsShell(): Promise<string | undefined> { public selectDefaultWindowsShell(): Promise<string | undefined> {
return this._detectWindowsShells().then(shells => { return this._detectWindowsShells().then(shells => {
const options: IPickOptions<IQuickPickItem> = { const options: IPickOptions<IQuickPickItem> = {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册