未验证 提交 28d06f02 编写于 作者: D Daniel Imms 提交者: GitHub

Merge pull request #74228 from microsoft/tyriar/72518_runInBackground

Add runInBackground option to Terminal API
...@@ -737,6 +737,29 @@ suite('window namespace tests', () => { ...@@ -737,6 +737,29 @@ suite('window namespace tests', () => {
const terminal1 = window.createTerminal({ name: 'test' }); const terminal1 = window.createTerminal({ name: 'test' });
terminal1.show(); terminal1.show();
}); });
test('runInBackground terminal: onDidWriteData should work', done => {
const terminal = window.createTerminal({ name: 'bg', runInBackground: true });
let data = '';
terminal.onDidWriteData(e => {
data += e;
if (data.indexOf('foo') !== -1) {
terminal.dispose();
done();
}
});
terminal.sendText('foo');
});
test('runInBackground terminal: should be available to terminals API', done => {
const terminal = window.createTerminal({ name: 'bg', runInBackground: true });
window.onDidOpenTerminal(t => {
assert.equal(t, terminal);
assert.equal(t.name, 'bg');
assert.ok(window.terminals.indexOf(terminal) !== -1);
done();
});
});
}); });
}); });
......
...@@ -1099,6 +1099,17 @@ declare module 'vscode' { ...@@ -1099,6 +1099,17 @@ declare module 'vscode' {
//#region Terminal //#region Terminal
export interface TerminalOptions {
/**
* When enabled the terminal will run the process as normal but not be surfaced to the user
* until `Terminal.show` is called. The typical usage for this is when you need to run
* something that may need interactivity but only want to tell the user about it when
* interaction is needed. Note that the terminals will still be exposed to all extensions
* as normal.
*/
runInBackground?: boolean;
}
/** /**
* An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change. * An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change.
*/ */
......
...@@ -62,7 +62,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape ...@@ -62,7 +62,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// when the extension host process goes down ? // when the extension host process goes down ?
} }
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }> { public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean, runInBackground?: boolean): Promise<{ id: number, name: string }> {
const shellLaunchConfig: IShellLaunchConfig = { const shellLaunchConfig: IShellLaunchConfig = {
name, name,
executable: shellPath, executable: shellPath,
...@@ -71,7 +71,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape ...@@ -71,7 +71,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
waitOnExit, waitOnExit,
ignoreConfigurationCwd: true, ignoreConfigurationCwd: true,
env, env,
strictEnv strictEnv,
runInBackground
}; };
const terminal = this.terminalService.createTerminal(shellLaunchConfig); const terminal = this.terminalService.createTerminal(shellLaunchConfig);
return Promise.resolve({ return Promise.resolve({
......
...@@ -390,7 +390,7 @@ export interface MainThreadProgressShape extends IDisposable { ...@@ -390,7 +390,7 @@ export interface MainThreadProgressShape extends IDisposable {
} }
export interface MainThreadTerminalServiceShape extends IDisposable { export interface MainThreadTerminalServiceShape extends IDisposable {
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }>; $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean, runInBackground?: boolean): Promise<{ id: number, name: string }>;
$createTerminalRenderer(name: string): Promise<number>; $createTerminalRenderer(name: string): Promise<number>;
$dispose(terminalId: number): void; $dispose(terminalId: number): void;
$hide(terminalId: number): void; $hide(terminalId: number): void;
......
...@@ -484,7 +484,8 @@ export function createApiFactory( ...@@ -484,7 +484,8 @@ export function createApiFactory(
}, },
createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
if (typeof nameOrOptions === 'object') { if (typeof nameOrOptions === 'object') {
return extHostTerminalService.createTerminalFromOptions(<vscode.TerminalOptions>nameOrOptions); nameOrOptions.runInBackground = nameOrOptions.runInBackground && extension.enableProposedApi;
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
} }
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs); return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
}, },
......
...@@ -114,9 +114,10 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi ...@@ -114,9 +114,10 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
cwd?: string | URI, cwd?: string | URI,
env?: { [key: string]: string | null }, env?: { [key: string]: string | null },
waitOnExit?: boolean, waitOnExit?: boolean,
strictEnv?: boolean strictEnv?: boolean,
runInBackground?: boolean
): void { ): void {
this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv).then(terminal => { this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, runInBackground).then(terminal => {
this._name = terminal.name; this._name = terminal.name;
this._runQueuedRequests(terminal.id); this._runQueuedRequests(terminal.id);
}); });
...@@ -308,7 +309,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { ...@@ -308,7 +309,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options.name); const terminal = new ExtHostTerminal(this._proxy, options.name);
terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv); terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv, options.runInBackground);
this._terminals.push(terminal); this._terminals.push(terminal);
return terminal; return terminal;
} }
......
...@@ -50,6 +50,15 @@ export abstract class TerminalService extends CommonTerminalService implements I ...@@ -50,6 +50,15 @@ export abstract class TerminalService extends CommonTerminalService implements I
} }
public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance { public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance {
if (shell.runInBackground) {
const instance = this.createInstance(this._terminalFocusContextKey,
this.configHelper,
undefined,
shell,
true);
this._backgroundedTerminalInstances.push(instance);
return instance;
}
const terminalTab = this._instantiationService.createInstance(TerminalTab, const terminalTab = this._instantiationService.createInstance(TerminalTab,
this._terminalFocusContextKey, this._terminalFocusContextKey,
this.configHelper, this.configHelper,
...@@ -68,6 +77,25 @@ export abstract class TerminalService extends CommonTerminalService implements I ...@@ -68,6 +77,25 @@ export abstract class TerminalService extends CommonTerminalService implements I
return instance; return instance;
} }
protected _showBackgroundTerminal(instance: ITerminalInstance): void {
this._backgroundedTerminalInstances = this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1);
instance.shellLaunchConfig.runInBackground = false;
const terminalTab = this._instantiationService.createInstance(TerminalTab,
this._terminalFocusContextKey,
this.configHelper,
this._terminalContainer,
instance);
this._terminalTabs.push(terminalTab);
terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed));
terminalTab.addDisposable(terminalTab.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged));
this._initInstanceListeners(instance);
if (this.terminalInstances.length === 1) {
// It's the first instance so it should be made active automatically
this.setActiveInstanceByIndex(0);
}
this._onInstancesChanged.fire();
}
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;
......
...@@ -225,7 +225,7 @@ export class TerminalTab extends Disposable implements ITerminalTab { ...@@ -225,7 +225,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
terminalFocusContextKey: IContextKey<boolean>, terminalFocusContextKey: IContextKey<boolean>,
configHelper: ITerminalConfigHelper, configHelper: ITerminalConfigHelper,
private _container: HTMLElement, private _container: HTMLElement,
shellLaunchConfig: IShellLaunchConfig, shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance,
@ITerminalService private readonly _terminalService: ITerminalService, @ITerminalService private readonly _terminalService: ITerminalService,
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService
) { ) {
...@@ -233,12 +233,17 @@ export class TerminalTab extends Disposable implements ITerminalTab { ...@@ -233,12 +233,17 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this._onDisposed = new Emitter<ITerminalTab>(); this._onDisposed = new Emitter<ITerminalTab>();
this._onInstancesChanged = new Emitter<void>(); this._onInstancesChanged = new Emitter<void>();
const instance = this._terminalService.createInstance( let instance: ITerminalInstance;
terminalFocusContextKey, if ('id' in shellLaunchConfigOrInstance) {
configHelper, instance = shellLaunchConfigOrInstance;
undefined, } else {
shellLaunchConfig, instance = this._terminalService.createInstance(
true); terminalFocusContextKey,
configHelper,
undefined,
shellLaunchConfigOrInstance,
true);
}
this._terminalInstances.push(instance); this._terminalInstances.push(instance);
this._initInstanceListeners(instance); this._initInstanceListeners(instance);
this._activeInstanceIndex = 0; this._activeInstanceIndex = 0;
......
...@@ -192,6 +192,15 @@ export interface IShellLaunchConfig { ...@@ -192,6 +192,15 @@ export interface IShellLaunchConfig {
* provided as nothing will be inherited from the process or any configuration. * provided as nothing will be inherited from the process or any configuration.
*/ */
strictEnv?: boolean; strictEnv?: boolean;
/**
* When enabled the terminal will run the process as normal but not be surfaced to the user
* until `Terminal.show` is called. The typical usage for this is when you need to run
* something that may need interactivity but only want to tell the user about it when
* interaction is needed. Note that the terminals will still be exposed to all extensions
* as normal.
*/
runInBackground?: boolean;
} }
export interface ITerminalService { export interface ITerminalService {
......
...@@ -30,6 +30,7 @@ export abstract class TerminalService implements ITerminalService { ...@@ -30,6 +30,7 @@ export abstract class TerminalService implements ITerminalService {
protected _findWidgetVisible: IContextKey<boolean>; protected _findWidgetVisible: IContextKey<boolean>;
protected _terminalContainer: HTMLElement; protected _terminalContainer: HTMLElement;
protected _terminalTabs: ITerminalTab[] = []; protected _terminalTabs: ITerminalTab[] = [];
protected _backgroundedTerminalInstances: ITerminalInstance[] = [];
protected get _terminalInstances(): ITerminalInstance[] { protected get _terminalInstances(): ITerminalInstance[] {
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]); return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
} }
...@@ -103,6 +104,7 @@ export abstract class TerminalService implements ITerminalService { ...@@ -103,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;
protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void;
public abstract refreshActiveTab(): void; public abstract refreshActiveTab(): void;
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
...@@ -222,6 +224,15 @@ export abstract class TerminalService implements ITerminalService { ...@@ -222,6 +224,15 @@ export abstract class TerminalService implements ITerminalService {
} }
public getInstanceFromId(terminalId: number): ITerminalInstance { public getInstanceFromId(terminalId: number): ITerminalInstance {
let bgIndex = -1;
this._backgroundedTerminalInstances.forEach((terminalInstance, i) => {
if (terminalInstance.id === terminalId) {
bgIndex = i;
}
});
if (bgIndex !== -1) {
return this._backgroundedTerminalInstances[bgIndex];
}
return this.terminalInstances[this._getIndexFromId(terminalId)]; return this.terminalInstances[this._getIndexFromId(terminalId)];
} }
...@@ -230,6 +241,11 @@ export abstract class TerminalService implements ITerminalService { ...@@ -230,6 +241,11 @@ export abstract class TerminalService implements ITerminalService {
} }
public setActiveInstance(terminalInstance: ITerminalInstance): void { public setActiveInstance(terminalInstance: ITerminalInstance): void {
// If this was a runInBackground terminal created by the API this was triggered by show,
// in which case we need to create the terminal tab
if (terminalInstance.shellLaunchConfig.runInBackground) {
this._showBackgroundTerminal(terminalInstance);
}
this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.id)); this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.id));
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册