mainThreadTerminalService.ts 7.5 KB
Newer Older
D
Daniel Imms 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

J
Johannes Rieken 已提交
7
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
8
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest } from 'vs/workbench/parts/terminal/common/terminal';
J
Johannes Rieken 已提交
9
import { TPromise } from 'vs/base/common/winjs.base';
10
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from '../node/extHost.protocol';
11
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
D
Daniel Imms 已提交
12

13
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
14
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
D
Daniel Imms 已提交
15

16
	private _proxy: ExtHostTerminalServiceShape;
17 18
	private _toDispose: IDisposable[] = [];
	private _terminalProcesses: { [id: number]: ITerminalProcessExtHostProxy } = {};
D
Daniel Imms 已提交
19
	private _dataListeners: { [id: number]: IDisposable } = {};
20
	private _rendererDataListeners: { [id: number]: IDisposable } = {};
21

D
Daniel Imms 已提交
22
	constructor(
23
		extHostContext: IExtHostContext,
24
		@ITerminalService private terminalService: ITerminalService
D
Daniel Imms 已提交
25
	) {
26
		this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
27
		this._toDispose.push(terminalService.onInstanceCreated((terminalInstance) => {
D
Daniel Imms 已提交
28
			// Delay this message so the TerminalInstance constructor has a chance to finish and
29 30 31 32
			// return the ID normally to the extension host. The ID that is passed here will be used
			// to register non-extension API terminals in the extension host.
			setTimeout(() => this._onTerminalOpened(terminalInstance), 100);
		}));
33 34
		this._toDispose.push(terminalService.onInstanceDisposed(terminalInstance => this._onTerminalDisposed(terminalInstance)));
		this._toDispose.push(terminalService.onInstanceProcessIdReady(terminalInstance => this._onTerminalProcessIdReady(terminalInstance)));
35
		this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
D
Daniel Imms 已提交
36 37 38 39 40 41

		// Set initial ext host state
		this.terminalService.terminalInstances.forEach(t => {
			this._onTerminalOpened(t);
			t.processReady.then(() => this._onTerminalProcessIdReady(t));
		});
42 43 44 45
	}

	public dispose(): void {
		this._toDispose = dispose(this._toDispose);
46 47 48

		// TODO@Daniel: Should all the previously created terminals be disposed
		// when the extension host process goes down ?
D
Daniel Imms 已提交
49
	}
D
Daniel Imms 已提交
50

51
	public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number> {
52 53 54 55
		const shellLaunchConfig: IShellLaunchConfig = {
			name,
			executable: shellPath,
			args: shellArgs,
D
Daniel Imms 已提交
56
			cwd,
57
			waitOnExit,
58 59
			ignoreConfigurationCwd: true,
			env
60
		};
61
		return TPromise.as(this.terminalService.createTerminal(shellLaunchConfig).id);
D
Daniel Imms 已提交
62 63
	}

64 65 66 67
	public $createTerminalRenderer(name: string): TPromise<number> {
		return TPromise.as(this.terminalService.createTerminalRenderer(name).id);
	}

D
Daniel Imms 已提交
68
	public $show(terminalId: number, preserveFocus: boolean): void {
D
Daniel Imms 已提交
69
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
70 71 72 73
		if (terminalInstance) {
			this.terminalService.setActiveInstance(terminalInstance);
			this.terminalService.showPanel(!preserveFocus);
		}
D
Daniel Imms 已提交
74
	}
D
Daniel Imms 已提交
75

D
Daniel Imms 已提交
76
	public $hide(terminalId: number): void {
77
		if (this.terminalService.getActiveInstance().id === terminalId) {
D
Daniel Imms 已提交
78
			this.terminalService.hidePanel();
79
		}
D
Daniel Imms 已提交
80 81 82
	}

	public $dispose(terminalId: number): void {
D
Daniel Imms 已提交
83
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
84 85 86
		if (terminalInstance) {
			terminalInstance.dispose();
		}
D
Daniel Imms 已提交
87 88
	}

89
	public $terminalRendererWrite(terminalId: number, text: string): void {
D
Daniel Imms 已提交
90
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
91 92 93 94 95
		if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
			terminalInstance.write(text);
		}
	}

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	public $terminalRendererSetName(terminalId: number, name: string): void {
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
		if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
			terminalInstance.setTitle(name, false);
		}
	}

	public $terminalRendererRegisterOnDataListener(terminalId: number): void {
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
		if (terminalInstance) {
			this._rendererDataListeners[terminalId] = terminalInstance.onRendererData(data => this._onTerminalRendererData(terminalId, data));
			terminalInstance.onDisposed(() => delete this._dataListeners[terminalId]);
		}
	}

D
Daniel Imms 已提交
111
	public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
D
Daniel Imms 已提交
112
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
113 114 115
		if (terminalInstance) {
			terminalInstance.sendText(text, addNewLine);
		}
D
Daniel Imms 已提交
116
	}
117

D
Daniel Imms 已提交
118
	public $registerOnDataListener(terminalId: number): void {
D
Daniel Imms 已提交
119
		const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
D
Daniel Imms 已提交
120 121
		if (terminalInstance) {
			this._dataListeners[terminalId] = terminalInstance.onData(data => this._onTerminalData(terminalId, data));
122
			terminalInstance.onDisposed(() => delete this._dataListeners[terminalId]);
D
Daniel Imms 已提交
123 124 125 126 127 128 129
		}
	}

	private _onTerminalData(terminalId: number, data: string): void {
		this._proxy.$acceptTerminalProcessData(terminalId, data);
	}

130 131 132 133
	private _onTerminalRendererData(terminalId: number, data: string): void {
		this._proxy.$acceptTerminalRendererData(terminalId, data);
	}

134
	private _onTerminalDisposed(terminalInstance: ITerminalInstance): void {
135 136
		this._proxy.$acceptTerminalClosed(terminalInstance.id);
	}
137

138 139 140 141
	private _onTerminalOpened(terminalInstance: ITerminalInstance): void {
		this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title);
	}

142 143 144
	private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void {
		this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
	}
145

146 147 148 149 150 151 152 153 154 155
	private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
		this._terminalProcesses[request.proxy.terminalId] = request.proxy;
		const shellLaunchConfigDto: ShellLaunchConfigDto = {
			name: request.shellLaunchConfig.name,
			executable: request.shellLaunchConfig.executable,
			args: request.shellLaunchConfig.args,
			cwd: request.shellLaunchConfig.cwd,
			env: request.shellLaunchConfig.env
		};
		this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.cols, request.rows);
156 157 158
		request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
		request.proxy.onResize((cols, rows) => this._proxy.$acceptProcessResize(request.proxy.terminalId, cols, rows));
		request.proxy.onShutdown(() => this._proxy.$acceptProcessShutdown(request.proxy.terminalId));
159 160 161 162 163 164 165 166 167 168 169 170 171
	}

	public $sendProcessTitle(terminalId: number, title: string): void {
		this._terminalProcesses[terminalId].emitTitle(title);
	}

	public $sendProcessData(terminalId: number, data: string): void {
		this._terminalProcesses[terminalId].emitData(data);
	}

	public $sendProcessPid(terminalId: number, pid: number): void {
		this._terminalProcesses[terminalId].emitPid(pid);
	}
D
Daniel Imms 已提交
172 173 174

	public $sendProcessExit(terminalId: number, exitCode: number): void {
		this._terminalProcesses[terminalId].emitExit(exitCode);
D
Daniel Imms 已提交
175
		delete this._terminalProcesses[terminalId];
D
Daniel Imms 已提交
176
	}
D
Daniel Imms 已提交
177
}