+++ /dev/null
-/**
- * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)
- * Copyright (c) 2016, Daniel Imms (MIT License).
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
- */
-
-import { Socket } from 'net';
-import { Terminal, DEFAULT_COLS, DEFAULT_ROWS } from './terminal';
-import { WindowsPtyAgent } from './windowsPtyAgent';
-import { IPtyOpenOptions, IWindowsPtyForkOptions } from './interfaces';
-import { ArgvOrCommandLine } from './types';
-import { assign } from './utils';
-
-const DEFAULT_FILE = 'cmd.exe';
-const DEFAULT_NAME = 'Windows Shell';
-
-export class WindowsTerminal extends Terminal {
- private _isReady: boolean;
- private _deferreds: any[];
- private _agent: WindowsPtyAgent;
-
- constructor(file?: string, args?: ArgvOrCommandLine, opt?: IWindowsPtyForkOptions) {
- super(opt);
-
- // Initialize arguments
- args = args || [];
- file = file || DEFAULT_FILE;
- opt = opt || {};
- opt.env = opt.env || process.env;
-
- if (opt.encoding) {
- console.warn('Setting encoding on Windows is not supported');
- }
-
- const env = assign({}, opt.env);
- this._cols = opt.cols || DEFAULT_COLS;
- this._rows = opt.rows || DEFAULT_ROWS;
- const cwd = opt.cwd || process.cwd();
- const name = opt.name || env.TERM || DEFAULT_NAME;
- const parsedEnv = this._parseEnv(env);
-
- // If the terminal is ready
- this._isReady = false;
-
- // Functions that need to run after `ready` event is emitted.
- this._deferreds = [];
-
- // Create new termal.
- this._agent = new WindowsPtyAgent(file, args, parsedEnv, cwd, this._cols, this._rows, false, opt.useConpty, opt.conptyInheritCursor);
- this._socket = this._agent.outSocket;
-
- // Not available until `ready` event emitted.
- this._pid = this._agent.innerPid;
- this._fd = this._agent.fd;
- this._pty = this._agent.pty;
-
- // The forked windows terminal is not available until `ready` event is
- // emitted.
- this._socket.on('ready_datapipe', () => {
-
- // These events needs to be forwarded.
- ['connect', 'data', 'end', 'timeout', 'drain'].forEach(event => {
- this._socket.on(event, () => {
-
- // Wait until the first data event is fired then we can run deferreds.
- if (!this._isReady && event === 'data') {
-
- // Terminal is now ready and we can avoid having to defer method
- // calls.
- this._isReady = true;
-
- // Execute all deferred methods
- this._deferreds.forEach(fn => {
- // NB! In order to ensure that `this` has all its references
- // updated any variable that need to be available in `this` before
- // the deferred is run has to be declared above this forEach
- // statement.
- fn.run();
- });
-
- // Reset
- this._deferreds = [];
-
- }
- });
- });
-
- // Shutdown if `error` event is emitted.
- this._socket.on('error', err => {
- // Close terminal session.
- this._close();
-
- // EIO, happens when someone closes our child process: the only process
- // in the terminal.
- // node < 0.6.14: errno 5
- // node >= 0.6.14: read EIO
- if ((<any>err).code) {
- if (~(<any>err).code.indexOf('errno 5') || ~(<any>err).code.indexOf('EIO')) return;
- }
-
- // Throw anything else.
- if (this.listeners('error').length < 2) {
- throw err;
- }
- });
-
- // Cleanup after the socket is closed.
- this._socket.on('close', () => {
- this.emit('exit', this._agent.exitCode);
- this._close();
- });
-
- });
-
- this._file = file;
- this._name = name;
-
- this._readable = true;
- this._writable = true;
-
- this._forwardEvents();
- }
-
- protected _write(data: string): void {
- this._defer(this._doWrite, data);
- }
-
- private _doWrite(data: string): void {
- this._agent.inSocket.write(data);
- }
-
- /**
- * openpty
- */
-
- public static open(options?: IPtyOpenOptions): void {
- throw new Error('open() not supported on windows, use Fork() instead.');
- }
-
- /**
- * TTY
- */
-
- public resize(cols: number, rows: number): void {
- if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
- throw new Error('resizing must be done using positive cols and rows');
- }
- this._defer(() => {
- this._agent.resize(cols, rows);
- this._cols = cols;
- this._rows = rows;
- });
- }
-
- public destroy(): void {
- this._defer(() => {
- this.kill();
- });
- }
-
- public kill(signal?: string): void {
- this._defer(() => {
- if (signal) {
- throw new Error('Signals not supported on windows.');
- }
- this._close();
- this._agent.kill();
- });
- }
-
- private _defer<A extends any>(deferredFn: (arg?: A) => void, arg?: A): void {
- // If the terminal is ready, execute.
- if (this._isReady) {
- deferredFn.call(this, arg);
- return;
- }
-
- // Queue until terminal is ready.
- this._deferreds.push({
- run: () => deferredFn.call(this, arg)
- });
- }
-
- public get process(): string { return this._name; }
- public get master(): Socket { throw new Error('master is not supported on Windows'); }
- public get slave(): Socket { throw new Error('slave is not supported on Windows'); }
-}