mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #3223 from jerch/simplify_handler_interface
cleanup parser handler interface
This commit is contained in:
+245
-173
File diff suppressed because it is too large
Load Diff
@@ -61,11 +61,12 @@ class TestHandler implements IDcsHandler {
|
||||
public put(data: Uint32Array, start: number, end: number): void {
|
||||
this.output.push([this.msg, 'PUT', utf32ToString(data, start, end)]);
|
||||
}
|
||||
public unhook(success: boolean): void | boolean {
|
||||
public unhook(success: boolean): boolean {
|
||||
this.output.push([this.msg, 'UNHOOK', success]);
|
||||
if (this.returnFalse) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ describe('DcsParser', () => {
|
||||
});
|
||||
describe('handler registration', () => {
|
||||
it('setDcsHandler', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -100,7 +101,7 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('clearDcsHandler', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.clearHandler(identifier({intermediates: '+', final: 'p'}));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
@@ -117,8 +118,8 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('addDcsHandler', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.addHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2'));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2'));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -137,8 +138,8 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('addDcsHandler with return false', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.addHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -157,8 +158,8 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('dispose handlers', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
const dispo = parser.addHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
dispo.dispose();
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
@@ -176,7 +177,7 @@ describe('DcsParser', () => {
|
||||
});
|
||||
describe('DcsHandlerFactory', () => {
|
||||
it('should be called once on end(true)', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -186,7 +187,7 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, [[[1, 2, 3], 'Here comes the mouse!']]);
|
||||
});
|
||||
it('should not be called on end(false)', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -196,8 +197,8 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, []);
|
||||
});
|
||||
it('should be disposable', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push(['one', params.toArray(), data])));
|
||||
const dispo = parser.addHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push(['two', params.toArray(), data])));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['one', params.toArray(), data]); return true; }));
|
||||
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['two', params.toArray(), data]); return true; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -215,8 +216,8 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!'], ['one', [1, 2, 3], 'some other data']]);
|
||||
});
|
||||
it('should respect return false', () => {
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push(['one', params.toArray(), data])));
|
||||
parser.addHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['two', params.toArray(), data]); return false; }));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['one', params.toArray(), data]); return true; }));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['two', params.toArray(), data]); return false; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -227,7 +228,7 @@ describe('DcsParser', () => {
|
||||
});
|
||||
it('should work up to payload limit', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
const data = toUtf32('A'.repeat(1000));
|
||||
for (let i = 0; i < PAYLOAD_LIMIT; i += 1000) {
|
||||
@@ -238,7 +239,7 @@ describe('DcsParser', () => {
|
||||
});
|
||||
it('should abort for payload limit +1', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('A'.repeat(1000));
|
||||
for (let i = 0; i < PAYLOAD_LIMIT; i += 1000) {
|
||||
|
||||
@@ -20,9 +20,10 @@ export class DcsParser implements IDcsParser {
|
||||
public dispose(): void {
|
||||
this._handlers = Object.create(null);
|
||||
this._handlerFb = () => {};
|
||||
this._active = EMPTY_HANDLERS;
|
||||
}
|
||||
|
||||
public addHandler(ident: number, handler: IDcsHandler): IDisposable {
|
||||
public registerHandler(ident: number, handler: IDcsHandler): IDisposable {
|
||||
if (this._handlers[ident] === undefined) {
|
||||
this._handlers[ident] = [];
|
||||
}
|
||||
@@ -38,10 +39,6 @@ export class DcsParser implements IDcsParser {
|
||||
};
|
||||
}
|
||||
|
||||
public setHandler(ident: number, handler: IDcsHandler): void {
|
||||
this._handlers[ident] = [handler];
|
||||
}
|
||||
|
||||
public clearHandler(ident: number): void {
|
||||
if (this._handlers[ident]) delete this._handlers[ident];
|
||||
}
|
||||
@@ -88,7 +85,7 @@ export class DcsParser implements IDcsParser {
|
||||
} else {
|
||||
let j = this._active.length - 1;
|
||||
for (; j >= 0; j--) {
|
||||
if (this._active[j].unhook(success) !== false) {
|
||||
if (this._active[j].unhook(success)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -103,19 +100,27 @@ export class DcsParser implements IDcsParser {
|
||||
}
|
||||
}
|
||||
|
||||
// predefine empty params as [0] (ZDM)
|
||||
const EMPTY_PARAMS = new Params();
|
||||
EMPTY_PARAMS.addParam(0);
|
||||
|
||||
/**
|
||||
* Convenient class to create a DCS handler from a single callback function.
|
||||
* Note: The payload is currently limited to 50 MB (hardcoded).
|
||||
*/
|
||||
export class DcsHandler implements IDcsHandler {
|
||||
private _data = '';
|
||||
private _params: IParams | undefined;
|
||||
private _params: IParams = EMPTY_PARAMS;
|
||||
private _hitLimit: boolean = false;
|
||||
|
||||
constructor(private _handler: (data: string, params: IParams) => any) {}
|
||||
constructor(private _handler: (data: string, params: IParams) => boolean) {}
|
||||
|
||||
public hook(params: IParams): void {
|
||||
this._params = params.clone();
|
||||
// since we need to preserve params until `unhook`, we have to clone it
|
||||
// (only borrowed from parser and spans multiple parser states)
|
||||
// perf optimization:
|
||||
// clone only, if we have non empty params, otherwise stick with default
|
||||
this._params = (params.length > 1 || params.params[0]) ? params.clone() : EMPTY_PARAMS;
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
}
|
||||
@@ -131,14 +136,14 @@ export class DcsHandler implements IDcsHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public unhook(success: boolean): any {
|
||||
let ret;
|
||||
public unhook(success: boolean): boolean {
|
||||
let ret = false;
|
||||
if (this._hitLimit) {
|
||||
ret = false;
|
||||
} else if (success) {
|
||||
ret = this._handler(this._data, this._params || new Params());
|
||||
ret = this._handler(this._data, this._params);
|
||||
}
|
||||
this._params = undefined;
|
||||
this._params = EMPTY_PARAMS;
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
return ret;
|
||||
|
||||
@@ -41,7 +41,7 @@ class MockOscPutParser implements IOscParser {
|
||||
this._fallback(id, 'END', this.data.slice(this.data.indexOf(';') + 1));
|
||||
}
|
||||
}
|
||||
public addHandler(ident: number, handler: IOscHandler): IDisposable {
|
||||
public registerHandler(ident: number, handler: IOscHandler): IDisposable {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
public setHandler(ident: number, handler: IOscHandler): void {
|
||||
@@ -1206,11 +1206,13 @@ describe('EscapeSequenceParser', function (): void {
|
||||
chai.expect(print).equal('');
|
||||
});
|
||||
it('ESC handler', function (): void {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, function (): void {
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, function (): boolean {
|
||||
esc.push('%G');
|
||||
return true;
|
||||
});
|
||||
parser2.setEscHandler({final: 'E'}, function (): void {
|
||||
parser2.registerEscHandler({final: 'E'}, function (): boolean {
|
||||
esc.push('E');
|
||||
return true;
|
||||
});
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['%G', 'E']);
|
||||
@@ -1226,49 +1228,49 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
describe('ESC custom handlers', () => {
|
||||
it('prevent fallback', () => {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom - %G']);
|
||||
});
|
||||
it('allow fallback', () => {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return false; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return false; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom - %G', 'default - %G']);
|
||||
});
|
||||
it('Multiple custom handlers fallback once', () => {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom2 - %G'); return false; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom2 - %G'); return false; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom2 - %G', 'custom - %G']);
|
||||
});
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom2 - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom2 - %G'); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom2 - %G']);
|
||||
});
|
||||
it('Execution order should go from latest handler down to the original', () => {
|
||||
const order: number[] = [];
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { order.push(1); });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { order.push(2); return false; });
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { order.push(3); return false; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { order.push(1); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { order.push(2); return false; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { order.push(3); return false; });
|
||||
parse(parser2, '\x1b%G');
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); });
|
||||
const dispo = parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); return true; });
|
||||
const dispo = parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
dispo.dispose();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['default - %G']);
|
||||
});
|
||||
it('Should not corrupt the parser when dispose is called twice', () => {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); });
|
||||
const dispo = parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('default - %G'); return true; });
|
||||
const dispo = parser2.registerEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
dispo.dispose();
|
||||
dispo.dispose();
|
||||
parse(parser2, INPUT);
|
||||
@@ -1276,8 +1278,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
});
|
||||
it('CSI handler', function (): void {
|
||||
parser2.setCsiHandler({final: 'm'}, function (params: IParams): void {
|
||||
parser2.registerCsiHandler({final: 'm'}, function (params: IParams): boolean {
|
||||
csi.push(['m', params.toArray(), '']);
|
||||
return true;
|
||||
});
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
@@ -1290,16 +1293,16 @@ describe('EscapeSequenceParser', function (): void {
|
||||
describe('CSI custom handlers', () => {
|
||||
it('Prevent fallback', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); });
|
||||
parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(csiCustom).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
});
|
||||
it('Allow fallback', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); });
|
||||
parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return false; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return false; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([['m', [1, 31], ''], ['m', [0], '']], 'Should fallback to original handler');
|
||||
chai.expect(csiCustom).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
@@ -1307,9 +1310,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('Multiple custom handlers fallback once', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
const csiCustom2: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); });
|
||||
parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.addCsiHandler({final: 'm'}, params => { csiCustom2.push(['m', params.toArray(), '']); return false; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csiCustom2.push(['m', params.toArray(), '']); return false; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(csiCustom).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
@@ -1318,9 +1321,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
const csiCustom2: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); });
|
||||
parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.addCsiHandler({final: 'm'}, params => { csiCustom2.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csiCustom2.push(['m', params.toArray(), '']); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(csiCustom).eql([], 'Should not fallback once');
|
||||
@@ -1328,16 +1331,16 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('Execution order should go from latest handler down to the original', () => {
|
||||
const order: number[] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, () => { order.push(1); });
|
||||
parser2.addCsiHandler({final: 'm'}, () => { order.push(2); return false; });
|
||||
parser2.addCsiHandler({final: 'm'}, () => { order.push(3); return false; });
|
||||
parser2.registerCsiHandler({final: 'm'}, () => { order.push(1); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, () => { order.push(2); return false; });
|
||||
parser2.registerCsiHandler({final: 'm'}, () => { order.push(3); return false; });
|
||||
parse(parser2, '\x1b[0m');
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); });
|
||||
const customHandler = parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); return true; });
|
||||
const customHandler = parser2.registerCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
customHandler.dispose();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
@@ -1345,8 +1348,8 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('Should not corrupt the parser when dispose is called twice', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); });
|
||||
const customHandler = parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
parser2.registerCsiHandler({final: 'm'}, params => { csi.push(['m', params.toArray(), '']); return true; });
|
||||
const customHandler = parser2.registerCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
customHandler.dispose();
|
||||
customHandler.dispose();
|
||||
parse(parser2, INPUT);
|
||||
@@ -1355,11 +1358,13 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
});
|
||||
it('EXECUTE handler', function (): void {
|
||||
parser2.setExecuteHandler('\n', function (): void {
|
||||
parser2.setExecuteHandler('\n', function (): boolean {
|
||||
exe.push('\n');
|
||||
return true;
|
||||
});
|
||||
parser2.setExecuteHandler('\r', function (): void {
|
||||
parser2.setExecuteHandler('\r', function (): boolean {
|
||||
exe.push('\r');
|
||||
return true;
|
||||
});
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(exe).eql(['\r', '\n']);
|
||||
@@ -1370,8 +1375,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
chai.expect(exe).eql(['\n']);
|
||||
});
|
||||
it('OSC handler', function (): void {
|
||||
parser2.setOscHandler(1, new OscHandler(function (data: string): void {
|
||||
parser2.registerOscHandler(1, new OscHandler(function (data: string): boolean {
|
||||
osc.push([1, data]);
|
||||
return true;
|
||||
}));
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(osc).eql([[1, 'foo=bar']]);
|
||||
@@ -1384,16 +1390,16 @@ describe('EscapeSequenceParser', function (): void {
|
||||
describe('OSC custom handlers', () => {
|
||||
it('Prevent fallback', () => {
|
||||
const oscCustom: [number, string][] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(data => osc.push([1, data])));
|
||||
parser2.addOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(osc).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(oscCustom).eql([[1, 'foo=bar']]);
|
||||
});
|
||||
it('Allow fallback', () => {
|
||||
const oscCustom: [number, string][] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(data => osc.push([1, data])));
|
||||
parser2.addOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return false; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return false; }));
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(osc).eql([[1, 'foo=bar']], 'Should fallback to original handler');
|
||||
chai.expect(oscCustom).eql([[1, 'foo=bar']]);
|
||||
@@ -1401,9 +1407,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('Multiple custom handlers fallback once', () => {
|
||||
const oscCustom: [number, string][] = [];
|
||||
const oscCustom2: [number, string][] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(data => osc.push([1, data])));
|
||||
parser2.addOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.addOscHandler(1, new OscHandler(data => { oscCustom2.push([1, data]); return false; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom2.push([1, data]); return false; }));
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(osc).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(oscCustom).eql([[1, 'foo=bar']]);
|
||||
@@ -1412,9 +1418,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
const oscCustom: [number, string][] = [];
|
||||
const oscCustom2: [number, string][] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(data => osc.push([1, data])));
|
||||
parser2.addOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.addOscHandler(1, new OscHandler(data => { oscCustom2.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom2.push([1, data]); return true; }));
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(osc).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(oscCustom).eql([], 'Should not fallback once');
|
||||
@@ -1422,16 +1428,16 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('Execution order should go from latest handler down to the original', () => {
|
||||
const order: number[] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(() => order.push(1)));
|
||||
parser2.addOscHandler(1, new OscHandler(() => { order.push(2); return false; }));
|
||||
parser2.addOscHandler(1, new OscHandler(() => { order.push(3); return false; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(() => { order.push(1); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(() => { order.push(2); return false; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(() => { order.push(3); return false; }));
|
||||
parse(parser2, '\x1b]1;foo=bar\x1b\\');
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
const oscCustom: [number, string][] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(data => osc.push([1, data])));
|
||||
const customHandler = parser2.addOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
|
||||
const customHandler = parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
customHandler.dispose();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(osc).eql([[1, 'foo=bar']]);
|
||||
@@ -1439,8 +1445,8 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('Should not corrupt the parser when dispose is called twice', () => {
|
||||
const oscCustom: [number, string][] = [];
|
||||
parser2.setOscHandler(1, new OscHandler(data => osc.push([1, data])));
|
||||
const customHandler = parser2.addOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
|
||||
const customHandler = parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
|
||||
customHandler.dispose();
|
||||
customHandler.dispose();
|
||||
parse(parser2, INPUT);
|
||||
@@ -1449,7 +1455,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
});
|
||||
it('DCS handler', function (): void {
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, {
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, {
|
||||
hook: function (params: IParams): void {
|
||||
dcs.push(['hook', '', params.toArray(), 0]);
|
||||
},
|
||||
@@ -1460,8 +1466,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
}
|
||||
dcs.push(['put', s]);
|
||||
},
|
||||
unhook: function (): void {
|
||||
unhook: function (): boolean {
|
||||
dcs.push(['unhook']);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
parse(parser2, '\x1bP1;2;3+pabc');
|
||||
@@ -1482,54 +1489,54 @@ describe('EscapeSequenceParser', function (): void {
|
||||
const DCS_INPUT = '\x1bP1;2;3+pabc\x1b\\';
|
||||
it('Prevent fallback', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parse(parser2, DCS_INPUT);
|
||||
chai.expect(dcsCustom).eql([['B', [1, 2, 3], 'abc']]);
|
||||
});
|
||||
it('Allow fallback', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return false; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return false; }));
|
||||
parse(parser2, DCS_INPUT);
|
||||
chai.expect(dcsCustom).eql([['B', [1, 2, 3], 'abc'], ['A', [1, 2, 3], 'abc']]);
|
||||
});
|
||||
it('Multiple custom handlers fallback once', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['C', params.toArray(), data]); return false; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['C', params.toArray(), data]); return false; }));
|
||||
parse(parser2, DCS_INPUT);
|
||||
chai.expect(dcsCustom).eql([['C', [1, 2, 3], 'abc'], ['B', [1, 2, 3], 'abc']]);
|
||||
});
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['C', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['C', params.toArray(), data]); return true; }));
|
||||
parse(parser2, DCS_INPUT);
|
||||
chai.expect(dcsCustom).eql([['C', [1, 2, 3], 'abc']]);
|
||||
});
|
||||
it('Execution order should go from latest handler down to the original', () => {
|
||||
const order: number[] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler(() => order.push(1)));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler(() => { order.push(2); return false; }));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler(() => { order.push(3); return false; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler(() => { order.push(1); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler(() => { order.push(2); return false; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler(() => { order.push(3); return false; }));
|
||||
parse(parser2, DCS_INPUT);
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
const dispo = parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
|
||||
const dispo = parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
dispo.dispose();
|
||||
parse(parser2, DCS_INPUT);
|
||||
chai.expect(dcsCustom).eql([['A', [1, 2, 3], 'abc']]);
|
||||
});
|
||||
it('Should not corrupt the parser when dispose is called twice', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
const dispo = parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
|
||||
const dispo = parser2.registerDcsHandler({intermediates: '+', final: 'p'}, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
dispo.dispose();
|
||||
dispo.dispose();
|
||||
parse(parser2, DCS_INPUT);
|
||||
@@ -1591,11 +1598,11 @@ describe('EscapeSequenceParser', function (): void {
|
||||
for (let i = 0x30; i <= 0x7e; ++i) {
|
||||
const final = String.fromCharCode(i);
|
||||
let handler: IDisposable | undefined;
|
||||
chai.assert.doesNotThrow(() => { handler = parser.addEscHandler({final}, () => {}); }, 'final must be in range 48 .. 126');
|
||||
chai.assert.doesNotThrow(() => { handler = parser.registerEscHandler({final}, () => true); }, 'final must be in range 48 .. 126');
|
||||
if (handler) handler.dispose();
|
||||
}
|
||||
chai.assert.throws(() => { parser.addEscHandler({final: '\x2f'}, () => {}); }, 'final must be in range 48 .. 126');
|
||||
chai.assert.throws(() => { parser.addEscHandler({final: '\x7f'}, () => {}); }, 'final must be in range 48 .. 126');
|
||||
chai.assert.throws(() => { parser.registerEscHandler({final: '\x2f'}, () => true); }, 'final must be in range 48 .. 126');
|
||||
chai.assert.throws(() => { parser.registerEscHandler({final: '\x7f'}, () => true); }, 'final must be in range 48 .. 126');
|
||||
});
|
||||
it('id calculation - should stacking prefix -> intermediate -> final', () => {
|
||||
chai.expect(parser.identToString(parser.identifier({final: 'z'}))).eql('z');
|
||||
@@ -1608,9 +1615,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
describe('identifier invocation', () => {
|
||||
it('ESC', () => {
|
||||
const callstack: string[] = [];
|
||||
const h1 = parser.addEscHandler({final: 'z'}, () => { callstack.push('z'); });
|
||||
const h2 = parser.addEscHandler({intermediates: '!', final: 'z'}, () => { callstack.push('!z'); });
|
||||
const h3 = parser.addEscHandler({intermediates: '!!', final: 'z'}, () => { callstack.push('!!z'); });
|
||||
const h1 = parser.registerEscHandler({final: 'z'}, () => { callstack.push('z'); return true; });
|
||||
const h2 = parser.registerEscHandler({intermediates: '!', final: 'z'}, () => { callstack.push('!z'); return true; });
|
||||
const h3 = parser.registerEscHandler({intermediates: '!!', final: 'z'}, () => { callstack.push('!!z'); return true; });
|
||||
parse(parser, '\x1bz\x1b!z\x1b!!z');
|
||||
h1.dispose();
|
||||
h2.dispose();
|
||||
@@ -1620,12 +1627,12 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('CSI', () => {
|
||||
const callstack: any[] = [];
|
||||
const h1 = parser.addCsiHandler({final: 'z'}, params => { callstack.push(['z', params.toArray()]); });
|
||||
const h2 = parser.addCsiHandler({intermediates: '!', final: 'z'}, params => { callstack.push(['!z', params.toArray()]); });
|
||||
const h3 = parser.addCsiHandler({intermediates: '!!', final: 'z'}, params => { callstack.push(['!!z', params.toArray()]); });
|
||||
const h4 = parser.addCsiHandler({prefix: '?', final: 'z'}, params => { callstack.push(['?z', params.toArray()]); });
|
||||
const h5 = parser.addCsiHandler({prefix: '?', intermediates: '!', final: 'z'}, params => { callstack.push(['?!z', params.toArray()]); });
|
||||
const h6 = parser.addCsiHandler({prefix: '?', intermediates: '!!', final: 'z'}, params => { callstack.push(['?!!z', params.toArray()]); });
|
||||
const h1 = parser.registerCsiHandler({final: 'z'}, params => { callstack.push(['z', params.toArray()]); return true; });
|
||||
const h2 = parser.registerCsiHandler({intermediates: '!', final: 'z'}, params => { callstack.push(['!z', params.toArray()]); return true; });
|
||||
const h3 = parser.registerCsiHandler({intermediates: '!!', final: 'z'}, params => { callstack.push(['!!z', params.toArray()]); return true; });
|
||||
const h4 = parser.registerCsiHandler({prefix: '?', final: 'z'}, params => { callstack.push(['?z', params.toArray()]); return true; });
|
||||
const h5 = parser.registerCsiHandler({prefix: '?', intermediates: '!', final: 'z'}, params => { callstack.push(['?!z', params.toArray()]); return true; });
|
||||
const h6 = parser.registerCsiHandler({prefix: '?', intermediates: '!!', final: 'z'}, params => { callstack.push(['?!!z', params.toArray()]); return true; });
|
||||
parse(parser, '\x1b[1;z\x1b[1;!z\x1b[1;!!z\x1b[?1;z\x1b[?1;!z\x1b[?1;!!z');
|
||||
h1.dispose();
|
||||
h2.dispose();
|
||||
@@ -1638,12 +1645,12 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('DCS', () => {
|
||||
const callstack: any[] = [];
|
||||
const h1 = parser.addDcsHandler({final: 'z'}, new DcsHandler((data, params) => { callstack.push(['z', params.toArray(), data]); }));
|
||||
const h2 = parser.addDcsHandler({intermediates: '!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['!z', params.toArray(), data]); }));
|
||||
const h3 = parser.addDcsHandler({intermediates: '!!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['!!z', params.toArray(), data]); }));
|
||||
const h4 = parser.addDcsHandler({prefix: '?', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['?z', params.toArray(), data]); }));
|
||||
const h5 = parser.addDcsHandler({prefix: '?', intermediates: '!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['?!z', params.toArray(), data]); }));
|
||||
const h6 = parser.addDcsHandler({prefix: '?', intermediates: '!!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['?!!z', params.toArray(), data]); }));
|
||||
const h1 = parser.registerDcsHandler({final: 'z'}, new DcsHandler((data, params) => { callstack.push(['z', params.toArray(), data]); return true; }));
|
||||
const h2 = parser.registerDcsHandler({intermediates: '!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['!z', params.toArray(), data]); return true; }));
|
||||
const h3 = parser.registerDcsHandler({intermediates: '!!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['!!z', params.toArray(), data]); return true; }));
|
||||
const h4 = parser.registerDcsHandler({prefix: '?', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['?z', params.toArray(), data]); return true; }));
|
||||
const h5 = parser.registerDcsHandler({prefix: '?', intermediates: '!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['?!z', params.toArray(), data]); return true; }));
|
||||
const h6 = parser.registerDcsHandler({prefix: '?', intermediates: '!!', final: 'z'}, new DcsHandler((data, params) => { callstack.push(['?!!z', params.toArray(), data]); return true; }));
|
||||
parse(parser, '\x1bP1;zAB\x1b\\\x1bP1;!zAB\x1b\\\x1bP1;!!zAB\x1b\\\x1bP?1;zAB\x1b\\\x1bP?1;!zAB\x1b\\\x1bP?1;!!zAB\x1b\\');
|
||||
h1.dispose();
|
||||
h2.dispose();
|
||||
|
||||
@@ -280,7 +280,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._errorHandler = this._errorHandlerFb;
|
||||
|
||||
// swallow 7bit ST (ESC+\)
|
||||
this.setEscHandler({final: '\\'}, () => {});
|
||||
this.registerEscHandler({final: '\\'}, () => true);
|
||||
}
|
||||
|
||||
protected _identifier(id: IFunctionIdentifier, finalRange: number[] = [0x40, 0x7e]): number {
|
||||
@@ -344,7 +344,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._printHandler = this._printHandlerFb;
|
||||
}
|
||||
|
||||
public addEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable {
|
||||
public registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable {
|
||||
const ident = this._identifier(id, [0x30, 0x7e]);
|
||||
if (this._escHandlers[ident] === undefined) {
|
||||
this._escHandlers[ident] = [];
|
||||
@@ -360,9 +360,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
}
|
||||
};
|
||||
}
|
||||
public setEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): void {
|
||||
this._escHandlers[this._identifier(id, [0x30, 0x7e])] = [handler];
|
||||
}
|
||||
public clearEscHandler(id: IFunctionIdentifier): void {
|
||||
if (this._escHandlers[this._identifier(id, [0x30, 0x7e])]) delete this._escHandlers[this._identifier(id, [0x30, 0x7e])];
|
||||
}
|
||||
@@ -380,7 +377,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._executeHandlerFb = handler;
|
||||
}
|
||||
|
||||
public addCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable {
|
||||
public registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable {
|
||||
const ident = this._identifier(id);
|
||||
if (this._csiHandlers[ident] === undefined) {
|
||||
this._csiHandlers[ident] = [];
|
||||
@@ -396,9 +393,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
}
|
||||
};
|
||||
}
|
||||
public setCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): void {
|
||||
this._csiHandlers[this._identifier(id)] = [handler];
|
||||
}
|
||||
public clearCsiHandler(id: IFunctionIdentifier): void {
|
||||
if (this._csiHandlers[this._identifier(id)]) delete this._csiHandlers[this._identifier(id)];
|
||||
}
|
||||
@@ -406,11 +400,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._csiHandlerFb = callback;
|
||||
}
|
||||
|
||||
public addDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable {
|
||||
return this._dcsParser.addHandler(this._identifier(id), handler);
|
||||
}
|
||||
public setDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): void {
|
||||
this._dcsParser.setHandler(this._identifier(id), handler);
|
||||
public registerDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable {
|
||||
return this._dcsParser.registerHandler(this._identifier(id), handler);
|
||||
}
|
||||
public clearDcsHandler(id: IFunctionIdentifier): void {
|
||||
this._dcsParser.clearHandler(this._identifier(id));
|
||||
@@ -419,11 +410,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._dcsParser.setHandlerFallback(handler);
|
||||
}
|
||||
|
||||
public addOscHandler(ident: number, handler: IOscHandler): IDisposable {
|
||||
return this._oscParser.addHandler(ident, handler);
|
||||
}
|
||||
public setOscHandler(ident: number, handler: IOscHandler): void {
|
||||
this._oscParser.setHandler(ident, handler);
|
||||
public registerOscHandler(ident: number, handler: IOscHandler): IDisposable {
|
||||
return this._oscParser.registerHandler(ident, handler);
|
||||
}
|
||||
public clearOscHandler(ident: number): void {
|
||||
this._oscParser.clearHandler(ident);
|
||||
@@ -533,8 +521,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
const handlers = this._csiHandlers[collect << 8 | code];
|
||||
let j = handlers ? handlers.length - 1 : -1;
|
||||
for (; j >= 0; j--) {
|
||||
// undefined or true means success and to stop bubbling
|
||||
if (handlers[j](params) !== false) {
|
||||
// true means success and to stop bubbling
|
||||
if (handlers[j](params)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -567,8 +555,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
const handlersEsc = this._escHandlers[collect << 8 | code];
|
||||
let jj = handlersEsc ? handlersEsc.length - 1 : -1;
|
||||
for (; jj >= 0; jj--) {
|
||||
// undefined or true means success and to stop bubbling
|
||||
if (handlersEsc[jj]() !== false) {
|
||||
// true means success and to stop bubbling
|
||||
if (handlersEsc[jj]()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -610,7 +598,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
case ParserAction.OSC_PUT:
|
||||
// inner loop: 0x20 (SP) included, 0x7F (DEL) included
|
||||
for (let j = i + 1; ; j++) {
|
||||
if (j >= length || (code = data[j]) < 0x20 || (code > 0x7f && code <= 0x9f)) {
|
||||
if (j >= length || (code = data[j]) < 0x20 || (code > 0x7f && code < NON_ASCII_PRINTABLE)) {
|
||||
osc.put(data, i, j);
|
||||
i = j - 1;
|
||||
break;
|
||||
|
||||
@@ -23,11 +23,12 @@ class TestHandler implements IOscHandler {
|
||||
public put(data: Uint32Array, start: number, end: number): void {
|
||||
this.output.push([this.msg, this.id, 'PUT', utf32ToString(data, start, end)]);
|
||||
}
|
||||
public end(success: boolean): void | boolean {
|
||||
public end(success: boolean): boolean {
|
||||
this.output.push([this.msg, this.id, 'END', success]);
|
||||
if (this.returnFalse) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ describe('OscParser', () => {
|
||||
});
|
||||
describe('handler registration', () => {
|
||||
it('setOscHandler', () => {
|
||||
parser.setHandler(1234, new TestHandler(1234, reports, 'th'));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th'));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -94,7 +95,7 @@ describe('OscParser', () => {
|
||||
]);
|
||||
});
|
||||
it('clearOscHandler', () => {
|
||||
parser.setHandler(1234, new TestHandler(1234, reports, 'th'));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th'));
|
||||
parser.clearHandler(1234);
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
@@ -111,8 +112,8 @@ describe('OscParser', () => {
|
||||
]);
|
||||
});
|
||||
it('addOscHandler', () => {
|
||||
parser.setHandler(1234, new TestHandler(1234, reports, 'th1'));
|
||||
parser.addHandler(1234, new TestHandler(1234, reports, 'th2'));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th1'));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th2'));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -131,8 +132,8 @@ describe('OscParser', () => {
|
||||
]);
|
||||
});
|
||||
it('addOscHandler with return false', () => {
|
||||
parser.setHandler(1234, new TestHandler(1234, reports, 'th1'));
|
||||
parser.addHandler(1234, new TestHandler(1234, reports, 'th2', true));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th1'));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th2', true));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -151,8 +152,8 @@ describe('OscParser', () => {
|
||||
]);
|
||||
});
|
||||
it('dispose handlers', () => {
|
||||
parser.setHandler(1234, new TestHandler(1234, reports, 'th1'));
|
||||
const dispo = parser.addHandler(1234, new TestHandler(1234, reports, 'th2', true));
|
||||
parser.registerHandler(1234, new TestHandler(1234, reports, 'th1'));
|
||||
const dispo = parser.registerHandler(1234, new TestHandler(1234, reports, 'th2', true));
|
||||
dispo.dispose();
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
@@ -170,7 +171,7 @@ describe('OscParser', () => {
|
||||
});
|
||||
describe('OscHandlerFactory', () => {
|
||||
it('should be called once on end(true)', () => {
|
||||
parser.setHandler(1234, new OscHandler(data => reports.push([1234, data])));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -180,7 +181,7 @@ describe('OscParser', () => {
|
||||
assert.deepEqual(reports, [[1234, 'Here comes the mouse!']]);
|
||||
});
|
||||
it('should not be called on end(false)', () => {
|
||||
parser.setHandler(1234, new OscHandler(data => reports.push([1234, data])));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -190,8 +191,8 @@ describe('OscParser', () => {
|
||||
assert.deepEqual(reports, []);
|
||||
});
|
||||
it('should be disposable', () => {
|
||||
parser.setHandler(1234, new OscHandler(data => reports.push(['one', data])));
|
||||
const dispo = parser.addHandler(1234, new OscHandler(data => reports.push(['two', data])));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push(['one', data]); return true; }));
|
||||
const dispo = parser.registerHandler(1234, new OscHandler(data => { reports.push(['two', data]); return true; }));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -209,8 +210,8 @@ describe('OscParser', () => {
|
||||
assert.deepEqual(reports, [['two', 'Here comes the mouse!'], ['one', 'some other data']]);
|
||||
});
|
||||
it('should respect return false', () => {
|
||||
parser.setHandler(1234, new OscHandler(data => reports.push(['one', data])));
|
||||
parser.addHandler(1234, new OscHandler(data => { reports.push(['two', data]); return false; }));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push(['one', data]); return true; }));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push(['two', data]); return false; }));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -221,7 +222,7 @@ describe('OscParser', () => {
|
||||
});
|
||||
it('should work up to payload limit', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setHandler(1234, new OscHandler(data => reports.push([1234, data])));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;');
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -234,7 +235,7 @@ describe('OscParser', () => {
|
||||
});
|
||||
it('should abort for payload limit +1', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setHandler(1234, new OscHandler(data => reports.push([1234, data])));
|
||||
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
|
||||
parser.start();
|
||||
let data = toUtf32('1234;');
|
||||
parser.put(data, 0, data.length);
|
||||
|
||||
@@ -8,14 +8,16 @@ import { OscState, PAYLOAD_LIMIT } from 'common/parser/Constants';
|
||||
import { utf32ToString } from 'common/input/TextDecoder';
|
||||
import { IDisposable } from 'common/Types';
|
||||
|
||||
const EMPTY_HANDLERS: IOscHandler[] = [];
|
||||
|
||||
export class OscParser implements IOscParser {
|
||||
private _state = OscState.START;
|
||||
private _active = EMPTY_HANDLERS;
|
||||
private _id = -1;
|
||||
private _handlers: IHandlerCollection<IOscHandler> = Object.create(null);
|
||||
private _handlerFb: OscFallbackHandlerType = () => { };
|
||||
|
||||
public addHandler(ident: number, handler: IOscHandler): IDisposable {
|
||||
public registerHandler(ident: number, handler: IOscHandler): IDisposable {
|
||||
if (this._handlers[ident] === undefined) {
|
||||
this._handlers[ident] = [];
|
||||
}
|
||||
@@ -30,9 +32,6 @@ export class OscParser implements IOscParser {
|
||||
}
|
||||
};
|
||||
}
|
||||
public setHandler(ident: number, handler: IOscHandler): void {
|
||||
this._handlers[ident] = [handler];
|
||||
}
|
||||
public clearHandler(ident: number): void {
|
||||
if (this._handlers[ident]) delete this._handlers[ident];
|
||||
}
|
||||
@@ -43,6 +42,7 @@ export class OscParser implements IOscParser {
|
||||
public dispose(): void {
|
||||
this._handlers = Object.create(null);
|
||||
this._handlerFb = () => {};
|
||||
this._active = EMPTY_HANDLERS;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
@@ -50,28 +50,28 @@ export class OscParser implements IOscParser {
|
||||
if (this._state === OscState.PAYLOAD) {
|
||||
this.end(false);
|
||||
}
|
||||
this._active = EMPTY_HANDLERS;
|
||||
this._id = -1;
|
||||
this._state = OscState.START;
|
||||
}
|
||||
|
||||
private _start(): void {
|
||||
const handlers = this._handlers[this._id];
|
||||
if (!handlers) {
|
||||
this._active = this._handlers[this._id] || EMPTY_HANDLERS;
|
||||
if (!this._active.length) {
|
||||
this._handlerFb(this._id, 'START');
|
||||
} else {
|
||||
for (let j = handlers.length - 1; j >= 0; j--) {
|
||||
handlers[j].start();
|
||||
for (let j = this._active.length - 1; j >= 0; j--) {
|
||||
this._active[j].start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _put(data: Uint32Array, start: number, end: number): void {
|
||||
const handlers = this._handlers[this._id];
|
||||
if (!handlers) {
|
||||
if (!this._active.length) {
|
||||
this._handlerFb(this._id, 'PUT', utf32ToString(data, start, end));
|
||||
} else {
|
||||
for (let j = handlers.length - 1; j >= 0; j--) {
|
||||
handlers[j].put(data, start, end);
|
||||
for (let j = this._active.length - 1; j >= 0; j--) {
|
||||
this._active[j].put(data, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,20 +80,19 @@ export class OscParser implements IOscParser {
|
||||
// other than the old code we always have to call .end
|
||||
// to keep the bubbling we use `success` to indicate
|
||||
// whether a handler should execute
|
||||
const handlers = this._handlers[this._id];
|
||||
if (!handlers) {
|
||||
if (!this._active.length) {
|
||||
this._handlerFb(this._id, 'END', success);
|
||||
} else {
|
||||
let j = handlers.length - 1;
|
||||
let j = this._active.length - 1;
|
||||
for (; j >= 0; j--) {
|
||||
if (handlers[j].end(success) !== false) {
|
||||
if (this._active[j].end(success)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
j--;
|
||||
// cleanup left over handlers
|
||||
for (; j >= 0; j--) {
|
||||
handlers[j].end(false);
|
||||
this._active[j].end(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +100,6 @@ export class OscParser implements IOscParser {
|
||||
public start(): void {
|
||||
// always reset leftover handlers
|
||||
this.reset();
|
||||
this._id = -1;
|
||||
this._state = OscState.ID;
|
||||
}
|
||||
|
||||
@@ -158,6 +156,7 @@ export class OscParser implements IOscParser {
|
||||
}
|
||||
this._end(success);
|
||||
}
|
||||
this._active = EMPTY_HANDLERS;
|
||||
this._id = -1;
|
||||
this._state = OscState.START;
|
||||
}
|
||||
@@ -171,7 +170,7 @@ export class OscHandler implements IOscHandler {
|
||||
private _data = '';
|
||||
private _hitLimit: boolean = false;
|
||||
|
||||
constructor(private _handler: (data: string) => any) {}
|
||||
constructor(private _handler: (data: string) => boolean) {}
|
||||
|
||||
public start(): void {
|
||||
this._data = '';
|
||||
@@ -189,8 +188,8 @@ export class OscHandler implements IOscHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public end(success: boolean): any {
|
||||
let ret;
|
||||
public end(success: boolean): boolean {
|
||||
let ret = false;
|
||||
if (this._hitLimit) {
|
||||
ret = false;
|
||||
} else if (success) {
|
||||
|
||||
Vendored
+10
-15
@@ -69,7 +69,7 @@ export interface IParsingState {
|
||||
* CSI handler types.
|
||||
* Note: `params` is borrowed.
|
||||
*/
|
||||
export type CsiHandlerType = (params: IParams) => boolean | void;
|
||||
export type CsiHandlerType = (params: IParams) => boolean;
|
||||
export type CsiFallbackHandlerType = (ident: number, params: IParams) => void;
|
||||
|
||||
/**
|
||||
@@ -93,20 +93,20 @@ export interface IDcsHandler {
|
||||
* execution of the command should depend on `success`.
|
||||
* To save memory also cleanup data structures here.
|
||||
*/
|
||||
unhook(success: boolean): void | boolean;
|
||||
unhook(success: boolean): boolean;
|
||||
}
|
||||
export type DcsFallbackHandlerType = (ident: number, action: 'HOOK' | 'PUT' | 'UNHOOK', payload?: any) => void;
|
||||
|
||||
/**
|
||||
* ESC handler types.
|
||||
*/
|
||||
export type EscHandlerType = () => boolean | void;
|
||||
export type EscHandlerType = () => boolean;
|
||||
export type EscFallbackHandlerType = (identifier: number) => void;
|
||||
|
||||
/**
|
||||
* EXECUTE handler types.
|
||||
*/
|
||||
export type ExecuteHandlerType = () => boolean | void;
|
||||
export type ExecuteHandlerType = () => boolean;
|
||||
export type ExecuteFallbackHandlerType = (ident: number) => void;
|
||||
|
||||
/**
|
||||
@@ -129,7 +129,7 @@ export interface IOscHandler {
|
||||
* execution of the command should depend on `success`.
|
||||
* To save memory also cleanup data structures here.
|
||||
*/
|
||||
end(success: boolean): void | boolean;
|
||||
end(success: boolean): boolean;
|
||||
}
|
||||
export type OscFallbackHandlerType = (ident: number, action: 'START' | 'PUT' | 'END', payload?: any) => void;
|
||||
|
||||
@@ -174,29 +174,25 @@ export interface IEscapeSequenceParser extends IDisposable {
|
||||
setPrintHandler(handler: PrintHandlerType): void;
|
||||
clearPrintHandler(): void;
|
||||
|
||||
setEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): void;
|
||||
registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable;
|
||||
clearEscHandler(id: IFunctionIdentifier): void;
|
||||
setEscHandlerFallback(handler: EscFallbackHandlerType): void;
|
||||
addEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable;
|
||||
|
||||
setExecuteHandler(flag: string, handler: ExecuteHandlerType): void;
|
||||
clearExecuteHandler(flag: string): void;
|
||||
setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void;
|
||||
|
||||
setCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): void;
|
||||
registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable;
|
||||
clearCsiHandler(id: IFunctionIdentifier): void;
|
||||
setCsiHandlerFallback(callback: CsiFallbackHandlerType): void;
|
||||
addCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable;
|
||||
|
||||
setDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): void;
|
||||
registerDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable;
|
||||
clearDcsHandler(id: IFunctionIdentifier): void;
|
||||
setDcsHandlerFallback(handler: DcsFallbackHandlerType): void;
|
||||
addDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable;
|
||||
|
||||
setOscHandler(ident: number, handler: IOscHandler): void;
|
||||
registerOscHandler(ident: number, handler: IOscHandler): IDisposable;
|
||||
clearOscHandler(ident: number): void;
|
||||
setOscHandlerFallback(handler: OscFallbackHandlerType): void;
|
||||
addOscHandler(ident: number, handler: IOscHandler): IDisposable;
|
||||
|
||||
setErrorHandler(handler: (state: IParsingState) => IParsingState): void;
|
||||
clearErrorHandler(): void;
|
||||
@@ -209,8 +205,7 @@ export interface IEscapeSequenceParser extends IDisposable {
|
||||
*/
|
||||
export interface ISubParser<T, U> extends IDisposable {
|
||||
reset(): void;
|
||||
addHandler(ident: number, handler: T): IDisposable;
|
||||
setHandler(ident: number, handler: T): void;
|
||||
registerHandler(ident: number, handler: T): IDisposable;
|
||||
clearHandler(ident: number): void;
|
||||
setHandlerFallback(handler: U): void;
|
||||
put(data: Uint32Array, start: number, end: number): void;
|
||||
|
||||
@@ -6,9 +6,11 @@ import { perfContext, before, beforeEach, ThroughputRuntimeCase } from 'xterm-be
|
||||
|
||||
import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser';
|
||||
import { C0, C1 } from 'common/data/EscapeSequences';
|
||||
import { IDcsHandler, IParams } from 'common/parser/Types';
|
||||
import { IDcsHandler, IOscHandler, IParams } from 'common/parser/Types';
|
||||
import { OscHandler } from 'common/parser/OscParser';
|
||||
import { DcsHandler } from '../../out/common/parser/DcsParser';
|
||||
|
||||
const SIZE = 5000000;
|
||||
|
||||
function toUtf32(s: string): Uint32Array {
|
||||
const result = new Uint32Array(s.length);
|
||||
@@ -18,10 +20,16 @@ function toUtf32(s: string): Uint32Array {
|
||||
return result;
|
||||
}
|
||||
|
||||
class DcsHandler implements IDcsHandler {
|
||||
class FastDcsHandler implements IDcsHandler {
|
||||
public hook(params: IParams): void {}
|
||||
public put(data: Uint32Array, start: number, end: number): void {}
|
||||
public unhook(): void {}
|
||||
public unhook(success: boolean): boolean { return true; }
|
||||
}
|
||||
|
||||
class FastOscHandler implements IOscHandler {
|
||||
public start(): void {}
|
||||
public put(data: Uint32Array, start: number, end: number): void {}
|
||||
public end(success: boolean): boolean { return true; }
|
||||
}
|
||||
|
||||
|
||||
@@ -32,80 +40,81 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
beforeEach(() => {
|
||||
parser = new EscapeSequenceParser();
|
||||
parser.setPrintHandler((data, start, end) => {});
|
||||
parser.setCsiHandler({final: '@'}, params => {});
|
||||
parser.setCsiHandler({final: 'A'}, params => {});
|
||||
parser.setCsiHandler({final: 'B'}, params => {});
|
||||
parser.setCsiHandler({final: 'C'}, params => {});
|
||||
parser.setCsiHandler({final: 'D'}, params => {});
|
||||
parser.setCsiHandler({final: 'E'}, params => {});
|
||||
parser.setCsiHandler({final: 'F'}, params => {});
|
||||
parser.setCsiHandler({final: 'G'}, params => {});
|
||||
parser.setCsiHandler({final: 'H'}, params => {});
|
||||
parser.setCsiHandler({final: 'I'}, params => {});
|
||||
parser.setCsiHandler({final: 'J'}, params => {});
|
||||
parser.setCsiHandler({final: 'K'}, params => {});
|
||||
parser.setCsiHandler({final: 'L'}, params => {});
|
||||
parser.setCsiHandler({final: 'M'}, params => {});
|
||||
parser.setCsiHandler({final: 'P'}, params => {});
|
||||
parser.setCsiHandler({final: 'S'}, params => {});
|
||||
parser.setCsiHandler({final: 'T'}, params => {});
|
||||
parser.setCsiHandler({final: 'X'}, params => {});
|
||||
parser.setCsiHandler({final: 'Z'}, params => {});
|
||||
parser.setCsiHandler({final: '`'}, params => {});
|
||||
parser.setCsiHandler({final: 'a'}, params => {});
|
||||
parser.setCsiHandler({final: 'b'}, params => {});
|
||||
parser.setCsiHandler({final: 'c'}, params => {});
|
||||
parser.setCsiHandler({final: 'd'}, params => {});
|
||||
parser.setCsiHandler({final: 'e'}, params => {});
|
||||
parser.setCsiHandler({final: 'f'}, params => {});
|
||||
parser.setCsiHandler({final: 'g'}, params => {});
|
||||
parser.setCsiHandler({final: 'h'}, params => {});
|
||||
parser.setCsiHandler({final: 'l'}, params => {});
|
||||
parser.setCsiHandler({final: 'm'}, params => {});
|
||||
parser.setCsiHandler({final: 'n'}, params => {});
|
||||
parser.setCsiHandler({final: 'p'}, params => {});
|
||||
parser.setCsiHandler({final: 'q'}, params => {});
|
||||
parser.setCsiHandler({final: 'r'}, params => {});
|
||||
parser.setCsiHandler({final: 's'}, params => {});
|
||||
parser.setCsiHandler({final: 'u'}, params => {});
|
||||
parser.setExecuteHandler(C0.BEL, () => {});
|
||||
parser.setExecuteHandler(C0.LF, () => {});
|
||||
parser.setExecuteHandler(C0.VT, () => {});
|
||||
parser.setExecuteHandler(C0.FF, () => {});
|
||||
parser.setExecuteHandler(C0.CR, () => {});
|
||||
parser.setExecuteHandler(C0.BS, () => {});
|
||||
parser.setExecuteHandler(C0.HT, () => {});
|
||||
parser.setExecuteHandler(C0.SO, () => {});
|
||||
parser.setExecuteHandler(C0.SI, () => {});
|
||||
parser.setExecuteHandler(C1.IND, () => {});
|
||||
parser.setExecuteHandler(C1.NEL, () => {});
|
||||
parser.setExecuteHandler(C1.HTS, () => {});
|
||||
parser.setOscHandler(0, new OscHandler((data) => {}));
|
||||
parser.setOscHandler(2, new OscHandler((data) => {}));
|
||||
parser.setEscHandler({final: '7'}, () => {});
|
||||
parser.setEscHandler({final: '8'}, () => {});
|
||||
parser.setEscHandler({final: 'D'}, () => {});
|
||||
parser.setEscHandler({final: 'E'}, () => {});
|
||||
parser.setEscHandler({final: 'H'}, () => {});
|
||||
parser.setEscHandler({final: 'M'}, () => {});
|
||||
parser.setEscHandler({final: '='}, () => {});
|
||||
parser.setEscHandler({final: '>'}, () => {});
|
||||
parser.setEscHandler({final: 'c'}, () => {});
|
||||
parser.setEscHandler({final: 'n'}, () => {});
|
||||
parser.setEscHandler({final: 'o'}, () => {});
|
||||
parser.setEscHandler({final: '|'}, () => {});
|
||||
parser.setEscHandler({final: '}'}, () => {});
|
||||
parser.setEscHandler({final: '~'}, () => {});
|
||||
parser.setEscHandler({intermediates: '%', final: '@'}, () => {});
|
||||
parser.setEscHandler({intermediates: '%', final: 'G'}, () => {});
|
||||
parser.setDcsHandler({final: 'q'}, new DcsHandler());
|
||||
parser.registerCsiHandler({final: '@'}, params => true);
|
||||
parser.registerCsiHandler({final: 'A'}, params => true);
|
||||
parser.registerCsiHandler({final: 'B'}, params => true);
|
||||
parser.registerCsiHandler({final: 'C'}, params => true);
|
||||
parser.registerCsiHandler({final: 'D'}, params => true);
|
||||
parser.registerCsiHandler({final: 'E'}, params => true);
|
||||
parser.registerCsiHandler({final: 'F'}, params => true);
|
||||
parser.registerCsiHandler({final: 'G'}, params => true);
|
||||
parser.registerCsiHandler({final: 'H'}, params => true);
|
||||
parser.registerCsiHandler({final: 'I'}, params => true);
|
||||
parser.registerCsiHandler({final: 'J'}, params => true);
|
||||
parser.registerCsiHandler({final: 'K'}, params => true);
|
||||
parser.registerCsiHandler({final: 'L'}, params => true);
|
||||
parser.registerCsiHandler({final: 'M'}, params => true);
|
||||
parser.registerCsiHandler({final: 'P'}, params => true);
|
||||
parser.registerCsiHandler({final: 'S'}, params => true);
|
||||
parser.registerCsiHandler({final: 'T'}, params => true);
|
||||
parser.registerCsiHandler({final: 'X'}, params => true);
|
||||
parser.registerCsiHandler({final: 'Z'}, params => true);
|
||||
parser.registerCsiHandler({final: '`'}, params => true);
|
||||
parser.registerCsiHandler({final: 'a'}, params => true);
|
||||
parser.registerCsiHandler({final: 'b'}, params => true);
|
||||
parser.registerCsiHandler({final: 'c'}, params => true);
|
||||
parser.registerCsiHandler({final: 'd'}, params => true);
|
||||
parser.registerCsiHandler({final: 'e'}, params => true);
|
||||
parser.registerCsiHandler({final: 'f'}, params => true);
|
||||
parser.registerCsiHandler({final: 'g'}, params => true);
|
||||
parser.registerCsiHandler({final: 'h'}, params => true);
|
||||
parser.registerCsiHandler({final: 'l'}, params => true);
|
||||
parser.registerCsiHandler({final: 'm'}, params => true);
|
||||
parser.registerCsiHandler({final: 'n'}, params => true);
|
||||
parser.registerCsiHandler({final: 'p'}, params => true);
|
||||
parser.registerCsiHandler({final: 'q'}, params => true);
|
||||
parser.registerCsiHandler({final: 'r'}, params => true);
|
||||
parser.registerCsiHandler({final: 's'}, params => true);
|
||||
parser.registerCsiHandler({final: 'u'}, params => true);
|
||||
parser.setExecuteHandler(C0.BEL, () => true);
|
||||
parser.setExecuteHandler(C0.LF, () => true);
|
||||
parser.setExecuteHandler(C0.VT, () => true);
|
||||
parser.setExecuteHandler(C0.FF, () => true);
|
||||
parser.setExecuteHandler(C0.CR, () => true);
|
||||
parser.setExecuteHandler(C0.BS, () => true);
|
||||
parser.setExecuteHandler(C0.HT, () => true);
|
||||
parser.setExecuteHandler(C0.SO, () => true);
|
||||
parser.setExecuteHandler(C0.SI, () => true);
|
||||
parser.setExecuteHandler(C1.IND, () => true);
|
||||
parser.setExecuteHandler(C1.NEL, () => true);
|
||||
parser.setExecuteHandler(C1.HTS, () => true);
|
||||
parser.registerOscHandler(0, new OscHandler(data => true));
|
||||
parser.registerOscHandler(1, new FastOscHandler());
|
||||
parser.registerEscHandler({final: '7'}, () => true);
|
||||
parser.registerEscHandler({final: '8'}, () => true);
|
||||
parser.registerEscHandler({final: 'D'}, () => true);
|
||||
parser.registerEscHandler({final: 'E'}, () => true);
|
||||
parser.registerEscHandler({final: 'H'}, () => true);
|
||||
parser.registerEscHandler({final: 'M'}, () => true);
|
||||
parser.registerEscHandler({final: '='}, () => true);
|
||||
parser.registerEscHandler({final: '>'}, () => true);
|
||||
parser.registerEscHandler({final: 'c'}, () => true);
|
||||
parser.registerEscHandler({final: 'n'}, () => true);
|
||||
parser.registerEscHandler({final: 'o'}, () => true);
|
||||
parser.registerEscHandler({final: '|'}, () => true);
|
||||
parser.registerEscHandler({final: '}'}, () => true);
|
||||
parser.registerEscHandler({final: '~'}, () => true);
|
||||
parser.registerEscHandler({intermediates: '%', final: '@'}, () => true);
|
||||
parser.registerEscHandler({intermediates: '%', final: 'G'}, () => true);
|
||||
parser.registerDcsHandler({final: 'p'}, new DcsHandler(data => true));
|
||||
parser.registerDcsHandler({final: 'q'}, new FastDcsHandler());
|
||||
});
|
||||
|
||||
perfContext('PRINT - a', () => {
|
||||
before(() => {
|
||||
const data = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -120,7 +129,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\n\n\n\n\n\n\n';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -135,7 +144,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\x1bE\x1bE\x1bE\x1bE\x1bE\x1bE\x1bE\x1bE\x1bE\x1bE';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -150,7 +159,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\x1b%G\x1b%G\x1b%G\x1b%G\x1b%G\x1b%G\x1b%G\x1b%G\x1b%G\x1b%G';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -165,7 +174,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -180,7 +189,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\x1b[?p\x1b[?p\x1b[?p\x1b[?p\x1b[?p\x1b[?p\x1b[?p\x1b[?p\x1b[?p\x1b[?p';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -195,7 +204,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m\x1b[1;2m';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -210,7 +219,7 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
before(() => {
|
||||
const data = '\x1b[1;2;3;4;5;6;7;8;9;0m\x1b[1;2;3;4;5;6;7;8;9;0m\x1b[1;2;3;4;5;6;7;8;9;0m';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -221,11 +230,11 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('OSC (short) - OSC 0;hi ST', () => {
|
||||
perfContext('OSC string interface (short seq) - OSC 0;hi ST', () => {
|
||||
before(() => {
|
||||
const data = '\x1b]0;hi\x1b\\\x1b]0;hi\x1b\\\x1b]0;hi\x1b\\\x1b]0;hi\x1b\\x1b]0;hi\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -236,11 +245,11 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('OSC (long) - OSC 0;<text> ST', () => {
|
||||
perfContext('OSC string interface (long seq) - OSC 0;<text> ST', () => {
|
||||
before(() => {
|
||||
const data = '\x1b]0;Lorem ipsum dolor sit amet, consetetur sadipscing elitr.\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -251,11 +260,41 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('DCS (short)', () => {
|
||||
perfContext('OSC class interface (short seq) - OSC 0;hi ST', () => {
|
||||
before(() => {
|
||||
const data = '\x1bPq~~\x1b\\';
|
||||
const data = '\x1b]1;hi\x1b\\\x1b]1;hi\x1b\\\x1b]1;hi\x1b\\\x1b]1;hi\x1b\\x1b]1;hi\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
});
|
||||
new ThroughputRuntimeCase('', () => {
|
||||
parser.parse(parsed, parsed.length);
|
||||
return {payloadSize: parsed.length};
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('OSC class interface (long seq) - OSC 0;<text> ST', () => {
|
||||
before(() => {
|
||||
const data = '\x1b]1;Lorem ipsum dolor sit amet, consetetur sadipscing elitr.\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
});
|
||||
new ThroughputRuntimeCase('', () => {
|
||||
parser.parse(parsed, parsed.length);
|
||||
return {payloadSize: parsed.length};
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('DCS string interface (short seq)', () => {
|
||||
before(() => {
|
||||
const data = '\x1bPphi\x1b\\\x1bPphi\x1b\\\x1bPphi\x1b\\\x1bPphi\x1b\\\x1bPphi\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
@@ -266,11 +305,41 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('DCS (long)', () => {
|
||||
perfContext('DCS string interface (long seq)', () => {
|
||||
before(() => {
|
||||
const data = '\x1bPq#0;2;0;0;0#1;2;100;100;0#2;2;0;100;0#1~~@@vv@@~~@@~~$#2??}}GG}}??}}??-#1!14@\x1b\\';
|
||||
const data = '\x1bPpLorem ipsum dolor sit amet, consetetur sadipscing elitr.\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < 50000000) {
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
});
|
||||
new ThroughputRuntimeCase('', async () => {
|
||||
parser.parse(parsed, parsed.length);
|
||||
return {payloadSize: parsed.length};
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('DCS class interface (short seq)', () => {
|
||||
before(() => {
|
||||
const data = '\x1bPqhi\x1b\\\x1bPqhi\x1b\\\x1bPqhi\x1b\\\x1bPqhi\x1b\\\x1bPqhi\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
});
|
||||
new ThroughputRuntimeCase('', async () => {
|
||||
parser.parse(parsed, parsed.length);
|
||||
return {payloadSize: parsed.length};
|
||||
}, {fork: true}).showAverageThroughput();
|
||||
});
|
||||
|
||||
perfContext('DCS class interface (long seq)', () => {
|
||||
before(() => {
|
||||
const data = '\x1bPqLorem ipsum dolor sit amet, consetetur sadipscing elitr.\x1b\\';
|
||||
let content = '';
|
||||
while (content.length < SIZE) {
|
||||
content += data;
|
||||
}
|
||||
parsed = toUtf32(content);
|
||||
|
||||
Reference in New Issue
Block a user