diff options
author | Anthony Schneider <tonyschneider3@gmail.com> | 2022-02-11 19:40:35 -0600 |
---|---|---|
committer | Anthony Schneider <tonyschneider3@gmail.com> | 2022-02-11 19:40:35 -0600 |
commit | b52feccdcc58c1f4583c8542632d6c026335dea7 (patch) | |
tree | 5e242dd13ed4bbfff85a07109ef826f80874e2a6 /node_modules/xterm/src/common/parser/DcsParser.ts | |
parent | 94862321e2e4a58e3209c037e8061f0435b3aa82 (diff) |
Changed javascript to be in its own file. Began (messy) setup for terminal.
Diffstat (limited to 'node_modules/xterm/src/common/parser/DcsParser.ts')
-rw-r--r-- | node_modules/xterm/src/common/parser/DcsParser.ts | 192 |
1 files changed, 192 insertions, 0 deletions
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; + } +} |