Skip to content

Commit

Permalink
Merge pull request #283 from Microsoft/282_events
Browse files Browse the repository at this point in the history
New events API
  • Loading branch information
Tyriar authored Apr 28, 2019
2 parents b1201e3 + 7287e06 commit bed37ce
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 20 deletions.
25 changes: 9 additions & 16 deletions examples/fork/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,27 @@
var os = require('os');
var pty = require('../..');

var shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
var isWindows = os.platform() === 'win32';
var shell = isWindows ? 'powershell.exe' : 'bash';

var ptyProcess = pty.spawn(shell, [], {
name: 'xterm-256color',
cols: 80,
rows: 26,
cwd: os.platform() === 'win32' ? process.env.USERPROFILE : process.env.HOME,
env: Object.assign({ TEST: "abc" }, process.env),
cwd: isWindows ? process.env.USERPROFILE : process.env.HOME,
env: Object.assign({ TEST: "Environment vars work" }, process.env),
experimentalUseConpty: true
});

ptyProcess.on('data', function(data) {
// console.log(data);
process.stdout.write(data);
});
ptyProcess.onData(data => process.stdout.write(data));

ptyProcess.write('dir\r');
// ptyProcess.write('ls\r');
ptyProcess.write(isWindows ? 'dir\r' : 'ls\r');

setTimeout(() => {
ptyProcess.resize(30, 19);
ptyProcess.write(shell === 'powershell.exe' ? '$Env:TEST\r' : 'echo %TEST%\r');
ptyProcess.write(isWindows ? '$Env:TEST\r' : 'echo $TEST\r');
}, 2000);

process.on('exit', () => {
ptyProcess.kill();
});
process.on('exit', () => ptyProcess.kill());

setTimeout(() => {
process.exit();
}, 4000);
setTimeout(() => process.exit(), 4000);
4 changes: 1 addition & 3 deletions examples/killDeepTree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ var ptyProcess = pty.spawn(shell, [], {
env: process.env
});

ptyProcess.on('data', function(data) {
process.stdout.write(data);
});
ptyProcess.onData((data) => process.stdout.write(data));

ptyProcess.write('start notepad\r');
ptyProcess.write('npm start\r');
Expand Down
30 changes: 30 additions & 0 deletions src/eventEmitter2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright (c) 2019, Microsoft Corporation (MIT License).
*/

import * as assert from 'assert';
import { EventEmitter2 } from './eventEmitter2';

describe('EventEmitter2', () => {
it('should fire listeners multiple times', () => {
const order: string[] = [];
const emitter = new EventEmitter2<number>();
emitter.event(data => order.push(data + 'a'));
emitter.event(data => order.push(data + 'b'));
emitter.fire(1);
emitter.fire(2);
assert.deepEqual(order, [ '1a', '1b', '2a', '2b' ]);
});

it('should not fire listeners once disposed', () => {
const order: string[] = [];
const emitter = new EventEmitter2<number>();
emitter.event(data => order.push(data + 'a'));
const disposeB = emitter.event(data => order.push(data + 'b'));
emitter.event(data => order.push(data + 'c'));
emitter.fire(1);
disposeB.dispose();
emitter.fire(2);
assert.deepEqual(order, [ '1a', '1b', '1c', '2a', '2c' ]);
});
});
48 changes: 48 additions & 0 deletions src/eventEmitter2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright (c) 2019, Microsoft Corporation (MIT License).
*/

import { IDisposable } from './types';

interface IListener<T> {
(e: T): void;
}

export interface IEvent<T> {
(listener: (e: T) => any): IDisposable;
}

export class EventEmitter2<T> {
private _listeners: IListener<T>[] = [];
private _event?: IEvent<T>;

public get event(): IEvent<T> {
if (!this._event) {
this._event = (listener: (e: T) => any) => {
this._listeners.push(listener);
const disposable = {
dispose: () => {
for (let i = 0; i < this._listeners.length; i++) {
if (this._listeners[i] === listener) {
this._listeners.splice(i, 1);
return;
}
}
}
};
return disposable;
};
}
return this._event;
}

public fire(data: T): void {
const queue: IListener<T>[] = [];
for (let i = 0; i < this._listeners.length; i++) {
queue.push(this._listeners[i]);
}
for (let i = 0; i < queue.length; i++) {
queue[i].call(undefined, data);
}
}
}
13 changes: 12 additions & 1 deletion src/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
* Copyright (c) 2018, Microsoft Corporation (MIT License).
*/

import * as path from 'path';
import { Socket } from 'net';
import { EventEmitter } from 'events';
import { ITerminal, IPtyForkOptions } from './interfaces';
import { EventEmitter2, IEvent } from './eventEmitter2';
import { IExitEvent } from './types';

export const DEFAULT_COLS: number = 80;
export const DEFAULT_ROWS: number = 24;
Expand All @@ -28,6 +29,11 @@ export abstract class Terminal implements ITerminal {

protected _internalee: EventEmitter;

private _onData = new EventEmitter2<string>();
public get onData(): IEvent<string> { return this._onData.event; }
private _onExit = new EventEmitter2<IExitEvent>();
public get onExit(): IEvent<IExitEvent> { return this._onExit.event; }

public get pid(): number { return this._pid; }

constructor(opt?: IPtyForkOptions) {
Expand All @@ -50,6 +56,11 @@ export abstract class Terminal implements ITerminal {
this._checkType('encoding', opt.encoding ? opt.encoding : null, 'string');
}

protected _forwardEvents(): void {
this.on('data', e => this._onData.fire(e));
this.on('exit', (exitCode, signal) => this._onExit.fire({ exitCode, signal }));
}

private _checkType(name: string, value: any, type: string): void {
if (value && typeof value !== type) {
throw new Error(`${name} must be a ${type} (not a ${typeof value})`);
Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,12 @@
*/

export type ArgvOrCommandLine = string[] | string;

export interface IExitEvent {
exitCode: number;
signal: number | undefined;
}

export interface IDisposable {
dispose(): void;
}
2 changes: 2 additions & 0 deletions src/unixTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ export class UnixTerminal extends Terminal {
this._close();
this.emit('close');
});

this._forwardEvents();
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/windowsTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export class WindowsTerminal extends Terminal {

this._readable = true;
this._writable = true;

this._forwardEvents();
}

/**
Expand Down
30 changes: 30 additions & 0 deletions typings/node-pty.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,24 @@ declare module 'node-pty' {
*/
process: string;

/**
* Adds an event listener for when a data event fires. This happens when data is returned from
* the pty.
* @returns an `IDisposable` to stop listening.
*/
onData: IEvent<string>;

/**
* Adds an event listener for when an exit event fires. This happens when the pty exits.
* @returns an `IDisposable` to stop listening.
*/
onExit: IEvent<{ exitCode: number, signal?: number }>;

/**
* Adds a listener to the data event, fired when data is returned from the pty.
* @param event The name of the event.
* @param listener The callback function.
* @deprecated Use IPty.onData
*/
on(event: 'data', listener: (data: string) => void): void;

Expand All @@ -62,6 +76,7 @@ declare module 'node-pty' {
* @param event The name of the event.
* @param listener The callback function, exitCode is the exit code of the process and signal is
* the signal that triggered the exit. signal is not supported on Windows.
* @deprecated Use IPty.onExit
*/
on(event: 'exit', listener: (exitCode: number, signal?: number) => void): void;

Expand All @@ -86,4 +101,19 @@ declare module 'node-pty' {
*/
kill(signal?: string): void;
}

/**
* An object that can be disposed via a dispose function.
*/
export interface IDisposable {
dispose(): void;
}

/**
* An event that can be listened to.
* @returns an `IDisposable` to stop listening.
*/
export interface IEvent<T> {
(listener: (e: T) => any): IDisposable;
}
}

0 comments on commit bed37ce

Please sign in to comment.