diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 9f548606..3190dc60 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -13,6 +13,7 @@ import { wcwidth } from './CharWidth'; import { EscapeSequenceParser } from './EscapeSequenceParser'; import { ICharset } from './core/Types'; import { Disposable } from './common/Lifecycle'; +import { concat, utf16ToString } from './common/TypedArrayUtils'; /** * Map collect to glevel. Used in `selectCharset`. @@ -33,22 +34,16 @@ const GLEVEL: {[key: string]: number} = {'(': 0, ')': 1, '*': 2, '+': 3, '-': 1, private _data: Uint16Array = new Uint16Array(0); constructor(private _terminal: any) { } hook(collect: string, params: number[], flag: number): void { + this._data = new Uint16Array(0); } put(data: Uint16Array, start: number, end: number): void { - const tmp = new Uint16Array(this._data.length + end - start); - tmp.set(this._data); - tmp.set(data.subarray(start, end), this._data.length); - this._data = data; + this._data = concat(this._data, data.subarray(start, end)); } unhook(): void { - let data = ''; - for (let i = 0; i < this._data.length; ++i) { - data += String.fromCharCode(this._data[i]); - } - this._data = new Uint16Array(0); // dont hold memory longer than needed + const data = utf16ToString(this._data); + this._data = new Uint16Array(0); // invalid: DCS 0 + r Pt ST this._terminal.handler(`${C0.ESC}P0+r${data}${C0.ESC}\\`); - this._data = new Uint16Array(0); } } @@ -67,18 +62,12 @@ class DECRQSS implements IDcsHandler { } put(data: Uint16Array, start: number, end: number): void { - const tmp = new Uint16Array(this._data.length + end - start); - tmp.set(this._data); - tmp.set(data.subarray(start, end), this._data.length); - this._data = data; + this._data = concat(this._data, data.subarray(start, end)); } unhook(): void { - let data = ''; - for (let i = 0; i < this._data.length; ++i) { - data += String.fromCharCode(this._data[i]); - } - this._data = new Uint16Array(0); // dont hold memory longer than needed + const data = utf16ToString(this._data); + this._data = new Uint16Array(0); switch (data) { // valid: DCS 1 $ r Pt ST (xterm) case '"q': // DECSCA diff --git a/src/common/TypedArrayUtils.test.ts b/src/common/TypedArrayUtils.test.ts index 69a62abc..b25b9b9a 100644 --- a/src/common/TypedArrayUtils.test.ts +++ b/src/common/TypedArrayUtils.test.ts @@ -3,21 +3,20 @@ * @license MIT */ import { assert } from 'chai'; -import { fillFallback } from './TypedArrayUtils'; +import { fillFallback, concat, utf16ToString } from './TypedArrayUtils'; type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array; -describe('polyfill conformance tests', function(): void { - - function deepEquals(a: TypedArray, b: TypedArray): void { - assert.equal(a.length, b.length); - for (let i = 0; i < a.length; ++i) { - assert.equal(a[i], b[i]); - } +function deepEquals(a: TypedArray, b: TypedArray): void { + assert.equal(a.length, b.length); + for (let i = 0; i < a.length; ++i) { + assert.equal(a[i], b[i]); } +} +describe('polyfill conformance tests', function(): void { describe('TypedArray.fill', function(): void { it('should work with all typed array types', function(): void { const u81 = new Uint8Array(5); @@ -87,3 +86,20 @@ describe('polyfill conformance tests', function(): void { }); }); }); + +describe('typed array convenience functions', () => { + it('concat', () => { + const a = new Uint8Array([1, 2, 3, 4, 5]); + const b = new Uint8Array([6, 7, 8, 9, 0]); + const merged = concat(a, b); + deepEquals(merged, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])); + }); + it('utf16ToString', () => { + const s = 'abcdefg'; + const data = new Uint16Array(s.length); + for (let i = 0; i < s.length; ++i) { + data[i] = s.charCodeAt(i); + } + assert.equal(utf16ToString(data), s); + }); +}); diff --git a/src/common/TypedArrayUtils.ts b/src/common/TypedArrayUtils.ts index 6e1a3630..8b540548 100644 --- a/src/common/TypedArrayUtils.ts +++ b/src/common/TypedArrayUtils.ts @@ -3,15 +3,14 @@ * @license MIT */ -/** - * polyfill for TypedArray.fill - * This is needed to support .fill in all safari versions and IE 11. - */ - type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array; +/** + * polyfill for TypedArray.fill + * This is needed to support .fill in all safari versions and IE 11. + */ export function fill(array: T, value: number, start?: number, end?: number): T { // all modern engines that support .fill if (array.fill) { @@ -39,3 +38,28 @@ export function fillFallback(array: T, value: number, star } return array; } + +/** + * Concat two typed arrays `a` and `b`. + * Returns a new typed array. + */ +export function concat(a: T, b: T): T { + const result = new (a.constructor as any)(a.length + b.length); + result.set(a); + result.set(b, a.length); + return result; +} + +/** + * Convert UTF16 char codes into JS string. + * Note the typed array is not limited to Uint16Array, make sure to align + * the values to 0-65535 integer for other typed array types, otherwise + * the conversion will fail. + */ +export function utf16ToString(data: T): string { + let s = ''; + for (let i = 0; i < data.length; ++i) { + s += String.fromCharCode(data[i]); + } + return s; +}