mainThreadTerminalService.ts 6.6 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

D
Daniel Imms 已提交
21
	constructor(
22
		extHostContext: IExtHostContext,
23
		@ITerminalService private terminalService: ITerminalService
D
Daniel Imms 已提交
24
	) {
25
		this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
26
		this._toDispose.push(terminalService.onInstanceCreated((terminalInstance) => {
D
Daniel Imms 已提交
27
			// Delay this message so the TerminalInstance constructor has a chance to finish and
28 29 30 31
			// 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);
		}));
32 33
		this._toDispose.push(terminalService.onInstanceDisposed(terminalInstance => this._onTerminalDisposed(terminalInstance)));
		this._toDispose.push(terminalService.onInstanceProcessIdReady(terminalInstance => this._onTerminalProcessIdReady(terminalInstance)));
34
		this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
D
Daniel Imms 已提交
35 36 37 38 39 40

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

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

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

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

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

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

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

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

88 89 90 91 92 93 94
	public $write(terminalId: number, text: string): void {
		let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
		if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
			terminalInstance.write(text);
		}
	}

D
Daniel Imms 已提交
95
	public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
96 97 98 99
		let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
		if (terminalInstance) {
			terminalInstance.sendText(text, addNewLine);
		}
D
Daniel Imms 已提交
100
	}
101

D
Daniel Imms 已提交
102 103 104 105 106 107 108 109 110 111 112 113
	public $registerOnDataListener(terminalId: number): void {
		let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
		if (terminalInstance) {
			this._dataListeners[terminalId] = terminalInstance.onData(data => this._onTerminalData(terminalId, data));
			terminalInstance.onDisposed(instance => delete this._dataListeners[terminalId]);
		}
	}

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

114
	private _onTerminalDisposed(terminalInstance: ITerminalInstance): void {
115 116
		this._proxy.$acceptTerminalClosed(terminalInstance.id);
	}
117

118 119 120 121
	private _onTerminalOpened(terminalInstance: ITerminalInstance): void {
		this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title);
	}

122 123 124
	private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void {
		this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
	}
125

126 127 128 129 130 131 132 133 134 135
	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);
136 137 138
		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));
139 140 141 142 143 144 145 146 147 148 149 150 151
	}

	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 已提交
152 153 154

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