| | |
| | |
| | |
| | |
| | |
| |
|
| | 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); |
| |
|
| | |
| | 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); |
| |
|
| | |
| | this._isReady = false; |
| |
|
| | |
| | this._deferreds = []; |
| |
|
| | |
| | this._agent = new WindowsPtyAgent(file, args, parsedEnv, cwd, this._cols, this._rows, false, opt.useConpty, opt.conptyInheritCursor); |
| | this._socket = this._agent.outSocket; |
| |
|
| | |
| | this._pid = this._agent.innerPid; |
| | this._fd = this._agent.fd; |
| | this._pty = this._agent.pty; |
| |
|
| | |
| | |
| | this._socket.on('ready_datapipe', () => { |
| |
|
| | |
| | ['connect', 'data', 'end', 'timeout', 'drain'].forEach(event => { |
| | this._socket.on(event, () => { |
| |
|
| | |
| | if (!this._isReady && event === 'data') { |
| |
|
| | |
| | |
| | this._isReady = true; |
| |
|
| | |
| | this._deferreds.forEach(fn => { |
| | |
| | |
| | |
| | |
| | fn.run(); |
| | }); |
| |
|
| | |
| | this._deferreds = []; |
| |
|
| | } |
| | }); |
| | }); |
| |
|
| | |
| | this._socket.on('error', err => { |
| | |
| | this._close(); |
| |
|
| | |
| | |
| | |
| | |
| | if ((<any>err).code) { |
| | if (~(<any>err).code.indexOf('errno 5') || ~(<any>err).code.indexOf('EIO')) return; |
| | } |
| |
|
| | |
| | if (this.listeners('error').length < 2) { |
| | throw err; |
| | } |
| | }); |
| |
|
| | |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | public static open(options?: IPtyOpenOptions): void { |
| | throw new Error('open() not supported on windows, use Fork() instead.'); |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | 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 (this._isReady) { |
| | deferredFn.call(this, arg); |
| | return; |
| | } |
| |
|
| | |
| | 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'); } |
| | } |
| |
|