xterm
[VSoRC/.git] / node_modules / xterm / src / common / parser / DcsParser.ts
diff --git a/node_modules/xterm/src/common/parser/DcsParser.ts b/node_modules/xterm/src/common/parser/DcsParser.ts
new file mode 100644 (file)
index 0000000..4622c4a
--- /dev/null
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2019 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IDisposable } from 'common/Types';
+import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType } 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 = () => {};
+
+  public dispose(): void {
+    this._handlers = Object.create(null);
+    this._handlerFb = () => {};
+  }
+
+  public addHandler(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 setHandler(ident: number, handler: IDcsHandler): void {
+    this._handlers[ident] = [handler];
+  }
+
+  public clearHandler(ident: number): void {
+    if (this._handlers[ident]) delete this._handlers[ident];
+  }
+
+  public setHandlerFallback(handler: DcsFallbackHandlerType): void {
+    this._handlerFb = handler;
+  }
+
+  public reset(): void {
+    if (this._active.length) {
+      this.unhook(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): void {
+    if (!this._active.length) {
+      this._handlerFb(this._ident, 'UNHOOK', success);
+    } else {
+      let j = this._active.length - 1;
+      for (; j >= 0; j--) {
+        if (this._active[j].unhook(success) !== false) {
+          break;
+        }
+      }
+      j--;
+      // cleanup left over handlers
+      for (; j >= 0; j--) {
+        this._active[j].unhook(false);
+      }
+    }
+    this._active = EMPTY_HANDLERS;
+    this._ident = 0;
+  }
+}
+
+/**
+ * Convenient class to create a DCS handler from a single callback function.
+ * Note: The payload is currently limited to 50 MB (hardcoded).
+ */
+export class DcsHandler implements IDcsHandler {
+  private _data = '';
+  private _params: IParams | undefined;
+  private _hitLimit: boolean = false;
+
+  constructor(private _handler: (data: string, params: IParams) => any) {}
+
+  public hook(params: IParams): void {
+    this._params = params.clone();
+    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): any {
+    let ret;
+    if (this._hitLimit) {
+      ret = false;
+    } else if (success) {
+      ret = this._handler(this._data, this._params ? this._params : new Params());
+    }
+    this._params = undefined;
+    this._data = '';
+    this._hitLimit = false;
+    return ret;
+  }
+}