aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/xterm/src/common/parser
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/xterm/src/common/parser')
-rw-r--r--node_modules/xterm/src/common/parser/Constants.ts58
-rw-r--r--node_modules/xterm/src/common/parser/DcsParser.ts192
-rw-r--r--node_modules/xterm/src/common/parser/EscapeSequenceParser.ts796
-rw-r--r--node_modules/xterm/src/common/parser/OscParser.ts238
-rw-r--r--node_modules/xterm/src/common/parser/Params.ts229
-rw-r--r--node_modules/xterm/src/common/parser/Types.d.ts274
6 files changed, 1787 insertions, 0 deletions
diff --git a/node_modules/xterm/src/common/parser/Constants.ts b/node_modules/xterm/src/common/parser/Constants.ts
new file mode 100644
index 0000000..85156c3
--- /dev/null
+++ b/node_modules/xterm/src/common/parser/Constants.ts
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+/**
+ * Internal states of EscapeSequenceParser.
+ */
+export const enum ParserState {
+ GROUND = 0,
+ ESCAPE = 1,
+ ESCAPE_INTERMEDIATE = 2,
+ CSI_ENTRY = 3,
+ CSI_PARAM = 4,
+ CSI_INTERMEDIATE = 5,
+ CSI_IGNORE = 6,
+ SOS_PM_APC_STRING = 7,
+ OSC_STRING = 8,
+ DCS_ENTRY = 9,
+ DCS_PARAM = 10,
+ DCS_IGNORE = 11,
+ DCS_INTERMEDIATE = 12,
+ DCS_PASSTHROUGH = 13
+}
+
+/**
+* Internal actions of EscapeSequenceParser.
+*/
+export const enum ParserAction {
+ IGNORE = 0,
+ ERROR = 1,
+ PRINT = 2,
+ EXECUTE = 3,
+ OSC_START = 4,
+ OSC_PUT = 5,
+ OSC_END = 6,
+ CSI_DISPATCH = 7,
+ PARAM = 8,
+ COLLECT = 9,
+ ESC_DISPATCH = 10,
+ CLEAR = 11,
+ DCS_HOOK = 12,
+ DCS_PUT = 13,
+ DCS_UNHOOK = 14
+}
+
+/**
+ * Internal states of OscParser.
+ */
+export const enum OscState {
+ START = 0,
+ ID = 1,
+ PAYLOAD = 2,
+ ABORT = 3
+}
+
+// payload limit for OSC and DCS
+export const PAYLOAD_LIMIT = 10000000;
diff --git a/node_modules/xterm/src/common/parser/DcsParser.ts b/node_modules/xterm/src/common/parser/DcsParser.ts
new file mode 100644
index 0000000..b66524b
--- /dev/null
+++ b/node_modules/xterm/src/common/parser/DcsParser.ts
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2019 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IDisposable } from 'common/Types';
+import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType, ISubParserStackState } from 'common/parser/Types';
+import { utf32ToString } from 'common/input/TextDecoder';
+import { Params } from 'common/parser/Params';
+import { PAYLOAD_LIMIT } from 'common/parser/Constants';
+
+const EMPTY_HANDLERS: IDcsHandler[] = [];
+
+export class DcsParser implements IDcsParser {
+ private _handlers: IHandlerCollection<IDcsHandler> = Object.create(null);
+ private _active: IDcsHandler[] = EMPTY_HANDLERS;
+ private _ident: number = 0;
+ private _handlerFb: DcsFallbackHandlerType = () => { };
+ private _stack: ISubParserStackState = {
+ paused: false,
+ loopPosition: 0,
+ fallThrough: false
+ };
+
+ public dispose(): void {
+ this._handlers = Object.create(null);
+ this._handlerFb = () => { };
+ this._active = EMPTY_HANDLERS;
+ }
+
+ public registerHandler(ident: number, handler: IDcsHandler): IDisposable {
+ if (this._handlers[ident] === undefined) {
+ this._handlers[ident] = [];
+ }
+ const handlerList = this._handlers[ident];
+ handlerList.push(handler);
+ return {
+ dispose: () => {
+ const handlerIndex = handlerList.indexOf(handler);
+ if (handlerIndex !== -1) {
+ handlerList.splice(handlerIndex, 1);
+ }
+ }
+ };
+ }
+
+ public clearHandler(ident: number): void {
+ if (this._handlers[ident]) delete this._handlers[ident];
+ }
+
+ public setHandlerFallback(handler: DcsFallbackHandlerType): void {
+ this._handlerFb = handler;
+ }
+
+ public reset(): void {
+ // force cleanup leftover handlers
+ if (this._active.length) {
+ for (let j = this._stack.paused ? this._stack.loopPosition - 1 : this._active.length - 1; j >= 0; --j) {
+ this._active[j].unhook(false);
+ }
+ }
+ this._stack.paused = false;
+ this._active = EMPTY_HANDLERS;
+ this._ident = 0;
+ }
+
+ public hook(ident: number, params: IParams): void {
+ // always reset leftover handlers
+ this.reset();
+ this._ident = ident;
+ this._active = this._handlers[ident] || EMPTY_HANDLERS;
+ if (!this._active.length) {
+ this._handlerFb(this._ident, 'HOOK', params);
+ } else {
+ for (let j = this._active.length - 1; j >= 0; j--) {
+ this._active[j].hook(params);
+ }
+ }
+ }
+
+ public put(data: Uint32Array, start: number, end: number): void {
+ if (!this._active.length) {
+ 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);
+ }
+ }
+ }
+
+ public unhook(success: boolean, promiseResult: boolean = true): void | Promise<boolean> {
+ if (!this._active.length) {
+ this._handlerFb(this._ident, 'UNHOOK', success);
+ } else {
+ let handlerResult: boolean | Promise<boolean> = false;
+ let j = this._active.length - 1;
+ let fallThrough = false;
+ if (this._stack.paused) {
+ j = this._stack.loopPosition - 1;
+ handlerResult = promiseResult;
+ fallThrough = this._stack.fallThrough;
+ this._stack.paused = false;
+ }
+ if (!fallThrough && handlerResult === false) {
+ for (; j >= 0; j--) {
+ handlerResult = this._active[j].unhook(success);
+ if (handlerResult === true) {
+ break;
+ } else if (handlerResult instanceof Promise) {
+ this._stack.paused = true;
+ this._stack.loopPosition = j;
+ this._stack.fallThrough = false;
+ return handlerResult;
+ }
+ }
+ j--;
+ }
+ // cleanup left over handlers (fallThrough for async)
+ for (; j >= 0; j--) {
+ handlerResult = this._active[j].unhook(false);
+ if (handlerResult instanceof Promise) {
+ this._stack.paused = true;
+ this._stack.loopPosition = j;
+ this._stack.fallThrough = true;
+ return handlerResult;
+ }
+ }
+ }
+ this._active = EMPTY_HANDLERS;
+ this._ident = 0;
+ }
+}
+
+// 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 = EMPTY_PARAMS;
+ private _hitLimit: boolean = false;
+
+ constructor(private _handler: (data: string, params: IParams) => boolean | Promise<boolean>) { }
+
+ public hook(params: IParams): void {
+ // 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;
+ }
+
+ public put(data: Uint32Array, start: number, end: number): void {
+ if (this._hitLimit) {
+ return;
+ }
+ this._data += utf32ToString(data, start, end);
+ if (this._data.length > PAYLOAD_LIMIT) {
+ this._data = '';
+ this._hitLimit = true;
+ }
+ }
+
+ public unhook(success: boolean): boolean | Promise<boolean> {
+ let ret: boolean | Promise<boolean> = false;
+ if (this._hitLimit) {
+ ret = false;
+ } else if (success) {
+ ret = this._handler(this._data, this._params);
+ if (ret instanceof Promise) {
+ // need to hold data and params until `ret` got resolved
+ // dont care for errors, data will be freed anyway on next start
+ return ret.then(res => {
+ this._params = EMPTY_PARAMS;
+ this._data = '';
+ this._hitLimit = false;
+ return res;
+ });
+ }
+ }
+ this._params = EMPTY_PARAMS;
+ this._data = '';
+ this._hitLimit = false;
+ return ret;
+ }
+}
diff --git a/node_modules/xterm/src/common/parser/EscapeSequenceParser.ts b/node_modules/xterm/src/common/parser/EscapeSequenceParser.ts
new file mode 100644
index 0000000..f20a7e9
--- /dev/null
+++ b/node_modules/xterm/src/common/parser/EscapeSequenceParser.ts
@@ -0,0 +1,796 @@
+/**
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType } from 'common/parser/Types';
+import { ParserState, ParserAction } from 'common/parser/Constants';
+import { Disposable } from 'common/Lifecycle';
+import { IDisposable } from 'common/Types';
+import { fill } from 'common/TypedArrayUtils';
+import { Params } from 'common/parser/Params';
+import { OscParser } from 'common/parser/OscParser';
+import { DcsParser } from 'common/parser/DcsParser';
+
+/**
+ * Table values are generated like this:
+ * index: currentState << TableValue.INDEX_STATE_SHIFT | charCode
+ * value: action << TableValue.TRANSITION_ACTION_SHIFT | nextState
+ */
+const enum TableAccess {
+ TRANSITION_ACTION_SHIFT = 4,
+ TRANSITION_STATE_MASK = 15,
+ INDEX_STATE_SHIFT = 8
+}
+
+/**
+ * Transition table for EscapeSequenceParser.
+ */
+export class TransitionTable {
+ public table: Uint8Array;
+
+ constructor(length: number) {
+ this.table = new Uint8Array(length);
+ }
+
+ /**
+ * Set default transition.
+ * @param action default action
+ * @param next default next state
+ */
+ public setDefault(action: ParserAction, next: ParserState): void {
+ fill(this.table, action << TableAccess.TRANSITION_ACTION_SHIFT | next);
+ }
+
+ /**
+ * Add a transition to the transition table.
+ * @param code input character code
+ * @param state current parser state
+ * @param action parser action to be done
+ * @param next next parser state
+ */
+ public add(code: number, state: ParserState, action: ParserAction, next: ParserState): void {
+ this.table[state << TableAccess.INDEX_STATE_SHIFT | code] = action << TableAccess.TRANSITION_ACTION_SHIFT | next;
+ }
+
+ /**
+ * Add transitions for multiple input character codes.
+ * @param codes input character code array
+ * @param state current parser state
+ * @param action parser action to be done
+ * @param next next parser state
+ */
+ public addMany(codes: number[], state: ParserState, action: ParserAction, next: ParserState): void {
+ for (let i = 0; i < codes.length; i++) {
+ this.table[state << TableAccess.INDEX_STATE_SHIFT | codes[i]] = action << TableAccess.TRANSITION_ACTION_SHIFT | next;
+ }
+ }
+}
+
+
+// Pseudo-character placeholder for printable non-ascii characters (unicode).
+const NON_ASCII_PRINTABLE = 0xA0;
+
+
+/**
+ * VT500 compatible transition table.
+ * Taken from https://vt100.net/emu/dec_ansi_parser.
+ */
+export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
+ const table: TransitionTable = new TransitionTable(4095);
+
+ // range macro for byte
+ const BYTE_VALUES = 256;
+ const blueprint = Array.apply(null, Array(BYTE_VALUES)).map((unused: any, i: number) => i);
+ const r = (start: number, end: number): number[] => blueprint.slice(start, end);
+
+ // Default definitions.
+ const PRINTABLES = r(0x20, 0x7f); // 0x20 (SP) included, 0x7F (DEL) excluded
+ const EXECUTABLES = r(0x00, 0x18);
+ EXECUTABLES.push(0x19);
+ EXECUTABLES.push.apply(EXECUTABLES, r(0x1c, 0x20));
+
+ const states: number[] = r(ParserState.GROUND, ParserState.DCS_PASSTHROUGH + 1);
+ let state: any;
+
+ // set default transition
+ table.setDefault(ParserAction.ERROR, ParserState.GROUND);
+ // printables
+ table.addMany(PRINTABLES, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND);
+ // global anywhere rules
+ for (state in states) {
+ table.addMany([0x18, 0x1a, 0x99, 0x9a], state, ParserAction.EXECUTE, ParserState.GROUND);
+ table.addMany(r(0x80, 0x90), state, ParserAction.EXECUTE, ParserState.GROUND);
+ table.addMany(r(0x90, 0x98), state, ParserAction.EXECUTE, ParserState.GROUND);
+ table.add(0x9c, state, ParserAction.IGNORE, ParserState.GROUND); // ST as terminator
+ table.add(0x1b, state, ParserAction.CLEAR, ParserState.ESCAPE); // ESC
+ table.add(0x9d, state, ParserAction.OSC_START, ParserState.OSC_STRING); // OSC
+ table.addMany([0x98, 0x9e, 0x9f], state, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
+ table.add(0x9b, state, ParserAction.CLEAR, ParserState.CSI_ENTRY); // CSI
+ table.add(0x90, state, ParserAction.CLEAR, ParserState.DCS_ENTRY); // DCS
+ }
+ // rules for executables and 7f
+ table.addMany(EXECUTABLES, ParserState.GROUND, ParserAction.EXECUTE, ParserState.GROUND);
+ table.addMany(EXECUTABLES, ParserState.ESCAPE, ParserAction.EXECUTE, ParserState.ESCAPE);
+ table.add(0x7f, ParserState.ESCAPE, ParserAction.IGNORE, ParserState.ESCAPE);
+ table.addMany(EXECUTABLES, ParserState.OSC_STRING, ParserAction.IGNORE, ParserState.OSC_STRING);
+ table.addMany(EXECUTABLES, ParserState.CSI_ENTRY, ParserAction.EXECUTE, ParserState.CSI_ENTRY);
+ table.add(0x7f, ParserState.CSI_ENTRY, ParserAction.IGNORE, ParserState.CSI_ENTRY);
+ table.addMany(EXECUTABLES, ParserState.CSI_PARAM, ParserAction.EXECUTE, ParserState.CSI_PARAM);
+ table.add(0x7f, ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_PARAM);
+ table.addMany(EXECUTABLES, ParserState.CSI_IGNORE, ParserAction.EXECUTE, ParserState.CSI_IGNORE);
+ table.addMany(EXECUTABLES, ParserState.CSI_INTERMEDIATE, ParserAction.EXECUTE, ParserState.CSI_INTERMEDIATE);
+ table.add(0x7f, ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_INTERMEDIATE);
+ table.addMany(EXECUTABLES, ParserState.ESCAPE_INTERMEDIATE, ParserAction.EXECUTE, ParserState.ESCAPE_INTERMEDIATE);
+ table.add(0x7f, ParserState.ESCAPE_INTERMEDIATE, ParserAction.IGNORE, ParserState.ESCAPE_INTERMEDIATE);
+ // osc
+ table.add(0x5d, ParserState.ESCAPE, ParserAction.OSC_START, ParserState.OSC_STRING);
+ table.addMany(PRINTABLES, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
+ table.add(0x7f, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
+ table.addMany([0x9c, 0x1b, 0x18, 0x1a, 0x07], ParserState.OSC_STRING, ParserAction.OSC_END, ParserState.GROUND);
+ table.addMany(r(0x1c, 0x20), ParserState.OSC_STRING, ParserAction.IGNORE, ParserState.OSC_STRING);
+ // sos/pm/apc does nothing
+ table.addMany([0x58, 0x5e, 0x5f], ParserState.ESCAPE, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
+ table.addMany(PRINTABLES, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
+ table.addMany(EXECUTABLES, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
+ table.add(0x9c, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.GROUND);
+ table.add(0x7f, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
+ // csi entries
+ table.add(0x5b, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.CSI_ENTRY);
+ table.addMany(r(0x40, 0x7f), ParserState.CSI_ENTRY, ParserAction.CSI_DISPATCH, ParserState.GROUND);
+ table.addMany(r(0x30, 0x3c), ParserState.CSI_ENTRY, ParserAction.PARAM, ParserState.CSI_PARAM);
+ table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_PARAM);
+ table.addMany(r(0x30, 0x3c), ParserState.CSI_PARAM, ParserAction.PARAM, ParserState.CSI_PARAM);
+ table.addMany(r(0x40, 0x7f), ParserState.CSI_PARAM, ParserAction.CSI_DISPATCH, ParserState.GROUND);
+ table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_IGNORE);
+ table.addMany(r(0x20, 0x40), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
+ table.add(0x7f, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
+ table.addMany(r(0x40, 0x7f), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.GROUND);
+ table.addMany(r(0x20, 0x30), ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
+ table.addMany(r(0x20, 0x30), ParserState.CSI_INTERMEDIATE, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
+ table.addMany(r(0x30, 0x40), ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
+ table.addMany(r(0x40, 0x7f), ParserState.CSI_INTERMEDIATE, ParserAction.CSI_DISPATCH, ParserState.GROUND);
+ table.addMany(r(0x20, 0x30), ParserState.CSI_PARAM, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
+ // esc_intermediate
+ table.addMany(r(0x20, 0x30), ParserState.ESCAPE, ParserAction.COLLECT, ParserState.ESCAPE_INTERMEDIATE);
+ table.addMany(r(0x20, 0x30), ParserState.ESCAPE_INTERMEDIATE, ParserAction.COLLECT, ParserState.ESCAPE_INTERMEDIATE);
+ table.addMany(r(0x30, 0x7f), ParserState.ESCAPE_INTERMEDIATE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
+ table.addMany(r(0x30, 0x50), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
+ table.addMany(r(0x51, 0x58), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
+ table.addMany([0x59, 0x5a, 0x5c], ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
+ table.addMany(r(0x60, 0x7f), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
+ // dcs entry
+ table.add(0x50, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.DCS_ENTRY);
+ table.addMany(EXECUTABLES, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
+ table.add(0x7f, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
+ table.addMany(r(0x1c, 0x20), ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
+ table.addMany(r(0x20, 0x30), ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
+ table.addMany(r(0x30, 0x3c), ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM);
+ table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_PARAM);
+ table.addMany(EXECUTABLES, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
+ table.addMany(r(0x20, 0x80), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
+ table.addMany(r(0x1c, 0x20), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
+ table.addMany(EXECUTABLES, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
+ table.add(0x7f, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
+ table.addMany(r(0x1c, 0x20), ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
+ table.addMany(r(0x30, 0x3c), ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM);
+ table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_IGNORE);
+ table.addMany(r(0x20, 0x30), ParserState.DCS_PARAM, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
+ table.addMany(EXECUTABLES, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
+ table.add(0x7f, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
+ table.addMany(r(0x1c, 0x20), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
+ table.addMany(r(0x20, 0x30), ParserState.DCS_INTERMEDIATE, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
+ table.addMany(r(0x30, 0x40), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
+ table.addMany(r(0x40, 0x7f), ParserState.DCS_INTERMEDIATE, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
+ table.addMany(r(0x40, 0x7f), ParserState.DCS_PARAM, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
+ table.addMany(r(0x40, 0x7f), ParserState.DCS_ENTRY, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
+ table.addMany(EXECUTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
+ table.addMany(PRINTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
+ table.add(0x7f, ParserState.DCS_PASSTHROUGH, ParserAction.IGNORE, ParserState.DCS_PASSTHROUGH);
+ table.addMany([0x1b, 0x9c, 0x18, 0x1a], ParserState.DCS_PASSTHROUGH, ParserAction.DCS_UNHOOK, ParserState.GROUND);
+ // special handling of unicode chars
+ table.add(NON_ASCII_PRINTABLE, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND);
+ table.add(NON_ASCII_PRINTABLE, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
+ table.add(NON_ASCII_PRINTABLE, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
+ table.add(NON_ASCII_PRINTABLE, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
+ table.add(NON_ASCII_PRINTABLE, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
+ return table;
+})();
+
+
+/**
+ * EscapeSequenceParser.
+ * This class implements the ANSI/DEC compatible parser described by
+ * Paul Williams (https://vt100.net/emu/dec_ansi_parser).
+ *
+ * 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` 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-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 (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
+ */
+export class EscapeSequenceParser extends Disposable implements IEscapeSequenceParser {
+ public initialState: number;
+ public currentState: number;
+ public precedingCodepoint: number;
+
+ // buffers over several parse calls
+ protected _params: Params;
+ protected _collect: number;
+
+ // handler lookup containers
+ protected _printHandler: PrintHandlerType;
+ protected _executeHandlers: { [flag: number]: ExecuteHandlerType };
+ protected _csiHandlers: IHandlerCollection<CsiHandlerType>;
+ protected _escHandlers: IHandlerCollection<EscHandlerType>;
+ protected _oscParser: IOscParser;
+ protected _dcsParser: IDcsParser;
+ protected _errorHandler: (state: IParsingState) => IParsingState;
+
+ // fallback handlers
+ protected _printHandlerFb: PrintFallbackHandlerType;
+ protected _executeHandlerFb: ExecuteFallbackHandlerType;
+ protected _csiHandlerFb: CsiFallbackHandlerType;
+ protected _escHandlerFb: EscFallbackHandlerType;
+ protected _errorHandlerFb: (state: IParsingState) => IParsingState;
+
+ // parser stack save for async handler support
+ protected _parseStack: IParserStackState = {
+ state: ParserStackType.NONE,
+ handlers: [],
+ handlerPos: 0,
+ transition: 0,
+ chunkPos: 0
+ };
+
+ constructor(
+ protected readonly _transitions: TransitionTable = VT500_TRANSITION_TABLE
+ ) {
+ super();
+
+ this.initialState = ParserState.GROUND;
+ this.currentState = this.initialState;
+ this._params = new Params(); // defaults to 32 storable params/subparams
+ this._params.addParam(0); // ZDM
+ 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 = (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);
+ this._csiHandlers = Object.create(null);
+ this._escHandlers = Object.create(null);
+ this._oscParser = new OscParser();
+ this._dcsParser = new DcsParser();
+ this._errorHandler = this._errorHandlerFb;
+
+ // swallow 7bit ST (ESC+\)
+ this.registerEscHandler({ final: '\\' }, () => true);
+ }
+
+ protected _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 {
+ this._csiHandlers = Object.create(null);
+ this._executeHandlers = Object.create(null);
+ this._escHandlers = Object.create(null);
+ this._oscParser.dispose();
+ this._dcsParser.dispose();
+ }
+
+ public setPrintHandler(handler: PrintHandlerType): void {
+ this._printHandler = handler;
+ }
+ public clearPrintHandler(): void {
+ this._printHandler = this._printHandlerFb;
+ }
+
+ public registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable {
+ const ident = this._identifier(id, [0x30, 0x7e]);
+ if (this._escHandlers[ident] === undefined) {
+ this._escHandlers[ident] = [];
+ }
+ const handlerList = this._escHandlers[ident];
+ handlerList.push(handler);
+ return {
+ dispose: () => {
+ const handlerIndex = handlerList.indexOf(handler);
+ if (handlerIndex !== -1) {
+ handlerList.splice(handlerIndex, 1);
+ }
+ }
+ };
+ }
+ public clearEscHandler(id: IFunctionIdentifier): void {
+ if (this._escHandlers[this._identifier(id, [0x30, 0x7e])]) delete this._escHandlers[this._identifier(id, [0x30, 0x7e])];
+ }
+ public setEscHandlerFallback(handler: EscFallbackHandlerType): void {
+ this._escHandlerFb = handler;
+ }
+
+ public setExecuteHandler(flag: string, handler: ExecuteHandlerType): void {
+ this._executeHandlers[flag.charCodeAt(0)] = handler;
+ }
+ public clearExecuteHandler(flag: string): void {
+ if (this._executeHandlers[flag.charCodeAt(0)]) delete this._executeHandlers[flag.charCodeAt(0)];
+ }
+ public setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void {
+ this._executeHandlerFb = handler;
+ }
+
+ public registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable {
+ const ident = this._identifier(id);
+ if (this._csiHandlers[ident] === undefined) {
+ this._csiHandlers[ident] = [];
+ }
+ const handlerList = this._csiHandlers[ident];
+ handlerList.push(handler);
+ return {
+ dispose: () => {
+ const handlerIndex = handlerList.indexOf(handler);
+ if (handlerIndex !== -1) {
+ handlerList.splice(handlerIndex, 1);
+ }
+ }
+ };
+ }
+ public clearCsiHandler(id: IFunctionIdentifier): void {
+ if (this._csiHandlers[this._identifier(id)]) delete this._csiHandlers[this._identifier(id)];
+ }
+ public setCsiHandlerFallback(callback: (ident: number, params: IParams) => void): void {
+ this._csiHandlerFb = callback;
+ }
+
+ 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));
+ }
+ public setDcsHandlerFallback(handler: DcsFallbackHandlerType): void {
+ this._dcsParser.setHandlerFallback(handler);
+ }
+
+ public registerOscHandler(ident: number, handler: IOscHandler): IDisposable {
+ return this._oscParser.registerHandler(ident, handler);
+ }
+ public clearOscHandler(ident: number): void {
+ this._oscParser.clearHandler(ident);
+ }
+ public setOscHandlerFallback(handler: OscFallbackHandlerType): void {
+ this._oscParser.setHandlerFallback(handler);
+ }
+
+ public setErrorHandler(callback: (state: IParsingState) => IParsingState): void {
+ this._errorHandler = callback;
+ }
+ public clearErrorHandler(): void {
+ this._errorHandler = this._errorHandlerFb;
+ }
+
+ /**
+ * Reset parser to initial values.
+ *
+ * This can also be used to lift the improper continuation error condition
+ * when dealing with async handlers. Use this only as a last resort to silence
+ * that error when the terminal has no pending data to be processed. Note that
+ * the interrupted async handler might continue its work in the future messing
+ * up the terminal state even further.
+ */
+ public reset(): void {
+ this.currentState = this.initialState;
+ this._oscParser.reset();
+ this._dcsParser.reset();
+ this._params.reset();
+ this._params.addParam(0); // ZDM
+ this._collect = 0;
+ this.precedingCodepoint = 0;
+ // abort pending continuation from async handler
+ // Here the RESET type indicates, that the next parse call will
+ // ignore any saved stack, instead continues sync with next codepoint from GROUND
+ if (this._parseStack.state !== ParserStackType.NONE) {
+ this._parseStack.state = ParserStackType.RESET;
+ this._parseStack.handlers = []; // also release handlers ref
+ }
+ }
+
+ /**
+ * Async parse support.
+ */
+ protected _preserveStack(
+ state: ParserStackType,
+ handlers: ResumableHandlersType,
+ handlerPos: number,
+ transition: number,
+ chunkPos: number
+ ): void {
+ this._parseStack.state = state;
+ this._parseStack.handlers = handlers;
+ this._parseStack.handlerPos = handlerPos;
+ this._parseStack.transition = transition;
+ this._parseStack.chunkPos = chunkPos;
+ }
+
+ /**
+ * Parse UTF32 codepoints in `data` up to `length`.
+ *
+ * Note: For several actions with high data load the parsing is optimized
+ * by using local read ahead loops with hardcoded conditions to
+ * avoid costly table lookups. Make sure that any change of table values
+ * will be reflected in the loop conditions as well and vice versa.
+ * Affected states/actions:
+ * - GROUND:PRINT
+ * - CSI_PARAM:PARAM
+ * - DCS_PARAM:PARAM
+ * - OSC_STRING:OSC_PUT
+ * - DCS_PASSTHROUGH:DCS_PUT
+ *
+ * Note on asynchronous handler support:
+ * Any handler returning a promise will be treated as asynchronous.
+ * To keep the in-band blocking working for async handlers, `parse` pauses execution,
+ * creates a stack save and returns the promise to the caller.
+ * For proper continuation of the paused state it is important
+ * to await the promise resolving. On resolve the parse must be repeated
+ * with the same chunk of data and the resolved value in `promiseResult`
+ * until no promise is returned.
+ *
+ * Important: With only sync handlers defined, parsing is completely synchronous as well.
+ * As soon as an async handler is involved, synchronous parsing is not possible anymore.
+ *
+ * Boilerplate for proper parsing of multiple chunks with async handlers:
+ *
+ * ```typescript
+ * async function parseMultipleChunks(chunks: Uint32Array[]): Promise<void> {
+ * for (const chunk of chunks) {
+ * let result: void | Promise<boolean>;
+ * let prev: boolean | undefined;
+ * while (result = parser.parse(chunk, chunk.length, prev)) {
+ * prev = await result;
+ * }
+ * }
+ * // finished parsing all chunks...
+ * }
+ * ```
+ */
+ public parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise<boolean> {
+ let code = 0;
+ let transition = 0;
+ let start = 0;
+ let handlerResult: void | boolean | Promise<boolean>;
+
+ // resume from async handler
+ if (this._parseStack.state) {
+ // allow sync parser reset even in continuation mode
+ // Note: can be used to recover parser from improper continuation error below
+ if (this._parseStack.state === ParserStackType.RESET) {
+ this._parseStack.state = ParserStackType.NONE;
+ start = this._parseStack.chunkPos + 1; // continue with next codepoint in GROUND
+ } else {
+ if (promiseResult === undefined || this._parseStack.state === ParserStackType.FAIL) {
+ /**
+ * Reject further parsing on improper continuation after pausing.
+ * This is a really bad condition with screwed up execution order and prolly messed up
+ * terminal state, therefore we exit hard with an exception and reject any further parsing.
+ *
+ * Note: With `Terminal.write` usage this exception should never occur, as the top level
+ * calls are guaranteed to handle async conditions properly. If you ever encounter this
+ * exception in your terminal integration it indicates, that you injected data chunks to
+ * `InputHandler.parse` or `EscapeSequenceParser.parse` synchronously without waiting for
+ * continuation of a running async handler.
+ *
+ * It is possible to get rid of this error by calling `reset`. But dont rely on that,
+ * as the pending async handler still might mess up the terminal later. Instead fix the faulty
+ * async handling, so this error will not be thrown anymore.
+ */
+ this._parseStack.state = ParserStackType.FAIL;
+ throw new Error('improper continuation due to previous async handler, giving up parsing');
+ }
+
+ // we have to resume the old handler loop if:
+ // - return value of the promise was `false`
+ // - handlers are not exhausted yet
+ const handlers = this._parseStack.handlers;
+ let handlerPos = this._parseStack.handlerPos - 1;
+ switch (this._parseStack.state) {
+ case ParserStackType.CSI:
+ if (promiseResult === false && handlerPos > -1) {
+ for (; handlerPos >= 0; handlerPos--) {
+ handlerResult = (handlers as CsiHandlerType[])[handlerPos](this._params);
+ if (handlerResult === true) {
+ break;
+ } else if (handlerResult instanceof Promise) {
+ this._parseStack.handlerPos = handlerPos;
+ return handlerResult;
+ }
+ }
+ }
+ this._parseStack.handlers = [];
+ break;
+ case ParserStackType.ESC:
+ if (promiseResult === false && handlerPos > -1) {
+ for (; handlerPos >= 0; handlerPos--) {
+ handlerResult = (handlers as EscHandlerType[])[handlerPos]();
+ if (handlerResult === true) {
+ break;
+ } else if (handlerResult instanceof Promise) {
+ this._parseStack.handlerPos = handlerPos;
+ return handlerResult;
+ }
+ }
+ }
+ this._parseStack.handlers = [];
+ break;
+ case ParserStackType.DCS:
+ code = data[this._parseStack.chunkPos];
+ handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a, promiseResult);
+ if (handlerResult) {
+ return handlerResult;
+ }
+ if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
+ this._params.reset();
+ this._params.addParam(0); // ZDM
+ this._collect = 0;
+ break;
+ case ParserStackType.OSC:
+ code = data[this._parseStack.chunkPos];
+ handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a, promiseResult);
+ if (handlerResult) {
+ return handlerResult;
+ }
+ if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
+ this._params.reset();
+ this._params.addParam(0); // ZDM
+ this._collect = 0;
+ break;
+ }
+ // cleanup before continuing with the main sync loop
+ this._parseStack.state = ParserStackType.NONE;
+ start = this._parseStack.chunkPos + 1;
+ this.precedingCodepoint = 0;
+ this.currentState = this._parseStack.transition & TableAccess.TRANSITION_STATE_MASK;
+ }
+ }
+
+ // continue with main sync loop
+
+ // process input string
+ for (let i = start; i < length; ++i) {
+ code = data[i];
+
+ // normal transition & action lookup
+ transition = this._transitions.table[this.currentState << TableAccess.INDEX_STATE_SHIFT | (code < 0xa0 ? code : NON_ASCII_PRINTABLE)];
+ switch (transition >> TableAccess.TRANSITION_ACTION_SHIFT) {
+ case ParserAction.PRINT:
+ // read ahead with loop unrolling
+ // Note: 0x20 (SP) is included, 0x7F (DEL) is excluded
+ for (let j = i + 1; ; ++j) {
+ if (j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
+ this._printHandler(data, i, j);
+ i = j - 1;
+ break;
+ }
+ if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
+ this._printHandler(data, i, j);
+ i = j - 1;
+ break;
+ }
+ if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
+ this._printHandler(data, i, j);
+ i = j - 1;
+ break;
+ }
+ if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
+ this._printHandler(data, i, j);
+ i = j - 1;
+ break;
+ }
+ }
+ break;
+ case ParserAction.EXECUTE:
+ if (this._executeHandlers[code]) this._executeHandlers[code]();
+ else this._executeHandlerFb(code);
+ this.precedingCodepoint = 0;
+ break;
+ case ParserAction.IGNORE:
+ break;
+ case ParserAction.ERROR:
+ const inject: IParsingState = this._errorHandler(
+ {
+ position: i,
+ code,
+ currentState: this.currentState,
+ collect: this._collect,
+ params: this._params,
+ abort: false
+ });
+ if (inject.abort) return;
+ // inject values: currently not implemented
+ break;
+ case ParserAction.CSI_DISPATCH:
+ // Trigger CSI Handler
+ const handlers = this._csiHandlers[this._collect << 8 | code];
+ let j = handlers ? handlers.length - 1 : -1;
+ for (; j >= 0; j--) {
+ // true means success and to stop bubbling
+ // a promise indicates an async handler that needs to finish before progressing
+ handlerResult = handlers[j](this._params);
+ if (handlerResult === true) {
+ break;
+ } else if (handlerResult instanceof Promise) {
+ this._preserveStack(ParserStackType.CSI, handlers, j, transition, i);
+ return handlerResult;
+ }
+ }
+ if (j < 0) {
+ this._csiHandlerFb(this._collect << 8 | code, this._params);
+ }
+ this.precedingCodepoint = 0;
+ break;
+ case ParserAction.PARAM:
+ // inner loop: digits (0x30 - 0x39) and ; (0x3b) and : (0x3a)
+ do {
+ switch (code) {
+ case 0x3b:
+ this._params.addParam(0); // ZDM
+ break;
+ case 0x3a:
+ this._params.addSubParam(-1);
+ break;
+ default: // 0x30 - 0x39
+ this._params.addDigit(code - 48);
+ }
+ } while (++i < length && (code = data[i]) > 0x2f && code < 0x3c);
+ i--;
+ break;
+ case ParserAction.COLLECT:
+ this._collect <<= 8;
+ this._collect |= code;
+ break;
+ case ParserAction.ESC_DISPATCH:
+ const handlersEsc = this._escHandlers[this._collect << 8 | code];
+ let jj = handlersEsc ? handlersEsc.length - 1 : -1;
+ for (; jj >= 0; jj--) {
+ // true means success and to stop bubbling
+ // a promise indicates an async handler that needs to finish before progressing
+ handlerResult = handlersEsc[jj]();
+ if (handlerResult === true) {
+ break;
+ } else if (handlerResult instanceof Promise) {
+ this._preserveStack(ParserStackType.ESC, handlersEsc, jj, transition, i);
+ return handlerResult;
+ }
+ }
+ if (jj < 0) {
+ this._escHandlerFb(this._collect << 8 | code);
+ }
+ this.precedingCodepoint = 0;
+ break;
+ case ParserAction.CLEAR:
+ this._params.reset();
+ this._params.addParam(0); // ZDM
+ this._collect = 0;
+ break;
+ case ParserAction.DCS_HOOK:
+ this._dcsParser.hook(this._collect << 8 | code, this._params);
+ break;
+ case ParserAction.DCS_PUT:
+ // inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f
+ // unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort)
+ for (let j = i + 1; ; ++j) {
+ if (j >= length || (code = data[j]) === 0x18 || code === 0x1a || code === 0x1b || (code > 0x7f && code < NON_ASCII_PRINTABLE)) {
+ this._dcsParser.put(data, i, j);
+ i = j - 1;
+ break;
+ }
+ }
+ break;
+ case ParserAction.DCS_UNHOOK:
+ handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a);
+ if (handlerResult) {
+ this._preserveStack(ParserStackType.DCS, [], 0, transition, i);
+ return handlerResult;
+ }
+ if (code === 0x1b) transition |= ParserState.ESCAPE;
+ this._params.reset();
+ this._params.addParam(0); // ZDM
+ this._collect = 0;
+ this.precedingCodepoint = 0;
+ break;
+ case ParserAction.OSC_START:
+ this._oscParser.start();
+ break;
+ 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 < NON_ASCII_PRINTABLE)) {
+ this._oscParser.put(data, i, j);
+ i = j - 1;
+ break;
+ }
+ }
+ break;
+ case ParserAction.OSC_END:
+ handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a);
+ if (handlerResult) {
+ this._preserveStack(ParserStackType.OSC, [], 0, transition, i);
+ return handlerResult;
+ }
+ if (code === 0x1b) transition |= ParserState.ESCAPE;
+ this._params.reset();
+ this._params.addParam(0); // ZDM
+ this._collect = 0;
+ this.precedingCodepoint = 0;
+ break;
+ }
+ this.currentState = transition & TableAccess.TRANSITION_STATE_MASK;
+ }
+ }
+}
diff --git a/node_modules/xterm/src/common/parser/OscParser.ts b/node_modules/xterm/src/common/parser/OscParser.ts
new file mode 100644
index 0000000..32710ae
--- /dev/null
+++ b/node_modules/xterm/src/common/parser/OscParser.ts
@@ -0,0 +1,238 @@
+/**
+ * Copyright (c) 2019 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IOscHandler, IHandlerCollection, OscFallbackHandlerType, IOscParser, ISubParserStackState } from 'common/parser/Types';
+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 = () => { };
+ private _stack: ISubParserStackState = {
+ paused: false,
+ loopPosition: 0,
+ fallThrough: false
+ };
+
+ public registerHandler(ident: number, handler: IOscHandler): IDisposable {
+ if (this._handlers[ident] === undefined) {
+ this._handlers[ident] = [];
+ }
+ const handlerList = this._handlers[ident];
+ handlerList.push(handler);
+ return {
+ dispose: () => {
+ const handlerIndex = handlerList.indexOf(handler);
+ if (handlerIndex !== -1) {
+ handlerList.splice(handlerIndex, 1);
+ }
+ }
+ };
+ }
+ public clearHandler(ident: number): void {
+ if (this._handlers[ident]) delete this._handlers[ident];
+ }
+ public setHandlerFallback(handler: OscFallbackHandlerType): void {
+ this._handlerFb = handler;
+ }
+
+ public dispose(): void {
+ this._handlers = Object.create(null);
+ this._handlerFb = () => { };
+ this._active = EMPTY_HANDLERS;
+ }
+
+ public reset(): void {
+ // force cleanup handlers if payload was already sent
+ if (this._state === OscState.PAYLOAD) {
+ for (let j = this._stack.paused ? this._stack.loopPosition - 1 : this._active.length - 1; j >= 0; --j) {
+ this._active[j].end(false);
+ }
+ }
+ this._stack.paused = false;
+ this._active = EMPTY_HANDLERS;
+ this._id = -1;
+ this._state = OscState.START;
+ }
+
+ private _start(): void {
+ this._active = this._handlers[this._id] || EMPTY_HANDLERS;
+ if (!this._active.length) {
+ this._handlerFb(this._id, 'START');
+ } else {
+ for (let j = this._active.length - 1; j >= 0; j--) {
+ this._active[j].start();
+ }
+ }
+ }
+
+ private _put(data: Uint32Array, start: number, end: number): void {
+ if (!this._active.length) {
+ this._handlerFb(this._id, 'PUT', utf32ToString(data, start, end));
+ } else {
+ for (let j = this._active.length - 1; j >= 0; j--) {
+ this._active[j].put(data, start, end);
+ }
+ }
+ }
+
+ public start(): void {
+ // always reset leftover handlers
+ this.reset();
+ this._state = OscState.ID;
+ }
+
+ /**
+ * Put data to current OSC command.
+ * Expects the identifier of the OSC command in the form
+ * OSC id ; payload ST/BEL
+ * Payload chunks are not further processed and get
+ * directly passed to the handlers.
+ */
+ public put(data: Uint32Array, start: number, end: number): void {
+ if (this._state === OscState.ABORT) {
+ return;
+ }
+ if (this._state === OscState.ID) {
+ while (start < end) {
+ const code = data[start++];
+ if (code === 0x3b) {
+ this._state = OscState.PAYLOAD;
+ this._start();
+ break;
+ }
+ if (code < 0x30 || 0x39 < code) {
+ this._state = OscState.ABORT;
+ return;
+ }
+ if (this._id === -1) {
+ this._id = 0;
+ }
+ this._id = this._id * 10 + code - 48;
+ }
+ }
+ if (this._state === OscState.PAYLOAD && end - start > 0) {
+ this._put(data, start, end);
+ }
+ }
+
+ /**
+ * Indicates end of an OSC command.
+ * Whether the OSC got aborted or finished normally
+ * is indicated by `success`.
+ */
+ public end(success: boolean, promiseResult: boolean = true): void | Promise<boolean> {
+ if (this._state === OscState.START) {
+ return;
+ }
+ // do nothing if command was faulty
+ if (this._state !== OscState.ABORT) {
+ // if we are still in ID state and get an early end
+ // means that the command has no payload thus we still have
+ // to announce START and send END right after
+ if (this._state === OscState.ID) {
+ this._start();
+ }
+
+ if (!this._active.length) {
+ this._handlerFb(this._id, 'END', success);
+ } else {
+ let handlerResult: boolean | Promise<boolean> = false;
+ let j = this._active.length - 1;
+ let fallThrough = false;
+ if (this._stack.paused) {
+ j = this._stack.loopPosition - 1;
+ handlerResult = promiseResult;
+ fallThrough = this._stack.fallThrough;
+ this._stack.paused = false;
+ }
+ if (!fallThrough && handlerResult === false) {
+ for (; j >= 0; j--) {
+ handlerResult = this._active[j].end(success);
+ if (handlerResult === true) {
+ break;
+ } else if (handlerResult instanceof Promise) {
+ this._stack.paused = true;
+ this._stack.loopPosition = j;
+ this._stack.fallThrough = false;
+ return handlerResult;
+ }
+ }
+ j--;
+ }
+ // cleanup left over handlers
+ // we always have to call .end for proper cleanup,
+ // here we use `success` to indicate whether a handler should execute
+ for (; j >= 0; j--) {
+ handlerResult = this._active[j].end(false);
+ if (handlerResult instanceof Promise) {
+ this._stack.paused = true;
+ this._stack.loopPosition = j;
+ this._stack.fallThrough = true;
+ return handlerResult;
+ }
+ }
+ }
+
+ }
+ this._active = EMPTY_HANDLERS;
+ this._id = -1;
+ this._state = OscState.START;
+ }
+}
+
+/**
+ * Convenient class to allow attaching string based handler functions
+ * as OSC handlers.
+ */
+export class OscHandler implements IOscHandler {
+ private _data = '';
+ private _hitLimit: boolean = false;
+
+ constructor(private _handler: (data: string) => boolean | Promise<boolean>) { }
+
+ public start(): void {
+ this._data = '';
+ this._hitLimit = false;
+ }
+
+ public put(data: Uint32Array, start: number, end: number): void {
+ if (this._hitLimit) {
+ return;
+ }
+ this._data += utf32ToString(data, start, end);
+ if (this._data.length > PAYLOAD_LIMIT) {
+ this._data = '';
+ this._hitLimit = true;
+ }
+ }
+
+ public end(success: boolean): boolean | Promise<boolean> {
+ let ret: boolean | Promise<boolean> = false;
+ if (this._hitLimit) {
+ ret = false;
+ } else if (success) {
+ ret = this._handler(this._data);
+ if (ret instanceof Promise) {
+ // need to hold data until `ret` got resolved
+ // dont care for errors, data will be freed anyway on next start
+ return ret.then(res => {
+ this._data = '';
+ this._hitLimit = false;
+ return res;
+ });
+ }
+ }
+ this._data = '';
+ this._hitLimit = false;
+ return ret;
+ }
+}
diff --git a/node_modules/xterm/src/common/parser/Params.ts b/node_modules/xterm/src/common/parser/Params.ts
new file mode 100644
index 0000000..7071453
--- /dev/null
+++ b/node_modules/xterm/src/common/parser/Params.ts
@@ -0,0 +1,229 @@
+/**
+ * Copyright (c) 2019 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+import { IParams, ParamsArray } from 'common/parser/Types';
+
+// max value supported for a single param/subparam (clamped to positive int32 range)
+const MAX_VALUE = 0x7FFFFFFF;
+// max allowed subparams for a single sequence (hardcoded limitation)
+const MAX_SUBPARAMS = 256;
+
+/**
+ * Params storage class.
+ * This type is used by the parser to accumulate sequence parameters and sub parameters
+ * and transmit them to the input handler actions.
+ *
+ * NOTES:
+ * - params object for action handlers is borrowed, use `.toArray` or `.clone` to get a copy
+ * - never read beyond `params.length - 1` (likely to contain arbitrary data)
+ * - `.getSubParams` returns a borrowed typed array, use `.getSubParamsAll` for cloned sub params
+ * - hardcoded limitations:
+ * - max. value for a single (sub) param is 2^31 - 1 (greater values are clamped to that)
+ * - max. 256 sub params possible
+ * - negative values are not allowed beside -1 (placeholder for default value)
+ *
+ * About ZDM (Zero Default Mode):
+ * ZDM is not orchestrated by this class. If the parser is in ZDM,
+ * it should add 0 for empty params, otherwise -1. This does not apply
+ * to subparams, empty subparams should always be added with -1.
+ */
+export class Params implements IParams {
+ // params store and length
+ public params: Int32Array;
+ public length: number;
+
+ // sub params store and length
+ protected _subParams: Int32Array;
+ protected _subParamsLength: number;
+
+ // sub params offsets from param: param idx --> [start, end] offset
+ private _subParamsIdx: Uint16Array;
+ private _rejectDigits: boolean;
+ private _rejectSubDigits: boolean;
+ private _digitIsSub: boolean;
+
+ /**
+ * Create a `Params` type from JS array representation.
+ */
+ public static fromArray(values: ParamsArray): Params {
+ const params = new Params();
+ if (!values.length) {
+ return params;
+ }
+ // skip leading sub params
+ for (let i = (Array.isArray(values[0])) ? 1 : 0; i < values.length; ++i) {
+ const value = values[i];
+ if (Array.isArray(value)) {
+ for (let k = 0; k < value.length; ++k) {
+ params.addSubParam(value[k]);
+ }
+ } else {
+ params.addParam(value);
+ }
+ }
+ return params;
+ }
+
+ /**
+ * @param maxLength max length of storable parameters
+ * @param maxSubParamsLength max length of storable sub parameters
+ */
+ constructor(public maxLength: number = 32, public maxSubParamsLength: number = 32) {
+ if (maxSubParamsLength > MAX_SUBPARAMS) {
+ throw new Error('maxSubParamsLength must not be greater than 256');
+ }
+ this.params = new Int32Array(maxLength);
+ this.length = 0;
+ this._subParams = new Int32Array(maxSubParamsLength);
+ this._subParamsLength = 0;
+ this._subParamsIdx = new Uint16Array(maxLength);
+ this._rejectDigits = false;
+ this._rejectSubDigits = false;
+ this._digitIsSub = false;
+ }
+
+ /**
+ * Clone object.
+ */
+ public clone(): Params {
+ const newParams = new Params(this.maxLength, this.maxSubParamsLength);
+ newParams.params.set(this.params);
+ newParams.length = this.length;
+ newParams._subParams.set(this._subParams);
+ newParams._subParamsLength = this._subParamsLength;
+ newParams._subParamsIdx.set(this._subParamsIdx);
+ newParams._rejectDigits = this._rejectDigits;
+ newParams._rejectSubDigits = this._rejectSubDigits;
+ newParams._digitIsSub = this._digitIsSub;
+ return newParams;
+ }
+
+ /**
+ * Get a JS array representation of the current parameters and sub parameters.
+ * The array is structured as follows:
+ * sequence: "1;2:3:4;5::6"
+ * array : [1, 2, [3, 4], 5, [-1, 6]]
+ */
+ public toArray(): ParamsArray {
+ const res: ParamsArray = [];
+ for (let i = 0; i < this.length; ++i) {
+ res.push(this.params[i]);
+ const start = this._subParamsIdx[i] >> 8;
+ const end = this._subParamsIdx[i] & 0xFF;
+ if (end - start > 0) {
+ res.push(Array.prototype.slice.call(this._subParams, start, end));
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Reset to initial empty state.
+ */
+ public reset(): void {
+ this.length = 0;
+ this._subParamsLength = 0;
+ this._rejectDigits = false;
+ this._rejectSubDigits = false;
+ this._digitIsSub = false;
+ }
+
+ /**
+ * Add a parameter value.
+ * `Params` only stores up to `maxLength` parameters, any later
+ * parameter will be ignored.
+ * Note: VT devices only stored up to 16 values, xterm seems to
+ * store up to 30.
+ */
+ public addParam(value: number): void {
+ this._digitIsSub = false;
+ if (this.length >= this.maxLength) {
+ this._rejectDigits = true;
+ return;
+ }
+ if (value < -1) {
+ throw new Error('values lesser than -1 are not allowed');
+ }
+ this._subParamsIdx[this.length] = this._subParamsLength << 8 | this._subParamsLength;
+ this.params[this.length++] = value > MAX_VALUE ? MAX_VALUE : value;
+ }
+
+ /**
+ * Add a sub parameter value.
+ * The sub parameter is automatically associated with the last parameter value.
+ * Thus it is not possible to add a subparameter without any parameter added yet.
+ * `Params` only stores up to `subParamsLength` sub parameters, any later
+ * sub parameter will be ignored.
+ */
+ public addSubParam(value: number): void {
+ this._digitIsSub = true;
+ if (!this.length) {
+ return;
+ }
+ if (this._rejectDigits || this._subParamsLength >= this.maxSubParamsLength) {
+ this._rejectSubDigits = true;
+ return;
+ }
+ if (value < -1) {
+ throw new Error('values lesser than -1 are not allowed');
+ }
+ this._subParams[this._subParamsLength++] = value > MAX_VALUE ? MAX_VALUE : value;
+ this._subParamsIdx[this.length - 1]++;
+ }
+
+ /**
+ * Whether parameter at index `idx` has sub parameters.
+ */
+ public hasSubParams(idx: number): boolean {
+ return ((this._subParamsIdx[idx] & 0xFF) - (this._subParamsIdx[idx] >> 8) > 0);
+ }
+
+ /**
+ * Return sub parameters for parameter at index `idx`.
+ * Note: The values are borrowed, thus you need to copy
+ * the values if you need to hold them in nonlocal scope.
+ */
+ public getSubParams(idx: number): Int32Array | null {
+ const start = this._subParamsIdx[idx] >> 8;
+ const end = this._subParamsIdx[idx] & 0xFF;
+ if (end - start > 0) {
+ return this._subParams.subarray(start, end);
+ }
+ return null;
+ }
+
+ /**
+ * Return all sub parameters as {idx: subparams} mapping.
+ * Note: The values are not borrowed.
+ */
+ public getSubParamsAll(): {[idx: number]: Int32Array} {
+ const result: {[idx: number]: Int32Array} = {};
+ for (let i = 0; i < this.length; ++i) {
+ const start = this._subParamsIdx[i] >> 8;
+ const end = this._subParamsIdx[i] & 0xFF;
+ if (end - start > 0) {
+ result[i] = this._subParams.slice(start, end);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Add a single digit value to current parameter.
+ * This is used by the parser to account digits on a char by char basis.
+ */
+ public addDigit(value: number): void {
+ let length;
+ if (this._rejectDigits
+ || !(length = this._digitIsSub ? this._subParamsLength : this.length)
+ || (this._digitIsSub && this._rejectSubDigits)
+ ) {
+ return;
+ }
+
+ const store = this._digitIsSub ? this._subParams : this.params;
+ const cur = store[length - 1];
+ store[length - 1] = ~cur ? Math.min(cur * 10 + value, MAX_VALUE) : value;
+ }
+}
diff --git a/node_modules/xterm/src/common/parser/Types.d.ts b/node_modules/xterm/src/common/parser/Types.d.ts
new file mode 100644
index 0000000..3a621ea
--- /dev/null
+++ b/node_modules/xterm/src/common/parser/Types.d.ts
@@ -0,0 +1,274 @@
+/**
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IDisposable } from 'common/Types';
+import { ParserState } from 'common/parser/Constants';
+
+
+/** sequence params serialized to js arrays */
+export type ParamsArray = (number | number[])[];
+
+/** Params constructor type. */
+export interface IParamsConstructor {
+ new(maxLength: number, maxSubParamsLength: number): IParams;
+
+ /** create params from ParamsArray */
+ fromArray(values: ParamsArray): IParams;
+}
+
+/** Interface of Params storage class. */
+export interface IParams {
+ /** from ctor */
+ maxLength: number;
+ maxSubParamsLength: number;
+
+ /** param values and its length */
+ params: Int32Array;
+ length: number;
+
+ /** methods */
+ clone(): IParams;
+ toArray(): ParamsArray;
+ reset(): void;
+ addParam(value: number): void;
+ addSubParam(value: number): void;
+ hasSubParams(idx: number): boolean;
+ getSubParams(idx: number): Int32Array | null;
+ getSubParamsAll(): {[idx: number]: Int32Array};
+}
+
+/**
+ * Internal state of EscapeSequenceParser.
+ * Used as argument of the error handler to allow
+ * introspection at runtime on parse errors.
+ * Return it with altered values to recover from
+ * faulty states (not yet supported).
+ * Set `abort` to `true` to abort the current parsing.
+ */
+export interface IParsingState {
+ // position in parse string
+ position: number;
+ // actual character code
+ code: number;
+ // current parser state
+ currentState: ParserState;
+ // collect buffer with intermediate characters
+ collect: number;
+ // params buffer
+ params: IParams;
+ // should abort (default: false)
+ abort: boolean;
+}
+
+/**
+ * Command handler interfaces.
+ */
+
+/**
+ * CSI handler types.
+ * Note: `params` is borrowed.
+ */
+export type CsiHandlerType = (params: IParams) => boolean | Promise<boolean>;
+export type CsiFallbackHandlerType = (ident: number, params: IParams) => void;
+
+/**
+ * DCS handler types.
+ */
+export interface IDcsHandler {
+ /**
+ * Called when a DCS command starts.
+ * Prepare needed data structures here.
+ * Note: `params` is borrowed.
+ */
+ hook(params: IParams): void;
+ /**
+ * Incoming payload chunk.
+ * Note: `params` is borrowed.
+ */
+ put(data: Uint32Array, start: number, end: number): void;
+ /**
+ * End of DCS command. `success` indicates whether the
+ * command finished normally or got aborted, thus final
+ * execution of the command should depend on `success`.
+ * To save memory also cleanup data structures here.
+ */
+ unhook(success: boolean): boolean | Promise<boolean>;
+}
+export type DcsFallbackHandlerType = (ident: number, action: 'HOOK' | 'PUT' | 'UNHOOK', payload?: any) => void;
+
+/**
+ * ESC handler types.
+ */
+export type EscHandlerType = () => boolean | Promise<boolean>;
+export type EscFallbackHandlerType = (identifier: number) => void;
+
+/**
+ * EXECUTE handler types.
+ */
+export type ExecuteHandlerType = () => boolean;
+export type ExecuteFallbackHandlerType = (ident: number) => void;
+
+/**
+ * OSC handler types.
+ */
+export interface IOscHandler {
+ /**
+ * Announces start of this OSC command.
+ * Prepare needed data structures here.
+ */
+ start(): void;
+ /**
+ * Incoming data chunk.
+ * Note: Data is borrowed.
+ */
+ put(data: Uint32Array, start: number, end: number): void;
+ /**
+ * End of OSC command. `success` indicates whether the
+ * command finished normally or got aborted, thus final
+ * execution of the command should depend on `success`.
+ * To save memory also cleanup data structures here.
+ */
+ end(success: boolean): boolean | Promise<boolean>;
+}
+export type OscFallbackHandlerType = (ident: number, action: 'START' | 'PUT' | 'END', payload?: any) => void;
+
+/**
+ * PRINT handler types.
+ */
+export type PrintHandlerType = (data: Uint32Array, start: number, end: number) => void;
+export type PrintFallbackHandlerType = PrintHandlerType;
+
+
+/**
+* EscapeSequenceParser interface.
+*/
+export interface IEscapeSequenceParser extends IDisposable {
+ /**
+ * Preceding codepoint to get REP working correctly.
+ * This must be set by the print handler as last action.
+ * It gets reset by the parser for any valid sequence beside REP itself.
+ */
+ precedingCodepoint: number;
+
+ /**
+ * Reset the parser to its initial state (handlers are kept).
+ */
+ reset(): void;
+
+ /**
+ * Parse UTF32 codepoints in `data` up to `length`.
+ * @param data The data to parse.
+ */
+ parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise<boolean>;
+
+ /**
+ * Get string from numercial function identifier `ident`.
+ * Useful in fallback handlers which expose the low level
+ * numcerical function identifier for debugging purposes.
+ * Note: A full back translation to `IFunctionIdentifier`
+ * is not implemented.
+ */
+ identToString(ident: number): string;
+
+ setPrintHandler(handler: PrintHandlerType): void;
+ clearPrintHandler(): void;
+
+ registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable;
+ clearEscHandler(id: IFunctionIdentifier): void;
+ setEscHandlerFallback(handler: EscFallbackHandlerType): void;
+
+ setExecuteHandler(flag: string, handler: ExecuteHandlerType): void;
+ clearExecuteHandler(flag: string): void;
+ setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void;
+
+ registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable;
+ clearCsiHandler(id: IFunctionIdentifier): void;
+ setCsiHandlerFallback(callback: CsiFallbackHandlerType): void;
+
+ registerDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable;
+ clearDcsHandler(id: IFunctionIdentifier): void;
+ setDcsHandlerFallback(handler: DcsFallbackHandlerType): void;
+
+ registerOscHandler(ident: number, handler: IOscHandler): IDisposable;
+ clearOscHandler(ident: number): void;
+ setOscHandlerFallback(handler: OscFallbackHandlerType): void;
+
+ setErrorHandler(handler: (state: IParsingState) => IParsingState): void;
+ clearErrorHandler(): void;
+}
+
+/**
+ * Subparser interfaces.
+ * The subparsers are instantiated in `EscapeSequenceParser` and
+ * called during `EscapeSequenceParser.parse`.
+ */
+export interface ISubParser<T, U> extends IDisposable {
+ reset(): void;
+ registerHandler(ident: number, handler: T): IDisposable;
+ clearHandler(ident: number): void;
+ setHandlerFallback(handler: U): void;
+ put(data: Uint32Array, start: number, end: number): void;
+}
+
+export interface IOscParser extends ISubParser<IOscHandler, OscFallbackHandlerType> {
+ start(): void;
+ end(success: boolean, promiseResult?: boolean): void | Promise<boolean>;
+}
+
+export interface IDcsParser extends ISubParser<IDcsHandler, DcsFallbackHandlerType> {
+ hook(ident: number, params: IParams): void;
+ unhook(success: boolean, promiseResult?: boolean): void | Promise<boolean>;
+}
+
+/**
+ * Interface to denote a specific ESC, CSI or DCS handler slot.
+ * The values are used to create an integer respresentation during handler
+ * regristation before passed to the subparsers as `ident`.
+ * The integer translation is made to allow a faster handler access
+ * in `EscapeSequenceParser.parse`.
+ */
+export interface IFunctionIdentifier {
+ prefix?: string;
+ intermediates?: string;
+ final: string;
+}
+
+export interface IHandlerCollection<T> {
+ [key: string]: T[];
+}
+
+/**
+ * Types for async parser support.
+ */
+
+// type of saved stack state in parser
+export const enum ParserStackType {
+ NONE = 0,
+ FAIL,
+ RESET,
+ CSI,
+ ESC,
+ OSC,
+ DCS
+}
+
+// aggregate of resumable handler lists
+export type ResumableHandlersType = CsiHandlerType[] | EscHandlerType[];
+
+// saved stack state of the parser
+export interface IParserStackState {
+ state: ParserStackType;
+ handlers: ResumableHandlersType;
+ handlerPos: number;
+ transition: number;
+ chunkPos: number;
+}
+
+// saved stack state of subparser (OSC and DCS)
+export interface ISubParserStackState {
+ paused: boolean;
+ loopPosition: number;
+ fallThrough: boolean;
+}