diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 3df611b17b469..342c6e3cd0734 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable } from 'vscode'; -import { doesNotThrow, equal, ok, deepEqual } from 'assert'; +import { doesNotThrow, equal, ok, deepEqual, throws } from 'assert'; suite('window namespace tests', () => { suiteSetup(async () => { @@ -84,6 +84,30 @@ suite('window namespace tests', () => { } }); + test('creationOptions should be set and readonly for TerminalOptions terminals', (done) => { + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } + terminal.dispose(); + disposables.push(window.onDidCloseTerminal(() => done())); + })); + const options = { + name: 'foo', + hideFromUser: true + }; + const terminal = window.createTerminal(options); + try { + equal(terminal.name, 'foo'); + deepEqual(terminal.creationOptions, options); + throws(() => (terminal.creationOptions).name = 'bad', 'creationOptions should be readonly at runtime'); + } catch (e) { + done(e); + } + }); + test('onDidOpenTerminal should fire when a terminal is created', (done) => { disposables.push(window.onDidOpenTerminal(term => { try { @@ -369,6 +393,33 @@ suite('window namespace tests', () => { }; const terminal = window.createTerminal({ name: 'foo', pty }); }); + + test('creationOptions should be set and readonly for ExtensionTerminalOptions terminals', (done) => { + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } + terminal.dispose(); + disposables.push(window.onDidCloseTerminal(() => done())); + })); + const writeEmitter = new EventEmitter(); + const pty: Pseudoterminal = { + onDidWrite: writeEmitter.event, + open: () => { }, + close: () => { } + }; + const options = { name: 'foo', pty }; + const terminal = window.createTerminal(options); + try { + equal(terminal.name, 'foo'); + deepEqual(terminal.creationOptions, options); + throws(() => (terminal.creationOptions).name = 'bad', 'creationOptions should be readonly at runtime'); + } catch (e) { + done(e); + } + }); }); }); }); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 2a268d8cf3a91..5052c1261ce90 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -689,6 +689,13 @@ declare module 'vscode' { } export interface Terminal { + /** + * The object used to initialize the terminal, this is useful for things like detecting the + * shell type of shells not launched by the extension or detecting what folder the shell was + * launched in. + */ + readonly creationOptions: Readonly; + /** * The current dimensions of the terminal. This will be `undefined` immediately after the * terminal is created as the dimensions are not known until shortly after the terminal is diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 8344b323c7e5c..37a0d6edd3b91 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -167,11 +167,18 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } private _onTerminalOpened(terminalInstance: ITerminalInstance): void { + const shellLaunchConfigDto: IShellLaunchConfigDto = { + name: terminalInstance.shellLaunchConfig.name, + executable: terminalInstance.shellLaunchConfig.executable, + args: terminalInstance.shellLaunchConfig.args, + cwd: terminalInstance.shellLaunchConfig.cwd, + env: terminalInstance.shellLaunchConfig.env + }; if (terminalInstance.title) { - this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title); + this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title, shellLaunchConfigDto); } else { terminalInstance.waitForTitle().then(title => { - this._proxy.$acceptTerminalOpened(terminalInstance.id, title); + this._proxy.$acceptTerminalOpened(terminalInstance.id, title, shellLaunchConfigDto); }); } } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 586824df3bbd6..6a2ca937d3627 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1197,7 +1197,7 @@ export interface ITerminalDimensionsDto { export interface ExtHostTerminalServiceShape { $acceptTerminalClosed(id: number): void; - $acceptTerminalOpened(id: number, name: string): void; + $acceptTerminalOpened(id: number, name: string, shellLaunchConfig: IShellLaunchConfigDto): void; $acceptActiveTerminalChanged(id: number | null): void; $acceptTerminalProcessId(id: number, processId: number): void; $acceptTerminalProcessData(id: number, data: string): void; diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 40ecebf643b21..714d51ad6b638 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -102,10 +102,12 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi constructor( proxy: MainThreadTerminalServiceShape, + private readonly _creationOptions: vscode.TerminalOptions | vscode.ExtensionTerminalOptions, private _name?: string, id?: number ) { super(proxy, id); + this._creationOptions = Object.freeze(this._creationOptions); this._pidPromise = new Promise(c => this._pidPromiseComplete = c); } @@ -162,6 +164,10 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi return this._pidPromise; } + public get creationOptions(): Readonly { + return this._creationOptions; + } + public sendText(text: string, addNewLine: boolean = true): void { this._checkDisposed(); this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]); @@ -310,7 +316,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void; public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { - const terminal = new ExtHostTerminal(this._proxy, options.name); + const terminal = new ExtHostTerminal(this._proxy, options, options.name); const p = new ExtHostPseudoterminal(options.pty); terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p)); this._terminals.push(terminal); @@ -390,7 +396,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ } } - public $acceptTerminalOpened(id: number, name: string): void { + public $acceptTerminalOpened(id: number, name: string, shellLaunchConfigDto: IShellLaunchConfigDto): void { const index = this._getTerminalObjectIndexById(this._terminals, id); if (index !== null) { // The terminal has already been created (via createTerminal*), only fire the event @@ -399,7 +405,14 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ return; } - const terminal = new ExtHostTerminal(this._proxy, name, id); + const creationOptions: vscode.TerminalOptions = { + name: shellLaunchConfigDto.name, + shellPath: shellLaunchConfigDto.executable, + shellArgs: shellLaunchConfigDto.args, + cwd: typeof shellLaunchConfigDto.cwd === 'string' ? shellLaunchConfigDto.cwd : URI.revive(shellLaunchConfigDto.cwd), + env: shellLaunchConfigDto.env + }; + const terminal = new ExtHostTerminal(this._proxy, creationOptions, name, id); this._terminals.push(terminal); this._onDidOpenTerminal.fire(terminal); terminal.isOpen = true; diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index d89750cfdf1ef..64d1a0005b7ce 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -45,14 +45,14 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { } public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { - const terminal = new ExtHostTerminal(this._proxy, name); + const terminal = new ExtHostTerminal(this._proxy, { name, shellPath, shellArgs }, name); terminal.create(shellPath, shellArgs); this._terminals.push(terminal); return terminal; } public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { - const terminal = new ExtHostTerminal(this._proxy, options.name); + const terminal = new ExtHostTerminal(this._proxy, options, options.name); terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv, options.hideFromUser); this._terminals.push(terminal); return terminal;