X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fxterm%2Fsrc%2Fcommon%2Fparser%2FOscParser.ts;fp=node_modules%2Fxterm%2Fsrc%2Fcommon%2Fparser%2FOscParser.ts;h=e8c5a801f22fd006fba10e4bdfbfe1399bd2d88b;hp=0000000000000000000000000000000000000000;hb=4339da12467b75fb8b6ca831f4bf0081c485ed2c;hpb=af450fde25a9ccf4767b29254c463ffb8ef25237 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..e8c5a80 --- /dev/null +++ b/node_modules/xterm/src/common/parser/OscParser.ts @@ -0,0 +1,203 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IOscHandler, IHandlerCollection, OscFallbackHandlerType, IOscParser } from 'common/parser/Types'; +import { OscState, PAYLOAD_LIMIT } from 'common/parser/Constants'; +import { utf32ToString } from 'common/input/TextDecoder'; +import { IDisposable } from 'common/Types'; + + +export class OscParser implements IOscParser { + private _state = OscState.START; + private _id = -1; + private _handlers: IHandlerCollection = Object.create(null); + private _handlerFb: OscFallbackHandlerType = () => { }; + + public addHandler(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 setHandler(ident: number, handler: IOscHandler): void { + this._handlers[ident] = [handler]; + } + 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 = () => {}; + } + + public reset(): void { + // cleanup handlers if payload was already sent + if (this._state === OscState.PAYLOAD) { + this.end(false); + } + this._id = -1; + this._state = OscState.START; + } + + private _start(): void { + const handlers = this._handlers[this._id]; + if (!handlers) { + this._handlerFb(this._id, 'START'); + } else { + for (let j = handlers.length - 1; j >= 0; j--) { + handlers[j].start(); + } + } + } + + private _put(data: Uint32Array, start: number, end: number): void { + const handlers = this._handlers[this._id]; + if (!handlers) { + this._handlerFb(this._id, 'PUT', utf32ToString(data, start, end)); + } else { + for (let j = handlers.length - 1; j >= 0; j--) { + handlers[j].put(data, start, end); + } + } + } + + private _end(success: boolean): void { + // other than the old code we always have to call .end + // to keep the bubbling we use `success` to indicate + // whether a handler should execute + const handlers = this._handlers[this._id]; + if (!handlers) { + this._handlerFb(this._id, 'END', success); + } else { + let j = handlers.length - 1; + for (; j >= 0; j--) { + if (handlers[j].end(success) !== false) { + break; + } + } + j--; + // cleanup left over handlers + for (; j >= 0; j--) { + handlers[j].end(false); + } + } + } + + public start(): void { + // always reset leftover handlers + this.reset(); + this._id = -1; + 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): void { + 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(); + } + this._end(success); + } + 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) => any) {} + + 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): any { + let ret; + if (this._hitLimit) { + ret = false; + } else if (success) { + ret = this._handler(this._data); + } + this._data = ''; + this._hitLimit = false; + return ret; + } +}