From 4941478743f17e72a72566a07f03d735bd3d796a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 25 Jun 2020 13:36:26 -0700 Subject: [PATCH] terminal: allow terminal types to be contributed * terminal: allow terminal types to be contributed * fixup! only allow terminal extensions on proposed APIs * fixup! rm unused import --- .../terminal/browser/terminalActions.ts | 38 ++++++++++++++---- .../contrib/terminal/common/terminal.ts | 39 +++++++++++++++++++ .../terminalExtensionPoints.contribution.ts | 9 +++++ .../common/terminalExtensionPoints.ts | 36 +++++++++++++++++ src/vs/workbench/workbench.common.main.ts | 1 + 5 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts create mode 100644 src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 8165776de8af2..6d726261b1818 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -38,6 +38,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { localize } from 'vs/nls'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise { switch (configHelper.config.splitCwd) { @@ -304,6 +305,8 @@ export class SelectDefaultShellWindowsTerminalAction extends Action { } } +const terminalIndexRe = /^([0-9]+): /; + export class SwitchTerminalAction extends Action { public static readonly ID = TERMINAL_COMMAND_ID.SWITCH_TERMINAL; @@ -311,7 +314,9 @@ export class SwitchTerminalAction extends Action { constructor( id: string, label: string, - @ITerminalService private readonly _terminalService: ITerminalService + @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalContributionService private readonly _contributions: ITerminalContributionService, + @ICommandService private readonly _commands: ICommandService, ) { super(id, label, 'terminal-action switch-terminal'); } @@ -328,9 +333,20 @@ export class SwitchTerminalAction extends Action { this._terminalService.refreshActiveTab(); return this._terminalService.selectDefaultShell(); } - const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1; - this._terminalService.setActiveTabByIndex(selectedTabIndex); - return this._terminalService.showPanel(true); + + const indexMatches = terminalIndexRe.exec(item); + if (indexMatches) { + this._terminalService.setActiveTabByIndex(Number(indexMatches[1]) - 1); + return this._terminalService.showPanel(true); + } + + const customType = this._contributions.terminalTypes.find(t => t.title === item); + if (customType) { + return this._commands.executeCommand(customType.command); + } + + console.warn(`Unmatched terminal item: "${item}"`); + return Promise.resolve(); } } @@ -342,9 +358,10 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem { action: IAction, @ITerminalService private readonly _terminalService: ITerminalService, @IThemeService private readonly _themeService: IThemeService, - @IContextViewService contextViewService: IContextViewService + @ITerminalContributionService private readonly _contributions: ITerminalContributionService, + @IContextViewService contextViewService: IContextViewService, ) { - super(null, action, getTerminalSelectOpenItems(_terminalService), _terminalService.activeTabIndex, contextViewService, { ariaLabel: localize('terminals', 'Open Terminals.'), optionsAsChildren: true }); + super(null, action, getTerminalSelectOpenItems(_terminalService, _contributions), _terminalService.activeTabIndex, contextViewService, { ariaLabel: localize('terminals', 'Open Terminals.'), optionsAsChildren: true }); this._register(_terminalService.onInstancesChanged(this._updateItems, this)); this._register(_terminalService.onActiveTabChanged(this._updateItems, this)); @@ -362,13 +379,18 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem { } private _updateItems(): void { - this.setOptions(getTerminalSelectOpenItems(this._terminalService), this._terminalService.activeTabIndex); + this.setOptions(getTerminalSelectOpenItems(this._terminalService, this._contributions), this._terminalService.activeTabIndex); } } -function getTerminalSelectOpenItems(terminalService: ITerminalService): ISelectOptionItem[] { +function getTerminalSelectOpenItems(terminalService: ITerminalService, contributions: ITerminalContributionService): ISelectOptionItem[] { const items = terminalService.getTabLabels().map(label => { text: label }); items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true }); + + for (const contributed of contributions.terminalTypes) { + items.push({ text: contributed.title }); + } + items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL }); return items; } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 0f2cb5a4e1f04..7a7639f627fa6 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -12,6 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { OperatingSystem } from 'vs/base/common/platform'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable'; +import { IExtensionPointDescriptor } from 'vs/workbench/services/extensions/common/extensionsRegistry'; export const TERMINAL_VIEW_ID = 'workbench.panel.terminal'; @@ -625,3 +626,41 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ 'workbench.action.quickOpenView', 'workbench.action.toggleMaximizedPanel' ]; + +export interface ITerminalContributions { + types?: ITerminalTypeContribution[]; +} + +export interface ITerminalTypeContribution { + title: string; + command: string; +} + +export const terminalContributionsDescriptor: IExtensionPointDescriptor = { + extensionPoint: 'terminal', + defaultExtensionKind: 'workspace', + jsonSchema: { + description: nls.localize('vscode.extension.contributes.terminal', 'Contributes terminal functionality.'), + type: 'object', + properties: { + types: { + type: 'array', + description: nls.localize('vscode.extension.contributes.terminal.types', "Defines additional terminal types that the user can create."), + items: { + type: 'object', + required: ['command', 'title'], + properties: { + command: { + description: nls.localize('vscode.extension.contributes.terminal.types.command', "Command to execute when the user creates this type of terminal."), + type: 'string', + }, + title: { + description: nls.localize('vscode.extension.contributes.terminal.types.title', "Title for this type of terminal."), + type: 'string', + }, + }, + }, + }, + }, + }, +}; diff --git a/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts b/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts new file mode 100644 index 0000000000000..86183be9c77f4 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITerminalContributionService, TerminalContributionService } from './terminalExtensionPoints'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +registerSingleton(ITerminalContributionService, TerminalContributionService, true); diff --git a/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.ts b/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.ts new file mode 100644 index 0000000000000..3bd6a63a328bb --- /dev/null +++ b/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { ITerminalTypeContribution, ITerminalContributions, terminalContributionsDescriptor } from 'vs/workbench/contrib/terminal/common/terminal'; +import { flatten } from 'vs/base/common/arrays'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +// terminal extension point +export const terminalsExtPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint(terminalContributionsDescriptor); + +export interface ITerminalContributionService { + readonly _serviceBrand: undefined; + + readonly terminalTypes: ReadonlyArray; +} + +export const ITerminalContributionService = createDecorator('terminalContributionsService'); + +export class TerminalContributionService implements ITerminalContributionService { + public readonly _serviceBrand = undefined; + + private _terminalTypes: ReadonlyArray = []; + + public get terminalTypes() { + return this._terminalTypes; + } + + constructor() { + terminalsExtPoint.setHandler(contributions => { + this._terminalTypes = flatten(contributions.filter(c => c.description.enableProposedApi).map(c => c.value?.types ?? [])); + }); + } +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 71b4a2d9faf2b..6ba5cea20fe83 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -208,6 +208,7 @@ import 'vs/workbench/contrib/output/browser/outputView'; // Terminal import 'vs/workbench/contrib/terminal/common/environmentVariable.contribution'; +import 'vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution'; import 'vs/workbench/contrib/terminal/browser/terminal.contribution'; import 'vs/workbench/contrib/terminal/browser/terminalView';