Skip to content

Commit 4941478

Browse files
authored
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
1 parent 6878988 commit 4941478

File tree

5 files changed

+115
-8
lines changed

5 files changed

+115
-8
lines changed

src/vs/workbench/contrib/terminal/browser/terminalActions.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
3838
import { localize } from 'vs/nls';
3939
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
4040
import { IOpenerService } from 'vs/platform/opener/common/opener';
41+
import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints';
4142

4243
async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise<string | URI | undefined> {
4344
switch (configHelper.config.splitCwd) {
@@ -304,14 +305,18 @@ export class SelectDefaultShellWindowsTerminalAction extends Action {
304305
}
305306
}
306307

308+
const terminalIndexRe = /^([0-9]+): /;
309+
307310
export class SwitchTerminalAction extends Action {
308311

309312
public static readonly ID = TERMINAL_COMMAND_ID.SWITCH_TERMINAL;
310313
public static readonly LABEL = localize('workbench.action.terminal.switchTerminal', "Switch Terminal");
311314

312315
constructor(
313316
id: string, label: string,
314-
@ITerminalService private readonly _terminalService: ITerminalService
317+
@ITerminalService private readonly _terminalService: ITerminalService,
318+
@ITerminalContributionService private readonly _contributions: ITerminalContributionService,
319+
@ICommandService private readonly _commands: ICommandService,
315320
) {
316321
super(id, label, 'terminal-action switch-terminal');
317322
}
@@ -328,9 +333,20 @@ export class SwitchTerminalAction extends Action {
328333
this._terminalService.refreshActiveTab();
329334
return this._terminalService.selectDefaultShell();
330335
}
331-
const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1;
332-
this._terminalService.setActiveTabByIndex(selectedTabIndex);
333-
return this._terminalService.showPanel(true);
336+
337+
const indexMatches = terminalIndexRe.exec(item);
338+
if (indexMatches) {
339+
this._terminalService.setActiveTabByIndex(Number(indexMatches[1]) - 1);
340+
return this._terminalService.showPanel(true);
341+
}
342+
343+
const customType = this._contributions.terminalTypes.find(t => t.title === item);
344+
if (customType) {
345+
return this._commands.executeCommand(customType.command);
346+
}
347+
348+
console.warn(`Unmatched terminal item: "${item}"`);
349+
return Promise.resolve();
334350
}
335351
}
336352

@@ -342,9 +358,10 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
342358
action: IAction,
343359
@ITerminalService private readonly _terminalService: ITerminalService,
344360
@IThemeService private readonly _themeService: IThemeService,
345-
@IContextViewService contextViewService: IContextViewService
361+
@ITerminalContributionService private readonly _contributions: ITerminalContributionService,
362+
@IContextViewService contextViewService: IContextViewService,
346363
) {
347-
super(null, action, getTerminalSelectOpenItems(_terminalService), _terminalService.activeTabIndex, contextViewService, { ariaLabel: localize('terminals', 'Open Terminals.'), optionsAsChildren: true });
364+
super(null, action, getTerminalSelectOpenItems(_terminalService, _contributions), _terminalService.activeTabIndex, contextViewService, { ariaLabel: localize('terminals', 'Open Terminals.'), optionsAsChildren: true });
348365

349366
this._register(_terminalService.onInstancesChanged(this._updateItems, this));
350367
this._register(_terminalService.onActiveTabChanged(this._updateItems, this));
@@ -362,13 +379,18 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
362379
}
363380

364381
private _updateItems(): void {
365-
this.setOptions(getTerminalSelectOpenItems(this._terminalService), this._terminalService.activeTabIndex);
382+
this.setOptions(getTerminalSelectOpenItems(this._terminalService, this._contributions), this._terminalService.activeTabIndex);
366383
}
367384
}
368385

369-
function getTerminalSelectOpenItems(terminalService: ITerminalService): ISelectOptionItem[] {
386+
function getTerminalSelectOpenItems(terminalService: ITerminalService, contributions: ITerminalContributionService): ISelectOptionItem[] {
370387
const items = terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
371388
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true });
389+
390+
for (const contributed of contributions.terminalTypes) {
391+
items.push({ text: contributed.title });
392+
}
393+
372394
items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL });
373395
return items;
374396
}

src/vs/workbench/contrib/terminal/common/terminal.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { URI } from 'vs/base/common/uri';
1212
import { OperatingSystem } from 'vs/base/common/platform';
1313
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
1414
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
15+
import { IExtensionPointDescriptor } from 'vs/workbench/services/extensions/common/extensionsRegistry';
1516

1617
export const TERMINAL_VIEW_ID = 'workbench.panel.terminal';
1718

@@ -625,3 +626,41 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
625626
'workbench.action.quickOpenView',
626627
'workbench.action.toggleMaximizedPanel'
627628
];
629+
630+
export interface ITerminalContributions {
631+
types?: ITerminalTypeContribution[];
632+
}
633+
634+
export interface ITerminalTypeContribution {
635+
title: string;
636+
command: string;
637+
}
638+
639+
export const terminalContributionsDescriptor: IExtensionPointDescriptor = {
640+
extensionPoint: 'terminal',
641+
defaultExtensionKind: 'workspace',
642+
jsonSchema: {
643+
description: nls.localize('vscode.extension.contributes.terminal', 'Contributes terminal functionality.'),
644+
type: 'object',
645+
properties: {
646+
types: {
647+
type: 'array',
648+
description: nls.localize('vscode.extension.contributes.terminal.types', "Defines additional terminal types that the user can create."),
649+
items: {
650+
type: 'object',
651+
required: ['command', 'title'],
652+
properties: {
653+
command: {
654+
description: nls.localize('vscode.extension.contributes.terminal.types.command', "Command to execute when the user creates this type of terminal."),
655+
type: 'string',
656+
},
657+
title: {
658+
description: nls.localize('vscode.extension.contributes.terminal.types.title', "Title for this type of terminal."),
659+
type: 'string',
660+
},
661+
},
662+
},
663+
},
664+
},
665+
},
666+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { ITerminalContributionService, TerminalContributionService } from './terminalExtensionPoints';
7+
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
8+
9+
registerSingleton(ITerminalContributionService, TerminalContributionService, true);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
7+
import { ITerminalTypeContribution, ITerminalContributions, terminalContributionsDescriptor } from 'vs/workbench/contrib/terminal/common/terminal';
8+
import { flatten } from 'vs/base/common/arrays';
9+
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
10+
11+
// terminal extension point
12+
export const terminalsExtPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<ITerminalContributions>(terminalContributionsDescriptor);
13+
14+
export interface ITerminalContributionService {
15+
readonly _serviceBrand: undefined;
16+
17+
readonly terminalTypes: ReadonlyArray<ITerminalTypeContribution>;
18+
}
19+
20+
export const ITerminalContributionService = createDecorator<ITerminalContributionService>('terminalContributionsService');
21+
22+
export class TerminalContributionService implements ITerminalContributionService {
23+
public readonly _serviceBrand = undefined;
24+
25+
private _terminalTypes: ReadonlyArray<ITerminalTypeContribution> = [];
26+
27+
public get terminalTypes() {
28+
return this._terminalTypes;
29+
}
30+
31+
constructor() {
32+
terminalsExtPoint.setHandler(contributions => {
33+
this._terminalTypes = flatten(contributions.filter(c => c.description.enableProposedApi).map(c => c.value?.types ?? []));
34+
});
35+
}
36+
}

src/vs/workbench/workbench.common.main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ import 'vs/workbench/contrib/output/browser/outputView';
208208

209209
// Terminal
210210
import 'vs/workbench/contrib/terminal/common/environmentVariable.contribution';
211+
import 'vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution';
211212
import 'vs/workbench/contrib/terminal/browser/terminal.contribution';
212213
import 'vs/workbench/contrib/terminal/browser/terminalView';
213214

0 commit comments

Comments
 (0)