From bf5f7dd5ec19d9137733d3fdbbc5a8f9927cb9e0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 26 May 2021 11:34:11 -0700 Subject: [PATCH] Get split terminals working --- .../api/browser/mainThreadTerminalService.ts | 16 +++++++++----- .../workbench/api/common/extHost.protocol.ts | 2 ++ .../api/common/extHostTerminalService.ts | 22 +++++++++++++++++-- .../api/node/extHostTerminalService.ts | 4 +++- .../contrib/terminal/browser/terminal.ts | 2 +- .../terminal/browser/terminalService.ts | 17 +++++++------- 6 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index f04d2d7298e..46707154776 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -143,7 +143,16 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal, useShellEnvironment: launchConfig.useShellEnvironment }; - const terminal = this._terminalService.createTerminal(shellLaunchConfig); + let terminal: ITerminalInstance | undefined; + if (launchConfig.isSplitTerminal) { + const activeInstance = this._terminalService.getActiveInstance(); + if (activeInstance) { + terminal = withNullAsUndefined(this._terminalService.splitInstance(activeInstance, shellLaunchConfig)); + } + } + if (!terminal) { + terminal = this._terminalService.createTerminal(shellLaunchConfig); + } this._extHostTerminalIds.set(extHostTerminalId, terminal.instanceId); } @@ -205,10 +214,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape public $registerProfileProvider(id: string): void { // Proxy profile provider requests through the extension host this._profileProviders.set(id, this._terminalService.registerTerminalProfileProvider(id, { - provideProfile: async () => { - console.log('provide profile', id); - return { name: 'My fake profile' }; - } + createContributedTerminalProfile: async () => this._proxy.$createContributedProfileTerminal(id) })); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8de553dcc9b..0a14ba69172 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -464,6 +464,7 @@ export interface TerminalLaunchConfig { isFeatureTerminal?: boolean; isExtensionOwnedTerminal?: boolean; useShellEnvironment?: boolean; + isSplitTerminal?: boolean; } export interface MainThreadTerminalServiceShape extends IDisposable { @@ -1713,6 +1714,7 @@ export interface ExtHostTerminalServiceShape { $activateLink(id: number, linkId: number): void; $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void; $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void; + $createContributedProfileTerminal(id: string): Promise; } export interface ExtHostSCMShape { diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 2d00e434763..ff084ae892d 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -49,6 +49,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID export interface ITerminalInternalOptions { isFeatureTerminal?: boolean; useShellEnvironment?: boolean; + isSplitTerminal?: boolean; } export const IExtHostTerminalService = createDecorator('IExtHostTerminalService'); @@ -130,12 +131,13 @@ export class ExtHostTerminal { hideFromUser?: boolean, isFeatureTerminal?: boolean, isExtensionOwnedTerminal?: boolean, - useShellEnvironment?: boolean + useShellEnvironment?: boolean, + isSplitTerminal?: boolean ): Promise { if (typeof this._id !== 'string') { throw new Error('Terminal has already been created'); } - await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, icon, initialText, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal, useShellEnvironment }); + await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, icon, initialText, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal, useShellEnvironment, isSplitTerminal }); } public async createExtensionTerminal(iconPath?: URI | { light: URI; dark: URI } | ThemeIcon): Promise { @@ -586,6 +588,22 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I }); } + public async $createContributedProfileTerminal(id: string): Promise { + // TODO: Use cancellation token + const options = await this._profileProviders.get(id)?.provideProfileOptions(new CancellationTokenSource().token); + if (!options) { + throw new Error(`No terminal profile options provided for id "${id}"`); + } + if ('pty' in options) { + // TODO: Pass in split terminal option + this.createExtensionTerminal(options); + } + // if (options.iconPath) { + // checkProposedApiEnabled(extension); + // } + this.createTerminalFromOptions(options, { isSplitTerminal: true }); + } + public async $provideLinks(terminalId: number, line: string): Promise { const terminal = this._getTerminalById(terminalId); if (!terminal) { diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 8b70a2fb70f..a9f5afe1c64 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -27,6 +27,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal { const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name); this._terminals.push(terminal); + // TODO: Pass in options instead of individual props terminal.create( withNullAsUndefined(options.shellPath), withNullAsUndefined(options.shellArgs), @@ -39,7 +40,8 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { withNullAsUndefined(options.hideFromUser), withNullAsUndefined(internalOptions?.isFeatureTerminal), true, - withNullAsUndefined(internalOptions?.useShellEnvironment) + withNullAsUndefined(internalOptions?.useShellEnvironment), + withNullAsUndefined(internalOptions?.isSplitTerminal) ); return terminal.value; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 16802c1818e..061f8fa2afa 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -227,7 +227,7 @@ export interface ITerminalExternalLinkProvider { } export interface ITerminalProfileProvider { - provideProfile(): Promise; + createContributedTerminalProfile(isSplitTerminal: boolean): Promise; } export interface ITerminalLink { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 5c0aa7f802c..938662c8aa6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -962,7 +962,7 @@ export class TerminalService implements ITerminalService { return; } if (type === 'createInstance') { - // TODO: How to support alt here? + // Legacy implementation - remove when js-debug adopts new if ('command' in value.profile) { return this._commandService.executeCommand(value.profile.command); } @@ -977,13 +977,14 @@ export class TerminalService implements ITerminalService { this._notificationService.error(`No terminal profile provider registered for id "${value.profile.id}"`); return; } - const slc = await profileProvider.provideProfile(); - if (keyMods?.alt && activeInstance) { - // create split, only valid if there's an active instance - instance = this.splitInstance(activeInstance, slc); - } else { - instance = this.createTerminal(slc); - } + await profileProvider.createContributedTerminalProfile(!!(keyMods?.alt && activeInstance)); + // TODO: Pass in cwd here? cwd should probably still be inherited + // if (keyMods?.alt && activeInstance) { + // // create split, only valid if there's an active instance + // instance = this.splitInstance(activeInstance, slc); + // } else { + // instance = this.createTerminal(slc); + // } return; } else { if (keyMods?.alt && activeInstance) {