mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
register functions by prefix/intermediate/final bytes
This commit is contained in:
@@ -53,39 +53,38 @@ describe('InputHandler', () => {
|
||||
it('should call Terminal.setOption with correct params', () => {
|
||||
const optionsService = new MockOptionsService();
|
||||
const inputHandler = new InputHandler(new MockInputHandlingTerminal(), new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), optionsService);
|
||||
const collect = ' ';
|
||||
|
||||
inputHandler.setCursorStyle(Params.fromArray([0]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([0]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'block');
|
||||
assert.equal(optionsService.options['cursorBlink'], true);
|
||||
|
||||
optionsService.options = clone(DEFAULT_OPTIONS);
|
||||
inputHandler.setCursorStyle(Params.fromArray([1]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([1]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'block');
|
||||
assert.equal(optionsService.options['cursorBlink'], true);
|
||||
|
||||
optionsService.options = clone(DEFAULT_OPTIONS);
|
||||
inputHandler.setCursorStyle(Params.fromArray([2]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([2]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'block');
|
||||
assert.equal(optionsService.options['cursorBlink'], false);
|
||||
|
||||
optionsService.options = clone(DEFAULT_OPTIONS);
|
||||
inputHandler.setCursorStyle(Params.fromArray([3]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([3]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'underline');
|
||||
assert.equal(optionsService.options['cursorBlink'], true);
|
||||
|
||||
optionsService.options = clone(DEFAULT_OPTIONS);
|
||||
inputHandler.setCursorStyle(Params.fromArray([4]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([4]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'underline');
|
||||
assert.equal(optionsService.options['cursorBlink'], false);
|
||||
|
||||
optionsService.options = clone(DEFAULT_OPTIONS);
|
||||
inputHandler.setCursorStyle(Params.fromArray([5]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([5]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'bar');
|
||||
assert.equal(optionsService.options['cursorBlink'], true);
|
||||
|
||||
optionsService.options = clone(DEFAULT_OPTIONS);
|
||||
inputHandler.setCursorStyle(Params.fromArray([6]), collect);
|
||||
inputHandler.setCursorStyle(Params.fromArray([6]));
|
||||
assert.equal(optionsService.options['cursorStyle'], 'bar');
|
||||
assert.equal(optionsService.options['cursorBlink'], false);
|
||||
});
|
||||
@@ -93,14 +92,13 @@ describe('InputHandler', () => {
|
||||
describe('setMode', () => {
|
||||
it('should toggle Terminal.bracketedPasteMode', () => {
|
||||
const terminal = new MockInputHandlingTerminal();
|
||||
const collect = '?';
|
||||
terminal.bracketedPasteMode = false;
|
||||
const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService());
|
||||
// Set bracketed paste mode
|
||||
inputHandler.setMode(Params.fromArray([2004]), collect);
|
||||
inputHandler.setModePrivate(Params.fromArray([2004]));
|
||||
assert.equal(terminal.bracketedPasteMode, true);
|
||||
// Reset bracketed paste mode
|
||||
inputHandler.resetMode(Params.fromArray([2004]), collect);
|
||||
inputHandler.resetModePrivate(Params.fromArray([2004]));
|
||||
assert.equal(terminal.bracketedPasteMode, false);
|
||||
});
|
||||
});
|
||||
|
||||
+204
-213
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -55,7 +55,7 @@ import { Disposable } from 'common/Lifecycle';
|
||||
import { IBufferSet, IBuffer } from 'common/buffer/Types';
|
||||
import { Attributes } from 'common/buffer/Constants';
|
||||
import { MouseService } from 'browser/services/MouseService';
|
||||
import { IParams } from 'common/parser/Types';
|
||||
import { IParams, IFunctionIdentifier } from 'common/parser/Types';
|
||||
import { CoreService } from 'common/services/CoreService';
|
||||
import { LogService } from 'common/services/LogService';
|
||||
import { ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport } from 'browser/Types';
|
||||
@@ -1395,18 +1395,18 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
}
|
||||
|
||||
/** Add handler for ESC escape sequence. See xterm.d.ts for details. */
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._inputHandler.addEscHandler(collectAndFlag, handler);
|
||||
public addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable {
|
||||
return this._inputHandler.addEscHandler(id, callback);
|
||||
}
|
||||
|
||||
/** Add handler for DCS escape sequence. See xterm.d.ts for details. */
|
||||
public addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable {
|
||||
return this._inputHandler.addDcsHandler(collectAndFlag, callback);
|
||||
public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable {
|
||||
return this._inputHandler.addDcsHandler(id, callback);
|
||||
}
|
||||
|
||||
/** Add handler for CSI escape sequence. See xterm.d.ts for details. */
|
||||
public addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable {
|
||||
return this._inputHandler.addCsiHandler(flag, callback);
|
||||
public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable {
|
||||
return this._inputHandler.addCsiHandler(id, callback);
|
||||
}
|
||||
/** Add handler for OSC escape sequence. See xterm.d.ts for details. */
|
||||
public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { IColorManager, IColorSet, ILinkMatcherOptions, ILinkifier, IViewport } from 'browser/Types';
|
||||
import { IOptionsService } from 'common/services/Services';
|
||||
import { EventEmitter } from 'common/EventEmitter';
|
||||
import { IParams } from 'common/parser/Types';
|
||||
import { IParams, IFunctionIdentifier } from 'common/parser/Types';
|
||||
import { ISelectionService } from 'browser/services/Services';
|
||||
|
||||
export class TestTerminal extends Terminal {
|
||||
@@ -74,13 +74,13 @@ export class MockTerminal implements ITerminal {
|
||||
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable {
|
||||
addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable {
|
||||
addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
|
||||
|
||||
Vendored
+6
-5
@@ -9,7 +9,7 @@ import { IEvent, IEventEmitter } from 'common/EventEmitter';
|
||||
import { IColorSet, ILinkifier, ILinkMatcherOptions, IViewport } from 'browser/Types';
|
||||
import { IOptionsService } from 'common/services/Services';
|
||||
import { IBuffer, IBufferSet } from 'common/buffer/Types';
|
||||
import { IParams } from 'common/parser/Types';
|
||||
import { IParams, IFunctionIdentifier } from 'common/parser/Types';
|
||||
|
||||
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
|
||||
|
||||
@@ -113,7 +113,8 @@ export interface IInputHandler {
|
||||
/** CSI ` */ charPosAbsolute(params: IParams): void;
|
||||
/** CSI a */ hPositionRelative(params: IParams): void;
|
||||
/** CSI b */ repeatPrecedingCharacter(params: IParams): void;
|
||||
/** CSI c */ sendDeviceAttributes(params: IParams, collect?: string): void;
|
||||
/** CSI c */ sendDeviceAttributesPrimary(params: IParams): void;
|
||||
sendDeviceAttributesSecondary(params: IParams): void;
|
||||
/** CSI d */ linePosAbsolute(params: IParams): void;
|
||||
/** CSI e */ vPositionRelative(params: IParams): void;
|
||||
/** CSI f */ hVPosition(params: IParams): void;
|
||||
@@ -200,9 +201,9 @@ export interface IPublicTerminal extends IDisposable {
|
||||
writeln(data: string): void;
|
||||
open(parent: HTMLElement): void;
|
||||
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable;
|
||||
addDcsHandler(collectAndFlag: string, callback: (param: IParams, data: string) => boolean): IDisposable;
|
||||
addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable;
|
||||
addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable;
|
||||
addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable;
|
||||
addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable;
|
||||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
|
||||
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number;
|
||||
deregisterLinkMatcher(matcherId: number): void;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { assert } from 'chai';
|
||||
import { DcsParser, DcsHandlerFactory } from 'common/parser/DcsParser';
|
||||
import { IDcsHandler, IParams } from 'common/parser/Types';
|
||||
import { IDcsHandler, IParams, IFunctionIdentifier } from 'common/parser/Types';
|
||||
import { utf32ToString, StringToUtf32 } from 'common/input/TextDecoder';
|
||||
import { Params } from 'common/parser/Params';
|
||||
import { PAYLOAD_LIMIT } from 'common/parser/Constants';
|
||||
@@ -16,10 +16,47 @@ function toUtf32(s: string): Uint32Array {
|
||||
return utf32.subarray(0, length);
|
||||
}
|
||||
|
||||
function identifier(id: IFunctionIdentifier): number {
|
||||
let res = 0;
|
||||
if (id.prefix) {
|
||||
if (id.prefix.length > 1) {
|
||||
throw new Error('only one byte as prefix supported');
|
||||
}
|
||||
res = id.prefix.charCodeAt(0);
|
||||
if (res && 0x3c > res || res > 0x3f) {
|
||||
throw new Error('prefix must be in range 0x3c .. 0x3f');
|
||||
}
|
||||
}
|
||||
if (id.intermediates) {
|
||||
if (id.intermediates.length > 2) {
|
||||
throw new Error('only two bytes as intermediates are supported');
|
||||
}
|
||||
for (let i = 0; i < id.intermediates.length; ++i) {
|
||||
const intermediate = id.intermediates.charCodeAt(i);
|
||||
if (0x20 > intermediate || intermediate > 0x2f) {
|
||||
throw new Error('intermediate must be in range 0x20 .. 0x2f');
|
||||
}
|
||||
res <<= 8;
|
||||
res |= intermediate;
|
||||
}
|
||||
}
|
||||
if (id.final.length !== 1) {
|
||||
throw new Error('final must be a single byte');
|
||||
}
|
||||
const finalCode = id.final.charCodeAt(0);
|
||||
if (0x40 > finalCode || finalCode > 0x7e) {
|
||||
throw new Error('final must be in range 0x40 .. 0x7e');
|
||||
}
|
||||
res <<= 8;
|
||||
res |= finalCode;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
class TestHandler implements IDcsHandler {
|
||||
constructor(public output: any[], public msg: string, public returnFalse: boolean = false) {}
|
||||
hook(collect: string, params: IParams, flag: number): void {
|
||||
this.output.push([this.msg, 'HOOK', params.toArray(), collect, flag]);
|
||||
hook(params: IParams): void {
|
||||
this.output.push([this.msg, 'HOOK', params.toArray()]);
|
||||
}
|
||||
put(data: Uint32Array, start: number, end: number): void {
|
||||
this.output.push([this.msg, 'PUT', utf32ToString(data, start, end)]);
|
||||
@@ -39,16 +76,16 @@ describe('DcsParser', () => {
|
||||
reports = [];
|
||||
parser = new DcsParser();
|
||||
parser.setDcsHandlerFallback((id, action, data) => {
|
||||
if (data.params) {
|
||||
data.params = data.params.toArray();
|
||||
if (action === 'HOOK') {
|
||||
data = data.toArray();
|
||||
}
|
||||
reports.push([id, action, data]);
|
||||
});
|
||||
});
|
||||
describe('handler registration', () => {
|
||||
it('setDcsHandler', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th'));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(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);
|
||||
data = toUtf32('the mouse!');
|
||||
@@ -56,16 +93,16 @@ describe('DcsParser', () => {
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
// messages from TestHandler
|
||||
['th', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th', 'HOOK', [1, 2, 3]],
|
||||
['th', 'PUT', 'Here comes'],
|
||||
['th', 'PUT', 'the mouse!'],
|
||||
['th', 'UNHOOK', true]
|
||||
]);
|
||||
});
|
||||
it('clearDcsHandler', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th'));
|
||||
parser.clearDcsHandler('+p');
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.clearDcsHandler(identifier({intermediates: '+', final: 'p'}));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
@@ -73,24 +110,24 @@ describe('DcsParser', () => {
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
// messages from fallback handler
|
||||
['+p', 'HOOK', {collect: '+', params: [1, 2, 3], flag: 'p'.charCodeAt(0)}],
|
||||
['+p', 'PUT', 'Here comes'],
|
||||
['+p', 'PUT', 'the mouse!'],
|
||||
['+p', 'UNHOOK', true]
|
||||
[identifier({intermediates: '+', final: 'p'}), 'HOOK', [1, 2, 3]],
|
||||
[identifier({intermediates: '+', final: 'p'}), 'PUT', 'Here comes'],
|
||||
[identifier({intermediates: '+', final: 'p'}), 'PUT', 'the mouse!'],
|
||||
[identifier({intermediates: '+', final: 'p'}), 'UNHOOK', true]
|
||||
]);
|
||||
});
|
||||
it('addDcsHandler', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler('+p', new TestHandler(reports, 'th2'));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler(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);
|
||||
data = toUtf32('the mouse!');
|
||||
parser.put(data, 0, data.length);
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
['th2', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th1', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th2', 'HOOK', [1, 2, 3]],
|
||||
['th1', 'HOOK', [1, 2, 3]],
|
||||
['th2', 'PUT', 'Here comes'],
|
||||
['th1', 'PUT', 'Here comes'],
|
||||
['th2', 'PUT', 'the mouse!'],
|
||||
@@ -100,17 +137,17 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('addDcsHandler with return false', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler('+p', new TestHandler(reports, 'th2', true));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler(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);
|
||||
data = toUtf32('the mouse!');
|
||||
parser.put(data, 0, data.length);
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
['th2', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th1', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th2', 'HOOK', [1, 2, 3]],
|
||||
['th1', 'HOOK', [1, 2, 3]],
|
||||
['th2', 'PUT', 'Here comes'],
|
||||
['th1', 'PUT', 'Here comes'],
|
||||
['th2', 'PUT', 'the mouse!'],
|
||||
@@ -120,17 +157,17 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('dispose handlers', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th1'));
|
||||
const dispo = parser.addDcsHandler('+p', new TestHandler(reports, 'th2', true));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
const dispo = parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
dispo.dispose();
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
parser.put(data, 0, data.length);
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
['th1', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th1', 'HOOK', [1, 2, 3]],
|
||||
['th1', 'PUT', 'Here comes'],
|
||||
['th1', 'PUT', 'the mouse!'],
|
||||
['th1', 'UNHOOK', true]
|
||||
@@ -139,8 +176,8 @@ describe('DcsParser', () => {
|
||||
});
|
||||
describe('DcsHandlerFactory', () => {
|
||||
it('should be called once on end(true)', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -149,8 +186,8 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, [[[1, 2, 3], 'Here comes the mouse!']]);
|
||||
});
|
||||
it('should not be called on end(false)', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -159,9 +196,9 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, []);
|
||||
});
|
||||
it('should be disposable', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params.toArray(), data])));
|
||||
const dispo = parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['two', params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push(['one', params.toArray(), data])));
|
||||
const dispo = parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push(['two', params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -169,7 +206,7 @@ describe('DcsParser', () => {
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!']]);
|
||||
dispo.dispose();
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
data = toUtf32('some other');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' data');
|
||||
@@ -178,9 +215,9 @@ 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.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params.toArray(), data])));
|
||||
parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { reports.push(['two', params.toArray(), data]); return false; }));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push(['one', params.toArray(), data])));
|
||||
parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((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);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -190,8 +227,8 @@ describe('DcsParser', () => {
|
||||
});
|
||||
it('should work up to payload limit', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
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) {
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -201,8 +238,8 @@ describe('DcsParser', () => {
|
||||
});
|
||||
it('should abort for payload limit +1', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
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) {
|
||||
parser.put(data, 0, data.length);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { IDisposable } from 'common/Types';
|
||||
import { IDcsHandler, IParams, ParamsArray, IHandlerCollection, IDcsParser, DcsFallbackHandler } from 'common/parser/Types';
|
||||
import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandler } from 'common/parser/Types';
|
||||
import { utf32ToString } from 'common/input/TextDecoder';
|
||||
import { Params } from 'common/parser/Params';
|
||||
import { PAYLOAD_LIMIT } from 'common/parser/Constants';
|
||||
@@ -13,7 +13,7 @@ import { PAYLOAD_LIMIT } from 'common/parser/Constants';
|
||||
export class DcsParser implements IDcsParser {
|
||||
private _handlers: IHandlerCollection<IDcsHandler> = Object.create(null);
|
||||
private _active: IDcsHandler[] = [];
|
||||
private _collectAndFlag: string = '';
|
||||
private _ident: number = 0;
|
||||
private _handlerFb: DcsFallbackHandler = () => {};
|
||||
|
||||
public dispose(): void {
|
||||
@@ -21,11 +21,11 @@ export class DcsParser implements IDcsParser {
|
||||
this._handlerFb = () => {};
|
||||
}
|
||||
|
||||
public addDcsHandler(collectAndFlag: string, handler: IDcsHandler): IDisposable {
|
||||
if (this._handlers[collectAndFlag] === undefined) {
|
||||
this._handlers[collectAndFlag] = [];
|
||||
public addDcsHandler(ident: number, handler: IDcsHandler): IDisposable {
|
||||
if (this._handlers[ident] === undefined) {
|
||||
this._handlers[ident] = [];
|
||||
}
|
||||
const handlerList = this._handlers[collectAndFlag];
|
||||
const handlerList = this._handlers[ident];
|
||||
handlerList.push(handler);
|
||||
return {
|
||||
dispose: () => {
|
||||
@@ -37,12 +37,12 @@ export class DcsParser implements IDcsParser {
|
||||
};
|
||||
}
|
||||
|
||||
public setDcsHandler(collectAndFlag: string, handler: IDcsHandler): void {
|
||||
this._handlers[collectAndFlag] = [handler];
|
||||
public setDcsHandler(ident: number, handler: IDcsHandler): void {
|
||||
this._handlers[ident] = [handler];
|
||||
}
|
||||
|
||||
public clearDcsHandler(collectAndFlag: string): void {
|
||||
if (this._handlers[collectAndFlag]) delete this._handlers[collectAndFlag];
|
||||
public clearDcsHandler(ident: number): void {
|
||||
if (this._handlers[ident]) delete this._handlers[ident];
|
||||
}
|
||||
|
||||
public setDcsHandlerFallback(handler: DcsFallbackHandler): void {
|
||||
@@ -54,24 +54,24 @@ export class DcsParser implements IDcsParser {
|
||||
this.unhook(false);
|
||||
}
|
||||
this._active = [];
|
||||
this._collectAndFlag = '';
|
||||
this._ident = 0;
|
||||
}
|
||||
|
||||
public hook(collect: string, params: IParams, flag: number): void {
|
||||
this._collectAndFlag = collect + String.fromCharCode(flag);
|
||||
this._active = this._handlers[this._collectAndFlag] || [];
|
||||
public hook(ident: number, params: IParams): void {
|
||||
this._ident = ident;
|
||||
this._active = this._handlers[ident] || [];
|
||||
if (!this._active.length) {
|
||||
this._handlerFb(this._collectAndFlag, 'HOOK', {collect, params, flag});
|
||||
this._handlerFb(this._ident, 'HOOK', params);
|
||||
} else {
|
||||
for (let j = this._active.length - 1; j >= 0; j--) {
|
||||
this._active[j].hook(collect, params, flag);
|
||||
this._active[j].hook(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public put(data: Uint32Array, start: number, end: number): void {
|
||||
if (!this._active.length) {
|
||||
this._handlerFb(this._collectAndFlag, 'PUT', utf32ToString(data, start, end));
|
||||
this._handlerFb(this._ident, 'PUT', utf32ToString(data, start, end));
|
||||
} else {
|
||||
for (let j = this._active.length - 1; j >= 0; j--) {
|
||||
this._active[j].put(data, start, end);
|
||||
@@ -81,7 +81,7 @@ export class DcsParser implements IDcsParser {
|
||||
|
||||
public unhook(success: boolean): void {
|
||||
if (!this._active.length) {
|
||||
this._handlerFb(this._collectAndFlag, 'UNHOOK', success);
|
||||
this._handlerFb(this._ident, 'UNHOOK', success);
|
||||
} else {
|
||||
let j = this._active.length - 1;
|
||||
for (; j >= 0; j--) {
|
||||
@@ -96,7 +96,7 @@ export class DcsParser implements IDcsParser {
|
||||
}
|
||||
}
|
||||
this._active = [];
|
||||
this._collectAndFlag = '';
|
||||
this._ident = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,9 +109,9 @@ export class DcsHandlerFactory implements IDcsHandler {
|
||||
private _params: IParams | undefined;
|
||||
private _hitLimit: boolean = false;
|
||||
|
||||
constructor(private _handler: (params: IParams, data: string) => any) {}
|
||||
constructor(private _handler: (data: string, params: IParams) => any) {}
|
||||
|
||||
public hook(collect: string, params: IParams, flag: number): void {
|
||||
public hook(params: IParams): void {
|
||||
this._params = params.clone();
|
||||
this._data = '';
|
||||
this._hitLimit = false;
|
||||
@@ -133,7 +133,7 @@ export class DcsHandlerFactory implements IDcsHandler {
|
||||
if (this._hitLimit) {
|
||||
ret = false;
|
||||
} else if (success) {
|
||||
ret = this._handler(this._params ? this._params : new Params(), this._data);
|
||||
ret = this._handler(this._data, this._params ? this._params : new Params());
|
||||
}
|
||||
this._params = undefined;
|
||||
this._data = '';
|
||||
|
||||
@@ -73,10 +73,14 @@ class TestEscapeSequenceParser extends EscapeSequenceParser {
|
||||
return this._params;
|
||||
}
|
||||
public get collect(): string {
|
||||
return this._collect;
|
||||
return this.identToString(this._collect);
|
||||
}
|
||||
public set collect(value: string) {
|
||||
this._collect = value;
|
||||
this._collect = 0;
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
this._collect <<= 8;
|
||||
this._collect |= value.charCodeAt(i);
|
||||
}
|
||||
}
|
||||
public mockOscParser(): void {
|
||||
this._oscParser = oscPutParser;
|
||||
@@ -111,8 +115,8 @@ const testTerminal: any = {
|
||||
actionESC: function (collect: string, flag: string): void {
|
||||
this.calls.push(['esc', collect, flag]);
|
||||
},
|
||||
actionDCSHook: function (collect: string, params: IParams, flag: string): void {
|
||||
this.calls.push(['dcs hook', collect, params.toArray(), flag]);
|
||||
actionDCSHook: function (params: IParams): void {
|
||||
this.calls.push(['dcs hook', params.toArray()]);
|
||||
},
|
||||
actionDCSPrint: function (s: string): void {
|
||||
this.calls.push(['dcs put', s]);
|
||||
@@ -144,11 +148,13 @@ let state: any;
|
||||
const testParser = new TestEscapeSequenceParser();
|
||||
testParser.mockOscParser();
|
||||
testParser.setPrintHandler(testTerminal.print.bind(testTerminal));
|
||||
testParser.setCsiHandlerFallback((collect: string, params: IParams, flag: number) => {
|
||||
testTerminal.actionCSI(collect, params, String.fromCharCode(flag));
|
||||
testParser.setCsiHandlerFallback((ident: number, params: IParams) => {
|
||||
const id = testParser.identToString(ident);
|
||||
testTerminal.actionCSI(id.slice(0, -1), params, id.slice(-1));
|
||||
});
|
||||
testParser.setEscHandlerFallback((collect: string, flag: number) => {
|
||||
testTerminal.actionESC(collect, String.fromCharCode(flag));
|
||||
testParser.setEscHandlerFallback((ident: number) => {
|
||||
const id = testParser.identToString(ident);
|
||||
testTerminal.actionESC(id.slice(0, -1), id.slice(-1));
|
||||
});
|
||||
testParser.setExecuteHandlerFallback((code: number) => {
|
||||
testTerminal.actionExecute(String.fromCharCode(code));
|
||||
@@ -160,7 +166,7 @@ testParser.setOscHandlerFallback((identifier, action, data) => {
|
||||
testParser.setDcsHandlerFallback((collectAndFlag, action, payload) => {
|
||||
switch (action) {
|
||||
case 'HOOK':
|
||||
testTerminal.actionDCSHook(payload.collect, payload.params, String.fromCharCode(payload.flag));
|
||||
testTerminal.actionDCSHook(payload);
|
||||
break;
|
||||
case 'PUT':
|
||||
testTerminal.actionDCSPrint(payload);
|
||||
@@ -939,7 +945,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
parser.currentState = ParserState.DCS_ENTRY;
|
||||
parse(parser, collect[i]);
|
||||
chai.expect(parser.currentState).equal(ParserState.DCS_PASSTHROUGH);
|
||||
testTerminal.compare([['dcs hook', '', [0], collect[i]]]);
|
||||
testTerminal.compare([['dcs hook', [0]]]);
|
||||
parser.reset();
|
||||
testTerminal.clear();
|
||||
}
|
||||
@@ -952,7 +958,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
parser.currentState = ParserState.DCS_PARAM;
|
||||
parse(parser, collect[i]);
|
||||
chai.expect(parser.currentState).equal(ParserState.DCS_PASSTHROUGH);
|
||||
testTerminal.compare([['dcs hook', '', [0], collect[i]]]);
|
||||
testTerminal.compare([['dcs hook', [0]]]);
|
||||
parser.reset();
|
||||
testTerminal.clear();
|
||||
}
|
||||
@@ -965,7 +971,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
parser.currentState = ParserState.DCS_INTERMEDIATE;
|
||||
parse(parser, collect[i]);
|
||||
chai.expect(parser.currentState).equal(ParserState.DCS_PASSTHROUGH);
|
||||
testTerminal.compare([['dcs hook', '', [0], collect[i]]]);
|
||||
testTerminal.compare([['dcs hook', [0]]]);
|
||||
parser.reset();
|
||||
testTerminal.clear();
|
||||
}
|
||||
@@ -1024,14 +1030,14 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('single DCS', function (): void {
|
||||
test('\x1bP1;2;3+$aäbc;däe\x9c', [
|
||||
['dcs hook', '+$', [1, 2, 3], 'a'],
|
||||
['dcs hook', [1, 2, 3]],
|
||||
['dcs put', 'äbc;däe'],
|
||||
['dcs unhook']
|
||||
], null);
|
||||
});
|
||||
it('multi DCS', function (): void {
|
||||
test('\x1bP1;2;3+$abc;de', [
|
||||
['dcs hook', '+$', [1, 2, 3], 'a'],
|
||||
['dcs hook', [1, 2, 3]],
|
||||
['dcs put', 'bc;de']
|
||||
], null);
|
||||
testTerminal.clear();
|
||||
@@ -1043,7 +1049,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('print + DCS(C1)', function (): void {
|
||||
test('abc\x901;2;3+$abc;de\x9c', [
|
||||
['print', 'abc'],
|
||||
['dcs hook', '+$', [1, 2, 3], 'a'],
|
||||
['dcs hook', [1, 2, 3]],
|
||||
['dcs put', 'bc;de'],
|
||||
['dcs unhook']
|
||||
], null);
|
||||
@@ -1086,7 +1092,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('colon notation in DCS params', function (): void {
|
||||
test('abc\x901;2::55;3+$abc;de\x9c', [
|
||||
['print', 'abc'],
|
||||
['dcs hook', '+$', [1, 2, [-1, 55], 3], 'a'],
|
||||
['dcs hook', [1, 2, [-1, 55], 3]],
|
||||
['dcs put', 'bc;de'],
|
||||
['dcs unhook']
|
||||
], null);
|
||||
@@ -1120,7 +1126,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
parser.currentState = ParserState.DCS_PASSTHROUGH;
|
||||
parse(parser, '\x901;2;3+$a€öäü');
|
||||
chai.expect(parser.currentState).equal(ParserState.DCS_PASSTHROUGH);
|
||||
testTerminal.compare([['dcs hook', '+$', [1, 2, 3], 'a'], ['dcs put', '€öäü']]);
|
||||
testTerminal.compare([['dcs hook', [1, 2, 3]], ['dcs put', '€öäü']]);
|
||||
parser.reset();
|
||||
testTerminal.clear();
|
||||
});
|
||||
@@ -1172,69 +1178,69 @@ describe('EscapeSequenceParser', function (): void {
|
||||
chai.expect(print).equal('');
|
||||
});
|
||||
it('ESC handler', function (): void {
|
||||
parser2.setEscHandler('%G', function (): void {
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, function (): void {
|
||||
esc.push('%G');
|
||||
});
|
||||
parser2.setEscHandler('E', function (): void {
|
||||
parser2.setEscHandler({final: 'E'}, function (): void {
|
||||
esc.push('E');
|
||||
});
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['%G', 'E']);
|
||||
parser2.clearEscHandler('%G');
|
||||
parser2.clearEscHandler('%G'); // should not throw
|
||||
parser2.clearEscHandler({intermediates: '%', final: 'G'});
|
||||
parser2.clearEscHandler({intermediates: '%', final: 'G'}); // should not throw
|
||||
clearAccu();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['E']);
|
||||
parser2.clearEscHandler('E');
|
||||
parser2.clearEscHandler({final: 'E'});
|
||||
clearAccu();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql([]);
|
||||
});
|
||||
describe('ESC custom handlers', () => {
|
||||
it('prevent fallback', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => esc.push('default - %G'));
|
||||
parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom - %G']);
|
||||
});
|
||||
it('allow fallback', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return false; });
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => esc.push('default - %G'));
|
||||
parser2.addEscHandler({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('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom2 - %G'); return false; });
|
||||
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; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom2 - %G', 'custom - %G']);
|
||||
});
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom2 - %G'); return true; });
|
||||
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; });
|
||||
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('%G', () => order.push(1));
|
||||
parser2.addEscHandler('%G', () => { order.push(2); return false; });
|
||||
parser2.addEscHandler('%G', () => { order.push(3); return false; });
|
||||
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; });
|
||||
parse(parser2, '\x1b%G');
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
const dispo = parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => esc.push('default - %G'));
|
||||
const dispo = parser2.addEscHandler({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('%G', () => esc.push('default - %G'));
|
||||
const dispo = parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.setEscHandler({intermediates: '%', final: 'G'}, () => esc.push('default - %G'));
|
||||
const dispo = parser2.addEscHandler({intermediates: '%', final: 'G'}, () => { esc.push('custom - %G'); return true; });
|
||||
dispo.dispose();
|
||||
dispo.dispose();
|
||||
parse(parser2, INPUT);
|
||||
@@ -1242,13 +1248,13 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
});
|
||||
it('CSI handler', function (): void {
|
||||
parser2.setCsiHandler('m', function (params: IParams, collect: string): void {
|
||||
csi.push(['m', params.toArray(), collect]);
|
||||
parser2.setCsiHandler({final: 'm'}, function (params: IParams): void {
|
||||
csi.push(['m', params.toArray(), '']);
|
||||
});
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
parser2.clearCsiHandler('m');
|
||||
parser2.clearCsiHandler('m'); // should not throw
|
||||
parser2.clearCsiHandler({final: 'm'});
|
||||
parser2.clearCsiHandler({final: 'm'}); // should not throw
|
||||
clearAccu();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([]);
|
||||
@@ -1256,16 +1262,16 @@ describe('EscapeSequenceParser', function (): void {
|
||||
describe('CSI custom handlers', () => {
|
||||
it('Prevent fallback', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler('m', (params, collect) => csi.push(['m', params.toArray(), collect]));
|
||||
parser2.addCsiHandler('m', (params, collect) => { csiCustom.push(['m', params.toArray(), collect]); return true; });
|
||||
parser2.setCsiHandler({final: 'm'}, params => csi.push(['m', params.toArray(), '']));
|
||||
parser2.addCsiHandler({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('m', (params, collect) => csi.push(['m', params.toArray(), collect]));
|
||||
parser2.addCsiHandler('m', (params, collect) => { csiCustom.push(['m', params.toArray(), collect]); return false; });
|
||||
parser2.setCsiHandler({final: 'm'}, params => csi.push(['m', params.toArray(), '']));
|
||||
parser2.addCsiHandler({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], '']]);
|
||||
@@ -1273,9 +1279,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('Multiple custom handlers fallback once', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
const csiCustom2: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler('m', (params, collect) => csi.push(['m', params.toArray(), collect]));
|
||||
parser2.addCsiHandler('m', (params, collect) => { csiCustom.push(['m', params.toArray(), collect]); return true; });
|
||||
parser2.addCsiHandler('m', (params, collect) => { csiCustom2.push(['m', params.toArray(), collect]); return false; });
|
||||
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; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(csiCustom).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
@@ -1284,9 +1290,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
const csiCustom2: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler('m', (params, collect) => csi.push(['m', params.toArray(), collect]));
|
||||
parser2.addCsiHandler('m', (params, collect) => { csiCustom.push(['m', params.toArray(), collect]); return true; });
|
||||
parser2.addCsiHandler('m', (params, collect) => { csiCustom2.push(['m', params.toArray(), collect]); return true; });
|
||||
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; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([], 'Should not fallback to original handler');
|
||||
chai.expect(csiCustom).eql([], 'Should not fallback once');
|
||||
@@ -1294,16 +1300,16 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('Execution order should go from latest handler down to the original', () => {
|
||||
const order: number[] = [];
|
||||
parser2.setCsiHandler('m', () => order.push(1));
|
||||
parser2.addCsiHandler('m', () => { order.push(2); return false; });
|
||||
parser2.addCsiHandler('m', () => { order.push(3); return false; });
|
||||
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; });
|
||||
parse(parser2, '\x1b[0m');
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler('m', (params, collect) => csi.push(['m', params.toArray(), collect]));
|
||||
const customHandler = parser2.addCsiHandler('m', (params, collect) => { csiCustom.push(['m', params.toArray(), collect]); return true; });
|
||||
parser2.setCsiHandler({final: 'm'}, params => csi.push(['m', params.toArray(), '']));
|
||||
const customHandler = parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
customHandler.dispose();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(csi).eql([['m', [1, 31], ''], ['m', [0], '']]);
|
||||
@@ -1311,8 +1317,8 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
it('Should not corrupt the parser when dispose is called twice', () => {
|
||||
const csiCustom: [string, ParamsArray, string][] = [];
|
||||
parser2.setCsiHandler('m', (params, collect) => csi.push(['m', params.toArray(), collect]));
|
||||
const customHandler = parser2.addCsiHandler('m', (params, collect) => { csiCustom.push(['m', params.toArray(), collect]); return true; });
|
||||
parser2.setCsiHandler({final: 'm'}, params => csi.push(['m', params.toArray(), '']));
|
||||
const customHandler = parser2.addCsiHandler({final: 'm'}, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
|
||||
customHandler.dispose();
|
||||
customHandler.dispose();
|
||||
parse(parser2, INPUT);
|
||||
@@ -1415,9 +1421,9 @@ describe('EscapeSequenceParser', function (): void {
|
||||
});
|
||||
});
|
||||
it('DCS handler', function (): void {
|
||||
parser2.setDcsHandler('+p', {
|
||||
hook: function (collect: string, params: IParams, flag: number): void {
|
||||
dcs.push(['hook', collect, params.toArray(), flag]);
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, {
|
||||
hook: function (params: IParams): void {
|
||||
dcs.push(['hook', '', params.toArray(), 0]);
|
||||
},
|
||||
put: function (data: Uint32Array, start: number, end: number): void {
|
||||
let s = '';
|
||||
@@ -1433,12 +1439,12 @@ describe('EscapeSequenceParser', function (): void {
|
||||
parse(parser2, '\x1bP1;2;3+pabc');
|
||||
parse(parser2, ';de\x9c');
|
||||
chai.expect(dcs).eql([
|
||||
['hook', '+', [1, 2, 3], 'p'.charCodeAt(0)],
|
||||
['hook', '', [1, 2, 3], 0],
|
||||
['put', 'abc'], ['put', ';de'],
|
||||
['unhook']
|
||||
]);
|
||||
parser2.clearDcsHandler('+p');
|
||||
parser2.clearDcsHandler('+p'); // should not throw
|
||||
parser2.clearDcsHandler({intermediates: '+', final: 'p'});
|
||||
parser2.clearDcsHandler({intermediates: '+', final: 'p'}); // should not throw
|
||||
clearAccu();
|
||||
parse(parser2, '\x1bP1;2;3+pabc');
|
||||
parse(parser2, ';de\x9c');
|
||||
@@ -1448,54 +1454,54 @@ describe('EscapeSequenceParser', function (): void {
|
||||
const DCS_INPUT = '\x1bP1;2;3+pabc\x1b\\';
|
||||
it('Prevent fallback', () => {
|
||||
const dcsCustom: [string, (number | number[])[], string][] = [];
|
||||
parser2.setDcsHandler('+p', new DcsHandlerFactory((params, data) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((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('+p', new DcsHandlerFactory((params, data) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['B', params.toArray(), data]); return false; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((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('+p', new DcsHandlerFactory((params, data) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['C', params.toArray(), data]); return false; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((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('+p', new DcsHandlerFactory((params, data) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['C', params.toArray(), data]); return true; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((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('+p', new DcsHandlerFactory(() => order.push(1)));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory(() => { order.push(2); return false; }));
|
||||
parser2.addDcsHandler('+p', new DcsHandlerFactory(() => { order.push(3); return false; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory(() => order.push(1)));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory(() => { order.push(2); return false; }));
|
||||
parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory(() => { 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('+p', new DcsHandlerFactory((params, data) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
const dispo = parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
const dispo = parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((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('+p', new DcsHandlerFactory((params, data) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
const dispo = parser2.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
parser2.setDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => dcsCustom.push(['A', params.toArray(), data])));
|
||||
const dispo = parser2.addDcsHandler({intermediates: '+', final: 'p'}, new DcsHandlerFactory((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
|
||||
dispo.dispose();
|
||||
dispo.dispose();
|
||||
parse(parser2, DCS_INPUT);
|
||||
@@ -1513,8 +1519,7 @@ describe('EscapeSequenceParser', function (): void {
|
||||
position: 6,
|
||||
code: '€'.charCodeAt(0),
|
||||
currentState: ParserState.CSI_PARAM,
|
||||
osc: '',
|
||||
collect: '',
|
||||
collect: 0,
|
||||
params: Params.fromArray([1, 2, 0]), // extra zero here
|
||||
abort: false
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandler, OscFallbackHandler, IOscParser, EscHandler, IDcsParser, DcsFallbackHandler } from 'common/parser/Types';
|
||||
import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandler, OscFallbackHandler, IOscParser, EscHandler, IDcsParser, DcsFallbackHandler, IFunctionIdentifier } from 'common/parser/Types';
|
||||
import { ParserState, ParserAction } from 'common/parser/Constants';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IDisposable } from 'common/Types';
|
||||
@@ -206,17 +206,25 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
|
||||
* To implement custom ANSI compliant escape sequences it is not needed to
|
||||
* alter this parser, instead consider registering a custom handler.
|
||||
* For non ANSI compliant sequences change the transition table with
|
||||
* the optional `transitions` contructor argument and
|
||||
* the optional `transitions` constructor argument and
|
||||
* reimplement the `parse` method.
|
||||
*
|
||||
* This parser is currently hardcoded to operate in ZDM (Zero Default Mode)
|
||||
* as suggested by the original parser, thus empty parameters are set to 0.
|
||||
* This this is not in line with the latest ECMA specification
|
||||
* This this is not in line with the latest ECMA-48 specification
|
||||
* (ZDM was part of the early specs and got completely removed later on).
|
||||
*
|
||||
* Other than the original parser from vt100.net this parser supports
|
||||
* sub parameters in digital parameters separated by colons. Empty sub parameters
|
||||
* are set to -1.
|
||||
* are set to -1 (no ZDM for sub parameters).
|
||||
*
|
||||
* About prefix and intermediate bytes:
|
||||
* This parser follows the assumptions of the vt100.net parser with these restrictions:
|
||||
* - only one prefix byte is allowed as first parameter byte, byte range 0x3c .. 0x3f
|
||||
* - max. two intermediates are respected, byte range 0x20 .. 0x2f
|
||||
* Note that this is not in line with ECMA-48 which does not limit either of those.
|
||||
* Furthermore ECMA-48 allows the prefix byte range at any param byte position. Currently
|
||||
* there are no known sequences that follow the broader definition of the specification.
|
||||
*
|
||||
* TODO: implement error recovery hook via error handler return values
|
||||
*/
|
||||
@@ -227,7 +235,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
|
||||
// buffers over several parse calls
|
||||
protected _params: Params;
|
||||
protected _collect: string;
|
||||
protected _collect: number;
|
||||
|
||||
// handler lookup containers
|
||||
protected _printHandler: (data: Uint32Array, start: number, end: number) => void;
|
||||
@@ -241,8 +249,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
// fallback handlers
|
||||
protected _printHandlerFb: (data: Uint32Array, start: number, end: number) => void;
|
||||
protected _executeHandlerFb: (code: number) => void;
|
||||
protected _csiHandlerFb: (collect: string, params: IParams, flag: number) => void;
|
||||
protected _escHandlerFb: (collect: string, flag: number) => void;
|
||||
protected _csiHandlerFb: (ident: number, params: IParams) => void;
|
||||
protected _escHandlerFb: (ident: number) => void;
|
||||
protected _errorHandlerFb: (state: IParsingState) => IParsingState;
|
||||
|
||||
constructor(readonly TRANSITIONS: TransitionTable = VT500_TRANSITION_TABLE) {
|
||||
@@ -252,14 +260,14 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this.currentState = this.initialState;
|
||||
this._params = new Params(); // defaults to 32 storable params/subparams
|
||||
this._params.addParam(0); // ZDM
|
||||
this._collect = '';
|
||||
this._collect = 0;
|
||||
this.precedingCodepoint = 0;
|
||||
|
||||
// set default fallback handlers and handler lookup containers
|
||||
this._printHandlerFb = (data, start, end): void => { };
|
||||
this._executeHandlerFb = (code: number): void => { };
|
||||
this._csiHandlerFb = (collect: string, params: IParams, flag: number): void => { };
|
||||
this._escHandlerFb = (collect: string, flag: number): void => { };
|
||||
this._csiHandlerFb = (ident: number, params: IParams): void => { };
|
||||
this._escHandlerFb = (ident: number): void => { };
|
||||
this._errorHandlerFb = (state: IParsingState): IParsingState => state;
|
||||
this._printHandler = this._printHandlerFb;
|
||||
this._executeHandlers = Object.create(null);
|
||||
@@ -270,7 +278,53 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._errorHandler = this._errorHandlerFb;
|
||||
|
||||
// swallow 7bit ST (ESC+\)
|
||||
this.setEscHandler('\\', () => {});
|
||||
this.setEscHandler({final: '\\'}, () => {});
|
||||
}
|
||||
|
||||
private _identifier(id: IFunctionIdentifier, finalRange: number[] = [0x40, 0x7e]): number {
|
||||
let res = 0;
|
||||
if (id.prefix) {
|
||||
if (id.prefix.length > 1) {
|
||||
throw new Error('only one byte as prefix supported');
|
||||
}
|
||||
res = id.prefix.charCodeAt(0);
|
||||
if (res && 0x3c > res || res > 0x3f) {
|
||||
throw new Error('prefix must be in range 0x3c .. 0x3f');
|
||||
}
|
||||
}
|
||||
if (id.intermediates) {
|
||||
if (id.intermediates.length > 2) {
|
||||
throw new Error('only two bytes as intermediates are supported');
|
||||
}
|
||||
for (let i = 0; i < id.intermediates.length; ++i) {
|
||||
const intermediate = id.intermediates.charCodeAt(i);
|
||||
if (0x20 > intermediate || intermediate > 0x2f) {
|
||||
throw new Error('intermediate must be in range 0x20 .. 0x2f');
|
||||
}
|
||||
res <<= 8;
|
||||
res |= intermediate;
|
||||
}
|
||||
}
|
||||
if (id.final.length !== 1) {
|
||||
throw new Error('final must be a single byte');
|
||||
}
|
||||
const finalCode = id.final.charCodeAt(0);
|
||||
if (finalRange[0] > finalCode || finalCode > finalRange[1]) {
|
||||
throw new Error(`final must be in range ${finalRange[0]} .. ${finalRange[1]}`);
|
||||
}
|
||||
res <<= 8;
|
||||
res |= finalCode;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public identToString(ident: number): string {
|
||||
const res: string[] = [];
|
||||
while (ident) {
|
||||
res.push(String.fromCharCode(ident & 0xFF));
|
||||
ident >>= 8;
|
||||
}
|
||||
return res.reverse().join('');
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -297,12 +351,12 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._executeHandlerFb = callback;
|
||||
}
|
||||
|
||||
addCsiHandler(flag: string, callback: CsiHandler): IDisposable {
|
||||
const index = flag.charCodeAt(0);
|
||||
if (this._csiHandlers[index] === undefined) {
|
||||
this._csiHandlers[index] = [];
|
||||
addCsiHandler(id: IFunctionIdentifier, callback: CsiHandler): IDisposable {
|
||||
const ident = this._identifier(id);
|
||||
if (this._csiHandlers[ident] === undefined) {
|
||||
this._csiHandlers[ident] = [];
|
||||
}
|
||||
const handlerList = this._csiHandlers[index];
|
||||
const handlerList = this._csiHandlers[ident];
|
||||
handlerList.push(callback);
|
||||
return {
|
||||
dispose: () => {
|
||||
@@ -313,21 +367,22 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
}
|
||||
};
|
||||
}
|
||||
setCsiHandler(flag: string, callback: (params: IParams, collect: string) => void): void {
|
||||
this._csiHandlers[flag.charCodeAt(0)] = [callback];
|
||||
setCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => void): void {
|
||||
this._csiHandlers[this._identifier(id)] = [callback];
|
||||
}
|
||||
clearCsiHandler(flag: string): void {
|
||||
if (this._csiHandlers[flag.charCodeAt(0)]) delete this._csiHandlers[flag.charCodeAt(0)];
|
||||
clearCsiHandler(id: IFunctionIdentifier): void {
|
||||
if (this._csiHandlers[this._identifier(id)]) delete this._csiHandlers[this._identifier(id)];
|
||||
}
|
||||
setCsiHandlerFallback(callback: (collect: string, params: IParams, flag: number) => void): void {
|
||||
setCsiHandlerFallback(callback: (ident: number, params: IParams) => void): void {
|
||||
this._csiHandlerFb = callback;
|
||||
}
|
||||
|
||||
addEscHandler(collectAndFlag: string, callback: EscHandler): IDisposable {
|
||||
if (this._escHandlers[collectAndFlag] === undefined) {
|
||||
this._escHandlers[collectAndFlag] = [];
|
||||
addEscHandler(id: IFunctionIdentifier, callback: EscHandler): IDisposable {
|
||||
const ident = this._identifier(id, [0x30, 0x7e]);
|
||||
if (this._escHandlers[ident] === undefined) {
|
||||
this._escHandlers[ident] = [];
|
||||
}
|
||||
const handlerList = this._escHandlers[collectAndFlag];
|
||||
const handlerList = this._escHandlers[ident];
|
||||
handlerList.push(callback);
|
||||
return {
|
||||
dispose: () => {
|
||||
@@ -338,13 +393,13 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
}
|
||||
};
|
||||
}
|
||||
setEscHandler(collectAndFlag: string, callback: () => void): void {
|
||||
this._escHandlers[collectAndFlag] = [callback];
|
||||
setEscHandler(id: IFunctionIdentifier, callback: () => void): void {
|
||||
this._escHandlers[this._identifier(id, [0x30, 0x7e])] = [callback];
|
||||
}
|
||||
clearEscHandler(collectAndFlag: string): void {
|
||||
if (this._escHandlers[collectAndFlag]) delete this._escHandlers[collectAndFlag];
|
||||
clearEscHandler(id: IFunctionIdentifier): void {
|
||||
if (this._escHandlers[this._identifier(id, [0x30, 0x7e])]) delete this._escHandlers[this._identifier(id, [0x30, 0x7e])];
|
||||
}
|
||||
setEscHandlerFallback(callback: (collect: string, flag: number) => void): void {
|
||||
setEscHandlerFallback(callback: (ident: number) => void): void {
|
||||
this._escHandlerFb = callback;
|
||||
}
|
||||
|
||||
@@ -361,14 +416,14 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._oscParser.setOscHandlerFallback(handler);
|
||||
}
|
||||
|
||||
addDcsHandler(collectAndFlag: string, handler: IDcsHandler): IDisposable {
|
||||
return this._dcsParser.addDcsHandler(collectAndFlag, handler);
|
||||
addDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable {
|
||||
return this._dcsParser.addDcsHandler(this._identifier(id), handler);
|
||||
}
|
||||
setDcsHandler(collectAndFlag: string, handler: IDcsHandler): void {
|
||||
this._dcsParser.setDcsHandler(collectAndFlag, handler);
|
||||
setDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): void {
|
||||
this._dcsParser.setDcsHandler(this._identifier(id), handler);
|
||||
}
|
||||
clearDcsHandler(collectAndFlag: string): void {
|
||||
this._dcsParser.clearDcsHandler(collectAndFlag);
|
||||
clearDcsHandler(id: IFunctionIdentifier): void {
|
||||
this._dcsParser.clearDcsHandler(this._identifier(id));
|
||||
}
|
||||
setDcsHandlerFallback(handler: DcsFallbackHandler): void {
|
||||
this._dcsParser.setDcsHandlerFallback(handler);
|
||||
@@ -387,11 +442,13 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._dcsParser.reset();
|
||||
this._params.reset();
|
||||
this._params.addParam(0); // ZDM
|
||||
this._collect = '';
|
||||
this._collect = 0;
|
||||
// this._activeDcsHandler = this._dcsHandlerFb;
|
||||
this.precedingCodepoint = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse UTF32 codepoints in `data` up to `length`.
|
||||
*
|
||||
@@ -415,7 +472,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
let collect = this._collect;
|
||||
const params = this._params;
|
||||
const table: Uint8Array = this.TRANSITIONS.table;
|
||||
// let dcsHandler: IDcsHandler = this._activeDcsHandler;
|
||||
let callback: Function | null = null;
|
||||
|
||||
// process input string
|
||||
@@ -465,7 +521,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
position: i,
|
||||
code,
|
||||
currentState,
|
||||
osc: '', // FIXME: what to send here?
|
||||
collect,
|
||||
params,
|
||||
abort: false
|
||||
@@ -475,16 +530,16 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
break;
|
||||
case ParserAction.CSI_DISPATCH:
|
||||
// Trigger CSI Handler
|
||||
const handlers = this._csiHandlers[code];
|
||||
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, collect) !== false) {
|
||||
if (handlers[j](params) !== false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < 0) {
|
||||
this._csiHandlerFb(collect, params, code);
|
||||
this._csiHandlerFb(collect << 8 | code, params);
|
||||
}
|
||||
this.precedingCodepoint = 0;
|
||||
break;
|
||||
@@ -509,10 +564,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
i--;
|
||||
break;
|
||||
case ParserAction.COLLECT:
|
||||
collect += String.fromCharCode(code);
|
||||
collect |= code;
|
||||
break;
|
||||
case ParserAction.ESC_DISPATCH:
|
||||
const handlersEsc = this._escHandlers[collect + String.fromCharCode(code)];
|
||||
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
|
||||
@@ -521,7 +576,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
}
|
||||
}
|
||||
if (jj < 0) {
|
||||
this._escHandlerFb(collect, code);
|
||||
this._escHandlerFb(collect << 8 | code);
|
||||
}
|
||||
this.precedingCodepoint = 0;
|
||||
break;
|
||||
@@ -529,10 +584,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
osc.reset();
|
||||
params.reset();
|
||||
params.addParam(0); // ZDM
|
||||
collect = '';
|
||||
collect = 0;
|
||||
break;
|
||||
case ParserAction.DCS_HOOK:
|
||||
dcs.hook(collect, params, code);
|
||||
dcs.hook(collect << 8 | code, params);
|
||||
break;
|
||||
case ParserAction.DCS_PUT:
|
||||
// inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f
|
||||
@@ -551,7 +606,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
osc.reset();
|
||||
params.reset();
|
||||
params.addParam(0); // ZDM
|
||||
collect = '';
|
||||
collect = 0;
|
||||
this.precedingCodepoint = 0;
|
||||
break;
|
||||
case ParserAction.OSC_START:
|
||||
@@ -573,7 +628,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
osc.reset();
|
||||
params.reset();
|
||||
params.addParam(0); // ZDM
|
||||
collect = '';
|
||||
collect = 0;
|
||||
this.precedingCodepoint = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
Vendored
+30
-21
@@ -53,10 +53,8 @@ export interface IParsingState {
|
||||
code: number;
|
||||
// current parser state
|
||||
currentState: ParserState;
|
||||
// osc string buffer
|
||||
osc: string;
|
||||
// collect buffer with intermediate characters
|
||||
collect: string;
|
||||
collect: number;
|
||||
// params buffer
|
||||
params: IParams;
|
||||
// should abort (default: false)
|
||||
@@ -67,7 +65,7 @@ export interface IHandlerCollection<T> {
|
||||
[key: string]: T[];
|
||||
}
|
||||
|
||||
export type CsiHandler = (params: IParams, collect: string) => boolean | void;
|
||||
export type CsiHandler = (params: IParams) => boolean | void;
|
||||
export type EscHandler = () => boolean | void;
|
||||
|
||||
/**
|
||||
@@ -93,12 +91,12 @@ export type EscHandler = () => boolean | void;
|
||||
* indicates whether the command was aborted.
|
||||
*/
|
||||
export interface IDcsHandler {
|
||||
hook(collect: string, params: IParams, flag: number): void;
|
||||
hook(params: IParams): void;
|
||||
put(data: Uint32Array, start: number, end: number): void;
|
||||
unhook(success: boolean): void | boolean;
|
||||
}
|
||||
|
||||
export type DcsFallbackHandler = (collectAndFlag: string, action: 'HOOK' | 'PUT' | 'UNHOOK', payload?: any) => void;
|
||||
export type DcsFallbackHandler = (ident: number, action: 'HOOK' | 'PUT' | 'UNHOOK', payload?: any) => void;
|
||||
|
||||
export interface IOscHandler {
|
||||
/**
|
||||
@@ -145,6 +143,11 @@ export interface IEscapeSequenceParser extends IDisposable {
|
||||
*/
|
||||
parse(data: Uint32Array, length: number): void;
|
||||
|
||||
/**
|
||||
* Get string from ident number.
|
||||
*/
|
||||
identToString(ident: number): string;
|
||||
|
||||
setPrintHandler(callback: (data: Uint32Array, start: number, end: number) => void): void;
|
||||
clearPrintHandler(): void;
|
||||
|
||||
@@ -152,25 +155,25 @@ export interface IEscapeSequenceParser extends IDisposable {
|
||||
clearExecuteHandler(flag: string): void;
|
||||
setExecuteHandlerFallback(callback: (code: number) => void): void;
|
||||
|
||||
setCsiHandler(flag: string, callback: (params: IParams, collect: string) => void): void;
|
||||
clearCsiHandler(flag: string): void;
|
||||
setCsiHandlerFallback(callback: (collect: string, params: IParams, flag: number) => void): void;
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable;
|
||||
setCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => void): void;
|
||||
clearCsiHandler(id: IFunctionIdentifier): void;
|
||||
setCsiHandlerFallback(callback: (identifier: number, params: IParams) => void): void;
|
||||
addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable;
|
||||
|
||||
setEscHandler(collectAndFlag: string, callback: () => void): void;
|
||||
clearEscHandler(collectAndFlag: string): void;
|
||||
setEscHandlerFallback(callback: (collect: string, flag: number) => void): void;
|
||||
addEscHandler(collectAndFlag: string, handler: EscHandler): IDisposable;
|
||||
setEscHandler(id: IFunctionIdentifier, callback: () => void): void;
|
||||
clearEscHandler(id: IFunctionIdentifier): void;
|
||||
setEscHandlerFallback(callback: (identifier: number) => void): void;
|
||||
addEscHandler(id: IFunctionIdentifier, handler: EscHandler): IDisposable;
|
||||
|
||||
setOscHandler(ident: number, handler: IOscHandler): void;
|
||||
clearOscHandler(ident: number): void;
|
||||
setOscHandlerFallback(handler: OscFallbackHandler): void;
|
||||
addOscHandler(ident: number, handler: IOscHandler): IDisposable;
|
||||
|
||||
setDcsHandler(collectAndFlag: string, handler: IDcsHandler): void;
|
||||
clearDcsHandler(collectAndFlag: string): void;
|
||||
setDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): void;
|
||||
clearDcsHandler(id: IFunctionIdentifier): void;
|
||||
setDcsHandlerFallback(handler: DcsFallbackHandler): void;
|
||||
addDcsHandler(collectAndFlag: string, handler: IDcsHandler): IDisposable;
|
||||
addDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable;
|
||||
|
||||
setErrorHandler(callback: (state: IParsingState) => IParsingState): void;
|
||||
clearErrorHandler(): void;
|
||||
@@ -188,12 +191,18 @@ export interface IOscParser extends IDisposable {
|
||||
}
|
||||
|
||||
export interface IDcsParser extends IDisposable {
|
||||
addDcsHandler(collectAndFlag: string, handler: IDcsHandler): IDisposable;
|
||||
setDcsHandler(collectAndFlag: string, handler: IDcsHandler): void;
|
||||
clearDcsHandler(collectAndFlag: string): void;
|
||||
addDcsHandler(ident: number, handler: IDcsHandler): IDisposable;
|
||||
setDcsHandler(ident: number, handler: IDcsHandler): void;
|
||||
clearDcsHandler(ident: number): void;
|
||||
setDcsHandlerFallback(handler: DcsFallbackHandler): void;
|
||||
reset(): void;
|
||||
hook(collect: string, params: IParams, flag: number): void;
|
||||
hook(ident: number, params: IParams): void;
|
||||
put(data: Uint32Array, start: number, end: number): void;
|
||||
unhook(success: boolean): void;
|
||||
}
|
||||
|
||||
export interface IFunctionIdentifier {
|
||||
prefix?: string;
|
||||
intermediates?: string;
|
||||
final: string;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Terminal as TerminalCore } from '../Terminal';
|
||||
import * as Strings from '../browser/LocalizableStrings';
|
||||
import { IEvent } from 'common/EventEmitter';
|
||||
import { AddonManager } from './AddonManager';
|
||||
import { IParams } from 'common/parser/Types';
|
||||
import { IParams, IFunctionIdentifier } from 'common/parser/Types';
|
||||
|
||||
export class Terminal implements ITerminalApi {
|
||||
private _core: ITerminal;
|
||||
@@ -57,14 +57,14 @@ export class Terminal implements ITerminalApi {
|
||||
public attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void {
|
||||
this._core.attachCustomKeyEventHandler(customKeyEventHandler);
|
||||
}
|
||||
public addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable {
|
||||
return this._core.addCsiHandler(flag, (params: IParams, collect: string) => callback(params.toArray(), collect));
|
||||
public addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable {
|
||||
return this._core.addCsiHandler(id, (params: IParams) => callback(params.toArray()));
|
||||
}
|
||||
public addDcsHandler(collectAndFlag: string, callback: (param: (number | number[])[], data: string) => boolean): IDisposable {
|
||||
return this._core.addDcsHandler(collectAndFlag, (params: IParams, data: string) => callback(params.toArray(), data));
|
||||
public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable {
|
||||
return this._core.addDcsHandler(id, (data: string, params: IParams) => callback(data, params.toArray()));
|
||||
}
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._core.addEscHandler(collectAndFlag, handler);
|
||||
public addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable {
|
||||
return this._core.addEscHandler(id, handler);
|
||||
}
|
||||
public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
|
||||
return this._core.addOscHandler(ident, callback);
|
||||
|
||||
@@ -340,7 +340,7 @@ describe('InputHandler Integration Tests', function(): void {
|
||||
await page.evaluate(`
|
||||
window.term.reset();
|
||||
const _customCsiHandlerParams = [];
|
||||
const _customCsiHandler = window.term.addCsiHandler('m', (params, collect) => {
|
||||
const _customCsiHandler = window.term.addCsiHandler({final: 'm'}, (params, collect) => {
|
||||
_customCsiHandlerParams.push(params);
|
||||
return false;
|
||||
}, '');
|
||||
@@ -356,15 +356,15 @@ describe('InputHandler Integration Tests', function(): void {
|
||||
await page.evaluate(`
|
||||
window.term.reset();
|
||||
const _customDcsHandlerCallStack = [];
|
||||
const _customDcsHandlerA = window.term.addDcsHandler('+p', (params, data) => {
|
||||
const _customDcsHandlerA = window.term.addDcsHandler({intermediates:'+', final: 'p'}, (data, params) => {
|
||||
_customDcsHandlerCallStack.push(['A', params, data]);
|
||||
return false;
|
||||
});
|
||||
const _customDcsHandlerB = window.term.addDcsHandler('+p', (params, data) => {
|
||||
const _customDcsHandlerB = window.term.addDcsHandler({intermediates:'+', final: 'p'}, (data, params) => {
|
||||
_customDcsHandlerCallStack.push(['B', params, data]);
|
||||
return true;
|
||||
});
|
||||
const _customDcsHandlerC = window.term.addDcsHandler('+p', (params, data) => {
|
||||
const _customDcsHandlerC = window.term.addDcsHandler({intermediates:'+', final: 'p'}, (data, params) => {
|
||||
_customDcsHandlerCallStack.push(['C', params, data]);
|
||||
return false;
|
||||
});
|
||||
@@ -380,15 +380,15 @@ describe('InputHandler Integration Tests', function(): void {
|
||||
await page.evaluate(`
|
||||
window.term.reset();
|
||||
const _customEscHandlerCallStack = [];
|
||||
const _customEscHandlerA = window.term.addEscHandler('(B', () => {
|
||||
const _customEscHandlerA = window.term.addEscHandler({intermediates:'(', final: 'B'}, () => {
|
||||
_customEscHandlerCallStack.push('A');
|
||||
return false;
|
||||
});
|
||||
const _customEscHandlerB = window.term.addEscHandler('(B', () => {
|
||||
const _customEscHandlerB = window.term.addEscHandler({intermediates:'(', final: 'B'}, () => {
|
||||
_customEscHandlerCallStack.push('B');
|
||||
return true;
|
||||
});
|
||||
const _customEscHandlerC = window.term.addEscHandler('(B', () => {
|
||||
const _customEscHandlerC = window.term.addEscHandler({intermediates:'(', final: 'B'}, () => {
|
||||
_customEscHandlerCallStack.push('C');
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ function toUtf32(s: string): Uint32Array {
|
||||
}
|
||||
|
||||
class DcsHandler implements IDcsHandler {
|
||||
hook(collect: string, params: IParams, flag: number) : void {}
|
||||
hook(params: IParams) : void {}
|
||||
put(data: Uint32Array, start: number, end: number) : void {}
|
||||
unhook() :void {}
|
||||
}
|
||||
@@ -32,42 +32,42 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
beforeEach(() => {
|
||||
parser = new EscapeSequenceParser();
|
||||
parser.setPrintHandler((data, start, end) => {});
|
||||
parser.setCsiHandler('@', (params, collect) => {});
|
||||
parser.setCsiHandler('A', (params, collect) => {});
|
||||
parser.setCsiHandler('B', (params, collect) => {});
|
||||
parser.setCsiHandler('C', (params, collect) => {});
|
||||
parser.setCsiHandler('D', (params, collect) => {});
|
||||
parser.setCsiHandler('E', (params, collect) => {});
|
||||
parser.setCsiHandler('F', (params, collect) => {});
|
||||
parser.setCsiHandler('G', (params, collect) => {});
|
||||
parser.setCsiHandler('H', (params, collect) => {});
|
||||
parser.setCsiHandler('I', (params, collect) => {});
|
||||
parser.setCsiHandler('J', (params, collect) => {});
|
||||
parser.setCsiHandler('K', (params, collect) => {});
|
||||
parser.setCsiHandler('L', (params, collect) => {});
|
||||
parser.setCsiHandler('M', (params, collect) => {});
|
||||
parser.setCsiHandler('P', (params, collect) => {});
|
||||
parser.setCsiHandler('S', (params, collect) => {});
|
||||
parser.setCsiHandler('T', (params, collect) => {});
|
||||
parser.setCsiHandler('X', (params, collect) => {});
|
||||
parser.setCsiHandler('Z', (params, collect) => {});
|
||||
parser.setCsiHandler('`', (params, collect) => {});
|
||||
parser.setCsiHandler('a', (params, collect) => {});
|
||||
parser.setCsiHandler('b', (params, collect) => {});
|
||||
parser.setCsiHandler('c', (params, collect) => {});
|
||||
parser.setCsiHandler('d', (params, collect) => {});
|
||||
parser.setCsiHandler('e', (params, collect) => {});
|
||||
parser.setCsiHandler('f', (params, collect) => {});
|
||||
parser.setCsiHandler('g', (params, collect) => {});
|
||||
parser.setCsiHandler('h', (params, collect) => {});
|
||||
parser.setCsiHandler('l', (params, collect) => {});
|
||||
parser.setCsiHandler('m', (params, collect) => {});
|
||||
parser.setCsiHandler('n', (params, collect) => {});
|
||||
parser.setCsiHandler('p', (params, collect) => {});
|
||||
parser.setCsiHandler('q', (params, collect) => {});
|
||||
parser.setCsiHandler('r', (params, collect) => {});
|
||||
parser.setCsiHandler('s', (params, collect) => {});
|
||||
parser.setCsiHandler('u', (params, collect) => {});
|
||||
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, () => {});
|
||||
@@ -82,23 +82,23 @@ perfContext('Parser throughput - 50MB data', () => {
|
||||
parser.setExecuteHandler(C1.HTS, () => {});
|
||||
parser.setOscHandler(0, new OscHandlerFactory((data) => {}));
|
||||
parser.setOscHandler(2, new OscHandlerFactory((data) => {}));
|
||||
parser.setEscHandler('7', () => {});
|
||||
parser.setEscHandler('8', () => {});
|
||||
parser.setEscHandler('D', () => {});
|
||||
parser.setEscHandler('E', () => {});
|
||||
parser.setEscHandler('H', () => {});
|
||||
parser.setEscHandler('M', () => {});
|
||||
parser.setEscHandler('=', () => {});
|
||||
parser.setEscHandler('>', () => {});
|
||||
parser.setEscHandler('c', () => {});
|
||||
parser.setEscHandler('n', () => {});
|
||||
parser.setEscHandler('o', () => {});
|
||||
parser.setEscHandler('|', () => {});
|
||||
parser.setEscHandler('}', () => {});
|
||||
parser.setEscHandler('~', () => {});
|
||||
parser.setEscHandler('%@', () => {});
|
||||
parser.setEscHandler('%G', () => {});
|
||||
parser.setDcsHandler('q', new DcsHandler());
|
||||
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());
|
||||
});
|
||||
|
||||
perfContext('PRINT - a', () => {
|
||||
|
||||
Vendored
+27
-10
@@ -502,8 +502,8 @@ declare module 'xterm' {
|
||||
|
||||
/**
|
||||
* Adds a handler for CSI escape sequences.
|
||||
* @param flag The flag should be one-character string, which specifies the
|
||||
* final character (e.g "m" for SGR) of the CSI sequence.
|
||||
* @param id Specifies the function identifier under which the callback gets registered,
|
||||
* e.g. {final: 'm'} for SGR.
|
||||
* @param callback The function to handle the escape sequence. The callback
|
||||
* is called with the numerical params, as well as the special characters
|
||||
* (e.g. "$" for DECSCPP). If the sequence has subparams the array will
|
||||
@@ -513,12 +513,12 @@ declare module 'xterm' {
|
||||
* The most recently-added handler is tried first.
|
||||
* @return An IDisposable you can call to remove this handler.
|
||||
*/
|
||||
addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable;
|
||||
addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for DCS escape sequences.
|
||||
* @param collect Should be a string, which specifies the collect and the
|
||||
* final character (e.g "$q" for DECRQSS) of the DCS sequence.
|
||||
* @param id Specifies the function identifier under which the callback gets registered,
|
||||
* e.g. {intermediates: '$' final: 'q'} for DECRQSS.
|
||||
* @param callback The function to handle the escape sequence. Note that the
|
||||
* function will only be called once if the sequence finished sucessfully.
|
||||
* There is currently no way to intercept smaller data chunks, those will be stored up
|
||||
@@ -531,20 +531,19 @@ declare module 'xterm' {
|
||||
* The most recently-added handler is tried first.
|
||||
* @return An IDisposable you can call to remove this handler.
|
||||
*/
|
||||
addDcsHandler(collect: string, callback: (param: (number | number[])[], data: string) => boolean): IDisposable;
|
||||
addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for ESC escape sequences.
|
||||
* @param collect Should be a string, which specifies the collect and the
|
||||
* final character (e.g "%G" for default charset selection)
|
||||
* of the ESC sequence.
|
||||
* @param id Specifies the function identifier under which the callback gets registered,
|
||||
* e.g. {intermediates: '%' final: 'G'} for default charset selection.
|
||||
* @param callback The function to handle the escape sequence.
|
||||
* Return true if the sequence was handled; false if
|
||||
* we should try a previous handler (set by addEscHandler or setEscHandler).
|
||||
* The most recently-added handler is tried first.
|
||||
* @return An IDisposable you can call to remove this handler.
|
||||
*/
|
||||
addEscHandler(collect: string, handler: () => boolean): IDisposable;
|
||||
addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for OSC escape sequences.
|
||||
@@ -987,4 +986,22 @@ declare module 'xterm' {
|
||||
*/
|
||||
readonly width: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data type to register a CSI, DCS or ESC callback in the parser.
|
||||
*/
|
||||
export interface IFunctionIdentifier {
|
||||
/**
|
||||
* Optional prefix byte, must be in range \x3c .. \x3f.
|
||||
*/
|
||||
prefix?: string;
|
||||
/**
|
||||
* Optional intermediate bytes, must be in range \x20 .. \x2f.
|
||||
*/
|
||||
intermediates?: string;
|
||||
/**
|
||||
* Final byte, must be in range \x40 .. \x7e (\x30 .. \x7e for ESC).
|
||||
*/
|
||||
final: string;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user