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

6
import lifecycle = require('vs/base/common/lifecycle');
7
import platform = require('vs/base/common/platform');
8
import DOM = require('vs/base/browser/dom');
D
Daniel Imms 已提交
9 10
import {TPromise} from 'vs/base/common/winjs.base';
import {Builder, Dimension} from 'vs/base/browser/builder';
11
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
D
Daniel Imms 已提交
12
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
13
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
14
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
15
import {ITerminalService, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/electron-browser/terminal';
D
Daniel Imms 已提交
16
import {Panel} from 'vs/workbench/browser/panel';
17 18
import {TerminalConfigHelper} from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
import {TerminalInstance} from 'vs/workbench/parts/terminal/electron-browser/terminalInstance';
D
Daniel Imms 已提交
19 20 21

export class TerminalPanel extends Panel {

22 23 24
	private toDispose: lifecycle.IDisposable[] = [];
	private terminalInstances: TerminalInstance[] = [];

D
Daniel Imms 已提交
25
	private parentDomElement: HTMLElement;
26
	private themeStyleElement: HTMLElement;
27
	private configurationHelper: TerminalConfigHelper;
28
	private activeTerminalIndex: number;
D
Daniel Imms 已提交
29 30

	constructor(
31
		@IConfigurationService private configurationService: IConfigurationService,
32
		@ITelemetryService telemetryService: ITelemetryService,
33
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
34 35
		@ITerminalService private terminalService: ITerminalService,
		@IThemeService private themeService: IThemeService
D
Daniel Imms 已提交
36 37 38 39
	) {
		super(TERMINAL_PANEL_ID, telemetryService);
	}

40
	public layout(dimension?: Dimension): void {
41 42
		if (this.terminalInstances.length > 0) {
			this.terminalInstances[this.activeTerminalIndex].layout(dimension);
43
		}
D
Daniel Imms 已提交
44 45 46 47
	}

	public create(parent: Builder): TPromise<void> {
		super.create(parent);
48
		this.parentDomElement = parent.getHTMLElement();
49 50
		this.themeStyleElement = document.createElement('style');
		this.parentDomElement.appendChild(this.themeStyleElement);
51
		this.configurationHelper = new TerminalConfigHelper(platform.platform, this.configurationService, this.parentDomElement);
52
		this.toDispose.push(DOM.addDisposableListener(this.parentDomElement, 'wheel', (event: WheelEvent) => {
53
			this.terminalInstances[this.activeTerminalIndex].dispatchEvent(new WheelEvent(event.type, event));
54
		}));
55

56
		return this.createTerminal();
57 58
	}

59 60 61
	public createNewTerminalInstance() : TPromise<void> {
		return this.createTerminal().then(() => {
			this.updateFont();
D
Daniel Imms 已提交
62
			this.focus();
63 64 65
		});
	}

66
	public setVisible(visible: boolean): TPromise<void> {
67
		if (visible) {
68
			if (this.terminalInstances.length > 0) {
69 70 71 72 73 74 75 76 77 78
				this.updateFont();
				this.updateTheme();
			} else {
				return super.setVisible(visible).then(() => {
					this.createTerminal();
					this.updateFont();
					this.updateTheme();
					return Promise.resolve(void 0);
				});
			}
79 80 81 82
		}
		return super.setVisible(visible);
	}

83 84
	private createTerminal(): TPromise<void> {
		return new TPromise<void>(resolve => {
85
			this.terminalInstances.push(new TerminalInstance(this.configurationHelper.getShell(), this.parentDomElement, this.contextService, this.terminalService, this.onTerminalInstanceExit.bind(this)));
86
			this.setActiveTerminal(this.terminalInstances.length - 1);
87 88
			this.toDispose.push(this.themeService.onDidThemeChange(this.updateTheme.bind(this)));
			this.toDispose.push(this.configurationService.onDidUpdateConfiguration(this.updateFont.bind(this)));
89
			resolve(void 0);
D
Daniel Imms 已提交
90 91
		});
	}
92

93 94 95 96 97 98 99
	private setActiveTerminal(index: number) {
		this.activeTerminalIndex = index;
		this.terminalInstances.forEach((terminalInstance, i) => {
			terminalInstance.toggleVisibility(i === this.activeTerminalIndex);
		});
	}

100
	private onTerminalInstanceExit(terminalInstance: TerminalInstance): void {
101 102 103 104 105 106 107 108 109
		for (var i = 0; i < this.terminalInstances.length; i++) {
			if (this.terminalInstances[i] === terminalInstance) {
				if (this.activeTerminalIndex === i) {
					this.activeTerminalIndex = -1;
				} else if (this.activeTerminalIndex > i) {
					this.activeTerminalIndex--;
				}
				this.terminalInstances.splice(i, 1);
			}
110 111 112 113 114 115 116 117
		}
		this.terminalService.toggle();
	}

	private updateTheme(themeId?: string): void {
		if (!themeId) {
			themeId = this.themeService.getTheme();
		}
D
Daniel Imms 已提交
118 119 120 121
		let theme = this.configurationHelper.getTheme(themeId);

		let css = '';
		theme.forEach((color: string, index: number) => {
122
			// TODO: The classes could probably be reduced, it's so long to beat the specificity of the general rule.
D
Daniel Imms 已提交
123
			let rgba = this.convertHexCssColorToRgba(color, 0.996);
124 125 126 127
			css += `.monaco-workbench .integrated-terminal .terminal .xterm-color-${index} { color: ${color}; }` +
				`.monaco-workbench .integrated-terminal .terminal .xterm-color-${index}::selection { background-color: ${rgba}; }` +
				`.monaco-workbench .integrated-terminal .terminal .xterm-bg-color-${index} { background-color: ${color}; }` +
				`.monaco-workbench .integrated-terminal .terminal .xterm-bg-color-${index}::selection { color: ${color}; }`;
D
Daniel Imms 已提交
128 129
		});

130
		this.themeStyleElement.innerHTML = css;
D
Daniel Imms 已提交
131 132
	}

D
Daniel Imms 已提交
133 134 135
	/**
	 * Converts a CSS hex color (#rrggbb) to a CSS rgba color (rgba(r, g, b, a)).
	 */
D
Daniel Imms 已提交
136 137 138 139 140
	private convertHexCssColorToRgba(hex: string, alpha: number): string {
		let r = parseInt(hex.substr(1, 2), 16);
		let g = parseInt(hex.substr(3, 2), 16);
		let b = parseInt(hex.substr(5, 2), 16);
		return `rgba(${r}, ${g}, ${b}, ${alpha})`;
141 142
	}

143
	private updateFont(): void {
144
		if (this.terminalInstances.length === 0) {
145 146
			return;
		}
147
		this.terminalInstances[this.activeTerminalIndex].setFont(this.configurationHelper.getFont());
148
		this.layout(new Dimension(this.parentDomElement.offsetWidth, this.parentDomElement.offsetHeight));
149 150
	}

151

152
	public focus(): void {
153 154
		if (this.terminalInstances.length > 0) {
			this.terminalInstances[this.activeTerminalIndex].focus(true);
155 156 157
		}
	}

158 159
	public dispose(): void {
		this.toDispose = lifecycle.dispose(this.toDispose);
160 161
		while (this.terminalInstances.length > 0) {
			this.terminalInstances.pop().dispose();
162
		}
163 164
		super.dispose();
	}
D
Daniel Imms 已提交
165
}