未验证 提交 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', () => {
const terminal1 = window.createTerminal({ name: 'test' });
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' {
//#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.
*/
......
......@@ -62,7 +62,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// 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 = {
name,
executable: shellPath,
......@@ -71,7 +71,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
waitOnExit,
ignoreConfigurationCwd: true,
env,
strictEnv
strictEnv,
runInBackground
};
const terminal = this.terminalService.createTerminal(shellLaunchConfig);
return Promise.resolve({
......
......@@ -390,7 +390,7 @@ export interface MainThreadProgressShape 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>;
$dispose(terminalId: number): void;
$hide(terminalId: number): void;
......
......@@ -484,7 +484,8 @@ export function createApiFactory(
},
createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
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);
},
......
......@@ -114,9 +114,10 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
cwd?: string | URI,
env?: { [key: string]: string | null },
waitOnExit?: boolean,
strictEnv?: boolean
strictEnv?: boolean,
runInBackground?: boolean
): 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._runQueuedRequests(terminal.id);
});
......@@ -308,7 +309,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
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);
return terminal;
}
......
......@@ -50,6 +50,15 @@ export abstract class TerminalService extends CommonTerminalService implements I
}
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,
this._terminalFocusContextKey,
this.configHelper,
......@@ -68,6 +77,25 @@ export abstract class TerminalService extends CommonTerminalService implements I
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> {
return this.showPanel(false).then(() => {
const panel = this._panelService.getActivePanel() as TerminalPanel;
......
......@@ -225,7 +225,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
terminalFocusContextKey: IContextKey<boolean>,
configHelper: ITerminalConfigHelper,
private _container: HTMLElement,
shellLaunchConfig: IShellLaunchConfig,
shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance,
@ITerminalService private readonly _terminalService: ITerminalService,
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService
) {
......@@ -233,12 +233,17 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this._onDisposed = new Emitter<ITerminalTab>();
this._onInstancesChanged = new Emitter<void>();
const instance = this._terminalService.createInstance(
terminalFocusContextKey,
configHelper,
undefined,
shellLaunchConfig,
true);
let instance: ITerminalInstance;
if ('id' in shellLaunchConfigOrInstance) {
instance = shellLaunchConfigOrInstance;
} else {
instance = this._terminalService.createInstance(
terminalFocusContextKey,
configHelper,
undefined,
shellLaunchConfigOrInstance,
true);
}
this._terminalInstances.push(instance);
this._initInstanceListeners(instance);
this._activeInstanceIndex = 0;
......
......@@ -192,6 +192,15 @@ export interface IShellLaunchConfig {
* provided as nothing will be inherited from the process or any configuration.
*/
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 {
......
......@@ -30,6 +30,7 @@ export abstract class TerminalService implements ITerminalService {
protected _findWidgetVisible: IContextKey<boolean>;
protected _terminalContainer: HTMLElement;
protected _terminalTabs: ITerminalTab[] = [];
protected _backgroundedTerminalInstances: ITerminalInstance[] = [];
protected get _terminalInstances(): ITerminalInstance[] {
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
}
......@@ -103,6 +104,7 @@ export abstract class TerminalService implements ITerminalService {
protected abstract _getWslPath(path: string): Promise<string>;
protected abstract _getWindowsBuildNumber(): number;
protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void;
public abstract refreshActiveTab(): void;
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
......@@ -222,6 +224,15 @@ export abstract class TerminalService implements ITerminalService {
}
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)];
}
......@@ -230,6 +241,11 @@ export abstract class TerminalService implements ITerminalService {
}
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));
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册