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

import termJs = require('term.js');
import fs = require('fs');
import {fork, Terminal} from 'pty.js';
9
import platform = require('vs/base/common/platform');
D
Daniel Imms 已提交
10 11
import {TPromise} from 'vs/base/common/winjs.base';
import {Builder, Dimension} from 'vs/base/browser/builder';
12
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
D
Daniel Imms 已提交
13
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
14
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
15
import {ITerminalConfiguration, TERMINAL_PANEL_ID} from 'vs/workbench/parts/terminal/common/terminal';
D
Daniel Imms 已提交
16
import {Panel} from 'vs/workbench/browser/panel';
17 18
import {DomScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElement';
import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
D
Daniel Imms 已提交
19 20 21 22 23 24 25 26 27 28 29 30

const TERMINAL_CHAR_WIDTH = 8;
const TERMINAL_CHAR_HEIGHT = 18;

export class TerminalPanel extends Panel {

	private ptyProcess: Terminal;
	private parentDomElement: HTMLElement;
	private terminal;
	private terminalDomElement: HTMLDivElement;

	constructor(
31
		@IConfigurationService private configurationService: IConfigurationService,
32 33
		@ITelemetryService telemetryService: ITelemetryService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
D
Daniel Imms 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47
	) {
		super(TERMINAL_PANEL_ID, telemetryService);
	}

	public layout(dimension: Dimension): void {
		let cols = Math.floor(this.parentDomElement.offsetWidth / TERMINAL_CHAR_WIDTH);
		let rows = Math.floor(this.parentDomElement.offsetHeight / TERMINAL_CHAR_HEIGHT);
		this.terminal.resize(cols, rows);
		this.ptyProcess.resize(cols, rows);
	}

	public create(parent: Builder): TPromise<void> {
		super.create(parent);

48 49 50 51 52 53 54 55
		this.parentDomElement = parent.getHTMLElement();
		this.createTerminal();

		return TPromise.as(null);
	}

	private createTerminal(): void {
		this.parentDomElement.innerHTML = '';
56
		this.ptyProcess = fork(this.getShell(), [], {
D
Daniel Imms 已提交
57
			name: fs.existsSync('/usr/share/terminfo/x/xterm-256color') ? 'xterm-256color' : 'xterm',
D
Daniel Imms 已提交
58
			cwd: this.contextService.getWorkspace() ? this.contextService.getWorkspace().resource.fsPath : process.env.HOME
D
Daniel Imms 已提交
59 60 61
		});
		this.terminalDomElement = document.createElement('div');
		this.parentDomElement.classList.add('integrated-terminal');
62 63 64 65 66 67
		let terminalScrollable = new DomScrollableElement(this.terminalDomElement, {
			canUseTranslate3d: false,
			horizontal: ScrollbarVisibility.Hidden,
			vertical: ScrollbarVisibility.Auto
		});
		//let terminalContainer = new ScrollableElement(this.terminalDomElement, terminalScrollable, { horizontal: 'hidden', vertical: 'auto' });
D
Daniel Imms 已提交
68
		this.terminal = termJs({
D
Daniel Imms 已提交
69
			cursorBlink: false // term.js' blinking cursor breaks selection
D
Daniel Imms 已提交
70
		});
D
Daniel Imms 已提交
71 72 73 74 75 76 77 78

		this.ptyProcess.on('data', (data) => {
			this.terminal.write(data);
		});
		this.terminal.on('data', (data) => {
			this.ptyProcess.write(data);
			return false;
		});
79 80 81 82 83 84 85
		this.ptyProcess.on('exit', (data) => {
			this.terminal.destroy();
			// TODO: When multiple terminals are supported this should do something smarter. There is
			// also a weird bug here at leasy on Ubuntu 15.10 where the new terminal text does not
			// repaint correctly.
			this.createTerminal();
		});
86 87 88 89 90 91 92
		this.parentDomElement.addEventListener('mousedown', (event) => {
			// Drop selection and focus terminal on Linux to enable middle button paste when click
			// occurs on the selection itself.
			if (event.which === 2 && platform.isLinux) {
				this.focusTerminal(true);
			}
		});
93 94 95 96 97
		this.parentDomElement.addEventListener('mouseup', (event) => {
			if (event.which !== 3) {
				this.focusTerminal();
			}
		});
D
Daniel Imms 已提交
98 99

		this.terminal.open(this.terminalDomElement);
100
		this.parentDomElement.appendChild(terminalScrollable.getDomNode());
D
Daniel Imms 已提交
101

102 103
		let config = this.configurationService.getConfiguration<ITerminalConfiguration>();
		this.terminalDomElement.style.fontFamily = config.integratedTerminal.fontFamily;
104
		this.terminal.colors = this.getTerminalColors();
D
Daniel Imms 已提交
105
	}
106

107
	private focusTerminal(force?: boolean): void {
108
		let text = window.getSelection().toString();
109
		if (!text || force) {
110 111 112 113 114 115 116
			this.terminal.focus();
			if (this.terminal._textarea) {
				this.terminal._textarea.focus();
			}
		}
	}

117 118 119
	private getShell(): string {
		let config = this.configurationService.getConfiguration<ITerminalConfiguration>();
		if (platform.isWindows) {
120
			return config.integratedTerminal.shell.windows;
121
		}
122 123 124 125 126 127
		return config.integratedTerminal.shell.unixLike;
	}

	private getTerminalColors(): string[] {
		let config = this.configurationService.getConfiguration<ITerminalConfiguration>().integratedTerminal.ansiColors;
		let colors = [
D
Daniel Imms 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
			config.black,
			config.red,
			config.green,
			config.yellow,
			config.blue,
			config.magenta,
			config.cyan,
			config.white,
			config.brightBlack,
			config.brightRed,
			config.brightGreen,
			config.brightYellow,
			config.brightBlue,
			config.brightMagenta,
			config.brightCyan,
			config.brightWhite
144 145
		];
		return colors;
146
	}
D
Daniel Imms 已提交
147
}