Compare commits

..
Author SHA1 Message Date
Cursor AgentandDaniel Imms 1040b799ce Disallow single-line brace-style blocks
Set allowSingleLine to false and expand multi-line braces
across the codebase via eslint --fix.

Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
2026-05-26 17:07:35 +00:00
Cursor AgentandDaniel Imms 1c42ae9af4 Add brace-style lint rule and fix violations
Enforce 1tbs brace style with allowSingleLine per #5900.
Auto-fix else/catch brace placement across the codebase and
move a comment in font.ts that blocked else-if formatting.

Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
2026-05-26 16:42:48 +00:00
Daniel Imms e749cb6125 Merge pull request #5891 from Tyriar/cross-env
Remove cross-env dep
2026-05-21 03:17:50 -07:00
Daniel Imms 8df996f9e7 Merge pull request #5892 from Tyriar/tyriar/deps
Remove @types/debug and trusted-types
2026-05-21 03:17:24 -07:00
Daniel Imms 51f6186352 Remove @types/debug and trusted-types 2026-05-21 03:09:41 -07:00
Daniel Imms ae5c41c518 Merge pull request #5890 from Tyriar/utf8
Remove utf8 dep
2026-05-21 03:09:04 -07:00
Daniel Imms df9fb7e473 Remove cross-env dep 2026-05-21 03:06:53 -07:00
Daniel Imms f100e93ba5 Remove utf8 dep 2026-05-21 03:04:16 -07:00
Daniel Imms 1d3825d341 Merge pull request #5889 from Tyriar/deepEqual
Remove deep-equal/types packages
2026-05-21 03:03:37 -07:00
Daniel Imms 57315e6cc9 Remove deep-equal/types packages 2026-05-21 02:58:43 -07:00
Daniel Imms 2be4fc68e5 Merge pull request #5884 from sotasan/addon-image-kitty-q2-suppresses-ok
addon-image: Kitty graphics q=2 should suppress OK responses too
2026-05-21 02:37:53 -07:00
Daniel Imms 66fabfc232 Merge pull request #5878 from PerBothner/demo-size-style
demo - indicate screen area size when non-auto
2026-05-21 02:36:24 -07:00
Daniel Imms 3e2a42eb29 Merge pull request #5883 from vsych/fix-webgl-atlas-merge-stale-vertices
Fix webgl rendering corruption from atlas page merges
2026-05-21 02:26:03 -07:00
Daniel Imms 6a47d09b4c Merge pull request #5888 from Tyriar/tyriar/nal-trace
Git ignore cursor nal-traces
2026-05-21 02:18:06 -07:00
Daniel Imms b36001ee7b Git ignore cursor nal-traces 2026-05-21 02:17:43 -07:00
Daniel Imms e64f25a0dd Merge pull request #5880 from ciembor/master
Add 4bit to the Real-world uses section.
2026-05-21 02:13:34 -07:00
Victor Sych 3bcb57545e Re-upload atlas textures after page merges 2026-05-21 04:59:37 +02:00
Victor Sych dc726a2ae6 Fix webgl rendering corruption from atlas page merges 2026-05-19 02:27:15 +02:00
Sōta 06e5ac7ab4 addon-image: Kitty graphics q=2 should suppress OK responses too 2026-05-18 18:26:32 +02:00
Maciej Ciemborowicz c6e3492a4a Add 4bit to the Real-world uses section. 2026-05-14 04:45:52 +02:00
Per Bothner 86291b6e96 Highlight xterm-screen when size is non-auto 2026-05-12 17:53:33 -07:00
70 changed files with 1665 additions and 2859 deletions
+3
View File
@@ -22,6 +22,9 @@ build/
yarn.lock
test-results/
# Tracing/debug files
.cursor/nal-trace/
# Keep bundled code out of Git
dist/
demo/dist/
+1
View File
@@ -253,6 +253,7 @@ Xterm.js is used in many world-class applications to provide great terminal expe
- [**SSH Connection Manager**](https://github.com/Amtrend/ssh-manager): Modern web-based SSH terminal and SFTP manager with AES-256 encryption, PWA support, and session management.
- [**WooTTY**](https://github.com/icoretech/wootty): Flawless browser terminal for real operators.
- [**Orca**](https://github.com/stablyai/orca): Agentic development environment for 100x builders.
- [**4bit**](https://ciembor.github.io/4bit): Terminal Color Scheme Designer.
- [And much more...](https://github.com/xtermjs/xterm.js/network/dependents?package_id=UGFja2FnZS0xNjYzMjc4OQ%3D%3D)
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it on our list. Please add any new contributions to the end of the list.
+3 -1
View File
@@ -21,7 +21,9 @@ const enum Constants {
*/
export class ImageRenderer extends Disposable implements IDisposable {
/** @deprecated Kept for backward compat — points to top layer canvas. */
public get canvas(): HTMLCanvasElement | undefined { return this._layers.get('top')?.canvas; }
public get canvas(): HTMLCanvasElement | undefined {
return this._layers.get('top')?.canvas;
}
private _layers = new Map<ImageLayer, CanvasRenderingContext2D>();
private _placeholder: HTMLCanvasElement | undefined;
private _placeholderBitmap: ImageBitmap | undefined;
+3 -1
View File
@@ -31,7 +31,9 @@ class ExtendedAttrsImage implements IExtendedAttrsImage {
}
return this._ext;
}
public set ext(value: number) { this._ext = value; }
public set ext(value: number) {
this._ext = value;
}
public get underlineStyle(): UnderlineStyle {
// Always return the URL style if it has one
@@ -533,8 +533,8 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler, IDispos
private _sendResponse(id: number, message: string, quiet: number, placementId?: number): void {
const isOk = message === 'OK';
if (isOk && quiet === 1) return;
if (!isOk && quiet === 2) return;
if (isOk && quiet >= 1) return;
if (!isOk && quiet >= 2) return;
const pPart = placementId ? `,p=${placementId}` : '';
const response = `\x1b_Gi=${id}${pPart};${message}\x1b\\`;
+201 -47
View File
@@ -322,7 +322,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('chunked transfer responds OK on final chunk when i= on first only', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
const half = Math.floor(KITTY_BLACK_1X1_BASE64.length / 2);
@@ -542,7 +544,9 @@ test.describe('Kitty Graphics Protocol', () => {
let response = '';
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write('\x1b_Gi=31,a=q;\x1b\\');
@@ -556,7 +560,9 @@ test.describe('Kitty Graphics Protocol', () => {
let response = '';
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=42,a=q,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -581,7 +587,9 @@ test.describe('Kitty Graphics Protocol', () => {
let response = '';
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write('\x1b_Gi=60,a=q,f=100;!!!invalid!!!\x1b\\');
@@ -595,7 +603,9 @@ test.describe('Kitty Graphics Protocol', () => {
let response = '';
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write('\x1b_Gi=70,a=q,f=24;AAAA\x1b\\');
@@ -608,7 +618,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('suppresses OK response when q=1', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Gi=80,a=q,q=1,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -617,10 +629,26 @@ test.describe('Kitty Graphics Protocol', () => {
strictEqual(await ctx.page.evaluate('window.kittyGotResponse'), false);
});
test('suppresses OK response when q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Gi=81,a=q,q=2,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
await timeout(100);
strictEqual(await ctx.page.evaluate('window.kittyGotResponse'), false);
});
test('suppresses error response when q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write('\x1b_Gi=90,a=q,q=2,f=100;!!!invalid!!!\x1b\\');
@@ -633,7 +661,9 @@ test.describe('Kitty Graphics Protocol', () => {
let response = '';
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
// Per spec: "Specifying both i and I keys in any command is an error"
@@ -648,7 +678,9 @@ test.describe('Kitty Graphics Protocol', () => {
let response = '';
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
// Delete command with both i and I (no payload case)
@@ -664,7 +696,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=t sends EINVAL on decode error when id is specified', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write('\x1b_Gi=110,a=t,f=100;!!!invalid!!!\x1b\\');
@@ -677,7 +711,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=t sends no response on decode error without id', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write('\x1b_Ga=t,f=100;!!!invalid!!!\x1b\\');
@@ -689,7 +725,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=T sends EINVAL on decode error when id is specified', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write('\x1b_Gi=120,a=T,f=100;!!!invalid!!!\x1b\\');
@@ -702,7 +740,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=T sends no response on decode error without id', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write('\x1b_Ga=T,f=100;!!!invalid!!!\x1b\\');
@@ -714,7 +754,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=T sends EINVAL when raw pixel render fails (missing dimensions)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=130,a=T,f=24;${RAW_RGB_1X1_BLACK}\x1b\\`);
@@ -727,7 +769,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=T sends OK on successful render with id', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=140,a=T,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -740,7 +784,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=t sends OK on successful transmit with id', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=150,a=t,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -753,7 +799,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=t EINVAL suppressed by q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write('\x1b_Gi=160,a=t,q=2,f=100;!!!invalid!!!\x1b\\');
@@ -765,7 +813,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=T EINVAL suppressed by q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write('\x1b_Gi=170,a=T,q=2,f=100;!!!invalid!!!\x1b\\');
@@ -777,7 +827,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=t OK suppressed by q=1', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Gi=180,a=t,q=1,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -789,7 +841,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('a=T OK suppressed by q=1', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Gi=190,a=T,q=1,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -797,13 +851,43 @@ test.describe('Kitty Graphics Protocol', () => {
strictEqual(await ctx.page.evaluate('window.kittyGotResponse'), false);
});
test('a=t OK suppressed by q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Gi=181,a=t,q=2,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
await timeout(100);
strictEqual(await ctx.page.evaluate('window.kittyGotResponse'), false);
});
test('a=T OK suppressed by q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Gi=191,a=T,q=2,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
await timeout(100);
strictEqual(await ctx.page.evaluate('window.kittyGotResponse'), false);
});
});
test.describe('Transmission medium rejection', () => {
test('query rejects t=f (file transmission)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=200,a=q,t=f,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -816,7 +900,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query rejects t=s (shared memory)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=201,a=q,t=s,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -829,7 +915,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query rejects t=t (temp file)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=202,a=q,t=t,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -842,7 +930,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query accepts t=d (direct transmission)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=203,a=q,t=d,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -855,7 +945,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query without t key defaults to direct (OK)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=204,a=q,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -868,7 +960,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit rejects t=f with id (EINVAL response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=300,a=t,t=f,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -881,7 +975,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit rejects t=s with id (EINVAL response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=301,a=t,t=s,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -894,7 +990,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit rejects t=t with id (EINVAL response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=302,a=t,t=t,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -907,7 +1005,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit rejects t=f without id (no response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Ga=t,t=f,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -920,7 +1020,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit+display rejects t=f with id (EINVAL response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=310,a=T,t=f,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -933,7 +1035,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit+display rejects t=s with id (EINVAL response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=311,a=T,t=s,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -946,7 +1050,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit+display rejects t=t with id (EINVAL response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=312,a=T,t=t,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -959,7 +1065,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('transmit+display rejects t=f without id (no response)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Ga=T,t=f,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
@@ -990,7 +1098,9 @@ test.describe('Kitty Graphics Protocol', () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=211\x1b\\`);
@@ -1003,7 +1113,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('responds ENOENT for non-existent image id', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=9999\x1b\\`);
@@ -1016,7 +1128,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('without id sends no response', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Ga=p\x1b\\`);
@@ -1136,7 +1250,9 @@ test.describe('Kitty Graphics Protocol', () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=220,q=1\x1b\\`);
@@ -1146,10 +1262,30 @@ test.describe('Kitty Graphics Protocol', () => {
strictEqual(await getImageStorageLength(), 1);
});
test('OK response suppressed by q=2', async () => {
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=221;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
await timeout(100);
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=221,q=2\x1b\\`);
await timeout(100);
strictEqual(await ctx.page.evaluate('window.kittyGotResponse'), false);
strictEqual(await getImageStorageLength(), 1);
});
test('ENOENT error suppressed by q=2', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyGotResponse = false;
(window as any).term.onData(() => { (window as any).kittyGotResponse = true; });
(window as any).term.onData(() => {
(window as any).kittyGotResponse = true;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=9998,q=2\x1b\\`);
@@ -1161,7 +1297,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('ENOENT still reported when q=1 (only suppresses OK)', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=9997,q=1\x1b\\`);
@@ -1216,7 +1354,9 @@ test.describe('Kitty Graphics Protocol', () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Ga=p,i=224,p=42\x1b\\`);
@@ -1751,7 +1891,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('responds with OK for valid 200x100 PNG query', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=600,a=q,f=100;${KITTY_MULTICOLOR_200X100_BASE64}\x1b\\`);
@@ -1900,7 +2042,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query returns EINVAL without dimensions', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=200,a=q,f=24;${RAW_RGB_1X1_BLACK}\x1b\\`);
await timeout(100);
@@ -1911,7 +2055,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query returns EINVAL for insufficient pixel data', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=201,a=q,f=24,s=2,v=2;${RAW_RGB_1X1_BLACK}\x1b\\`);
await timeout(100);
@@ -1922,7 +2068,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query returns OK for valid RGB data with correct dimensions', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=202,a=q,f=24,s=1,v=1;${RAW_RGB_1X1_RED}\x1b\\`);
await timeout(100);
@@ -2034,7 +2182,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query returns EINVAL without dimensions', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=300,a=q,f=32;${RAW_RGBA_1X1_RED}\x1b\\`);
await timeout(100);
@@ -2045,7 +2195,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query returns EINVAL for insufficient pixel data', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=301,a=q,f=32,s=2,v=2;${RAW_RGBA_1X1_RED}\x1b\\`);
await timeout(100);
@@ -2056,7 +2208,9 @@ test.describe('Kitty Graphics Protocol', () => {
test('query returns OK for valid RGBA data with correct dimensions', async () => {
await ctx.page.evaluate(() => {
(window as any).kittyResponse = '';
(window as any).term.onData((data: string) => { (window as any).kittyResponse = data; });
(window as any).term.onData((data: string) => {
(window as any).kittyResponse = data;
});
});
await ctx.proxy.write(`\x1b_Gi=302,a=q,f=32,s=1,v=1;${RAW_RGBA_1X1_RED}\x1b\\`);
await timeout(100);
+2 -3
View File
@@ -65,9 +65,8 @@ export default async function load(fontFamily: string, cacheSize: number): Promi
console.error(err.name, err.message);
}
}
}
// Latest proposal https://bugs.chromium.org/p/chromium/issues/detail?id=1312603
else if (typeof window !== 'undefined' && 'queryLocalFonts' in window) {
} else if (typeof window !== 'undefined' && 'queryLocalFonts' in window) {
// Latest proposal https://bugs.chromium.org/p/chromium/issues/detail?id=1312603
const fonts: Record<string, IFontMetadata[]> = {};
try {
const fontsIterator = await (window as any).queryLocalFonts();
@@ -46,7 +46,9 @@ describe('LigaturesAddon', () => {
});
beforeEach(() => {
onRefresh = Object.assign((..._args: any[]) => { onRefresh.called = true; onRefresh.callCount++; }, { called: false, callCount: 0 });
onRefresh = Object.assign((..._args: any[]) => {
onRefresh.called = true; onRefresh.callCount++;
}, { called: false, callCount: 0 });
term = new MockTerminal(onRefresh);
ligatureSupport.enableLigatures(term as any);
});
@@ -127,7 +129,9 @@ class MockTerminal {
public deregisterCharacterJoiner(id: number): void {
this.joiner = undefined;
}
public get options(): { [name: string]: string | number } { return this._options; }
public get options(): { [name: string]: string | number } {
return this._options;
}
public set options(options: { [name: string]: string | number }) {
for (const key in this._options) {
this._options[key] = options[key];
+6 -2
View File
@@ -64,7 +64,9 @@ export class DecorationManager extends Disposable {
public createActiveDecoration(result: ISearchResult, options: ISearchDecorationOptions): IMultiHighlight | undefined {
const decorations = this._createResultDecorations(result, options, true);
if (decorations) {
return { decorations, match: result, dispose() { dispose(decorations); } };
return { decorations, match: result, dispose() {
dispose(decorations);
} };
}
return undefined;
}
@@ -85,7 +87,9 @@ export class DecorationManager extends Disposable {
*/
private _storeDecoration(decoration: IDecoration, match: ISearchResult): void {
this._highlightedLines.add(decoration.marker.line);
this._highlightDecorations.push({ decoration, match, dispose() { decoration.dispose(); } });
this._highlightDecorations.push({ decoration, match, dispose() {
decoration.dispose();
} });
}
/**
@@ -25,7 +25,9 @@ export class SearchResultTracker extends Disposable {
private _selectedDecoration: ISelectedDecoration | undefined;
private readonly _onDidChangeResults = this._register(new Emitter<ISearchResultChangeEvent>());
public get onDidChangeResults(): IEvent<ISearchResultChangeEvent> { return this._onDidChangeResults.event; }
public get onDidChangeResults(): IEvent<ISearchResultChangeEvent> {
return this._onDidChangeResults.event;
}
/**
* Gets the current search results.
@@ -29,12 +29,20 @@ class TestSelectionService {
this._model = new SelectionModel(bufferService);
}
public get model(): SelectionModel { return this._model; }
public get model(): SelectionModel {
return this._model;
}
public get hasSelection(): boolean { return this._hasSelection; }
public get hasSelection(): boolean {
return this._hasSelection;
}
public get selectionStart(): [number, number] | undefined { return this._model.finalSelectionStart; }
public get selectionEnd(): [number, number] | undefined { return this._model.finalSelectionEnd; }
public get selectionStart(): [number, number] | undefined {
return this._model.finalSelectionStart;
}
public get selectionEnd(): [number, number] | undefined {
return this._model.finalSelectionEnd;
}
public setSelection(col: number, row: number, length: number): void {
this._model.selectionStart = [col, row];
+63 -26
View File
@@ -70,7 +70,9 @@ abstract class BaseSerializeHandler {
protected _rowEnd(row: number, isLastRow: boolean): void { }
protected _beforeSerialize(rows: number, startRow: number, endRow: number): void { }
protected _afterSerialize(): void { }
protected _serializeString(excludeFinalCursorPosition?: boolean): string { return ''; }
protected _serializeString(excludeFinalCursorPosition?: boolean): string {
return '';
}
}
function equalFg(cell1: IBufferCell | IAttributeData, cell2: IBufferCell): boolean {
@@ -291,25 +293,39 @@ class StringSerializeHandler extends BaseSerializeHandler {
} else {
if (fgChanged) {
const color = cell.getFgColor();
if (cell.isFgRGB()) { sgrSeq.push(38, 2, (color >>> 16) & 0xFF, (color >>> 8) & 0xFF, color & 0xFF); }
else if (cell.isFgPalette()) {
if (color >= 16) { sgrSeq.push(38, 5, color); }
else { sgrSeq.push(color & 8 ? 90 + (color & 7) : 30 + (color & 7)); }
if (cell.isFgRGB()) {
sgrSeq.push(38, 2, (color >>> 16) & 0xFF, (color >>> 8) & 0xFF, color & 0xFF);
} else if (cell.isFgPalette()) {
if (color >= 16) {
sgrSeq.push(38, 5, color);
} else {
sgrSeq.push(color & 8 ? 90 + (color & 7) : 30 + (color & 7));
}
} else {
sgrSeq.push(39);
}
else { sgrSeq.push(39); }
}
if (bgChanged) {
const color = cell.getBgColor();
if (cell.isBgRGB()) { sgrSeq.push(48, 2, (color >>> 16) & 0xFF, (color >>> 8) & 0xFF, color & 0xFF); }
else if (cell.isBgPalette()) {
if (color >= 16) { sgrSeq.push(48, 5, color); }
else { sgrSeq.push(color & 8 ? 100 + (color & 7) : 40 + (color & 7)); }
if (cell.isBgRGB()) {
sgrSeq.push(48, 2, (color >>> 16) & 0xFF, (color >>> 8) & 0xFF, color & 0xFF);
} else if (cell.isBgPalette()) {
if (color >= 16) {
sgrSeq.push(48, 5, color);
} else {
sgrSeq.push(color & 8 ? 100 + (color & 7) : 40 + (color & 7));
}
} else {
sgrSeq.push(49);
}
else { sgrSeq.push(49); }
}
if (flagsChanged) {
if (cell.isInverse() !== oldCell.isInverse()) { sgrSeq.push(cell.isInverse() ? 7 : 27); }
if (cell.isBold() !== oldCell.isBold()) { sgrSeq.push(cell.isBold() ? 1 : 22); }
if (cell.isInverse() !== oldCell.isInverse()) {
sgrSeq.push(cell.isInverse() ? 7 : 27);
}
if (cell.isBold() !== oldCell.isBold()) {
sgrSeq.push(cell.isBold() ? 1 : 22);
}
if (!equalUnderline(cell, oldCell)) {
const style = cell.getUnderlineStyle();
if (style === UnderlineStyle.NONE) {
@@ -332,12 +348,24 @@ class StringSerializeHandler extends BaseSerializeHandler {
} else if (cell.isUnderline() !== oldCell.isUnderline()) {
sgrSeq.push(cell.isUnderline() ? 4 : 24);
}
if (cell.isOverline() !== oldCell.isOverline()) { sgrSeq.push(cell.isOverline() ? 53 : 55); }
if (cell.isBlink() !== oldCell.isBlink()) { sgrSeq.push(cell.isBlink() ? 5 : 25); }
if (cell.isInvisible() !== oldCell.isInvisible()) { sgrSeq.push(cell.isInvisible() ? 8 : 28); }
if (cell.isItalic() !== oldCell.isItalic()) { sgrSeq.push(cell.isItalic() ? 3 : 23); }
if (cell.isDim() !== oldCell.isDim()) { sgrSeq.push(cell.isDim() ? 2 : 22); }
if (cell.isStrikethrough() !== oldCell.isStrikethrough()) { sgrSeq.push(cell.isStrikethrough() ? 9 : 29); }
if (cell.isOverline() !== oldCell.isOverline()) {
sgrSeq.push(cell.isOverline() ? 53 : 55);
}
if (cell.isBlink() !== oldCell.isBlink()) {
sgrSeq.push(cell.isBlink() ? 5 : 25);
}
if (cell.isInvisible() !== oldCell.isInvisible()) {
sgrSeq.push(cell.isInvisible() ? 8 : 28);
}
if (cell.isItalic() !== oldCell.isItalic()) {
sgrSeq.push(cell.isItalic() ? 3 : 23);
}
if (cell.isDim() !== oldCell.isDim()) {
sgrSeq.push(cell.isDim() ? 2 : 22);
}
if (cell.isStrikethrough() !== oldCell.isStrikethrough()) {
sgrSeq.push(cell.isStrikethrough() ? 9 : 29);
}
}
}
}
@@ -646,8 +674,7 @@ export class HTMLSerializeHandler extends BaseSerializeHandler {
// For xterm headless: fallback to ansi colors
if ((_terminal as any)._core._themeService) {
this._ansiColors = (_terminal as any)._core._themeService.colors.ansi;
}
else {
} else {
this._ansiColors = DEFAULT_ANSI_COLORS;
}
}
@@ -752,8 +779,12 @@ export class HTMLSerializeHandler extends BaseSerializeHandler {
content.push('background-color: ' + bgHexColor + ';');
}
if (cell.isInverse()) { content.push('color: #000000; background-color: #BFBFBF;'); }
if (cell.isBold()) { content.push('font-weight: bold;'); }
if (cell.isInverse()) {
content.push('color: #000000; background-color: #BFBFBF;');
}
if (cell.isBold()) {
content.push('font-weight: bold;');
}
// Handle text-decoration (underline, overline, strikethrough, blink)
const decorations: string[] = [];
@@ -781,9 +812,15 @@ export class HTMLSerializeHandler extends BaseSerializeHandler {
}
}
if (cell.isInvisible()) { content.push('visibility: hidden;'); }
if (cell.isItalic()) { content.push('font-style: italic;'); }
if (cell.isDim()) { content.push('opacity: 0.5;'); }
if (cell.isInvisible()) {
content.push('visibility: hidden;');
}
if (cell.isItalic()) {
content.push('font-style: italic;');
}
if (cell.isDim()) {
content.push('opacity: 0.5;');
}
return content;
}
@@ -40,7 +40,9 @@ export class CursorBlinkStateManager {
}
}
public get isPaused(): boolean { return !(this._blinkStartTimeout || this._blinkInterval); }
public get isPaused(): boolean {
return !(this._blinkStartTimeout || this._blinkInterval);
}
public dispose(): void {
if (this._blinkInterval) {
+7 -1
View File
@@ -358,7 +358,9 @@ export class GlyphRenderer extends Disposable {
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, activeBuffer.subarray(0, bufferLength), gl.STREAM_DRAW);
// Bind the atlas page texture if they have changed
// Bind the atlas page texture if they have changed. AtlasPage.version is globally
// monotonic, so a page object swap at the same index (which happens after a page merge)
// is detected by the same comparison.
for (let i = 0; i < this._atlas.pages.length; i++) {
if (this._atlas.pages[i].version !== this._atlasTextures[i].version) {
this._bindAtlasPageTexture(gl, this._atlas, i);
@@ -371,6 +373,10 @@ export class GlyphRenderer extends Disposable {
public setAtlas(atlas: ITextureAtlas): void {
this._atlas = atlas;
this.invalidateAtlasTextures();
}
public invalidateAtlasTextures(): void {
for (const glTexture of this._atlasTextures) {
glTexture.version = -1;
}
+3 -2
View File
@@ -336,8 +336,9 @@ export class RectangleRenderer extends Disposable {
}
}
if (vertices.attributes.length < offset + 4) {
vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE);
if (vertices.attributes.length < offset + INDICES_PER_RECTANGLE) {
// +1 for the viewport-clear rectangle at offset 0.
vertices.attributes = expandFloat32Array(vertices.attributes, (this._terminal.rows * this._terminal.cols + 1) * INDICES_PER_RECTANGLE);
}
$x1 = startX * this._dimensions.device.cell.width;
$y1 = y * this._dimensions.device.cell.height;
+22 -10
View File
@@ -62,7 +62,9 @@ export class TextureAtlas implements ITextureAtlas {
// The texture that the atlas is drawn to
private _pages: AtlasPage[] = [];
public get pages(): { canvas: HTMLCanvasElement, version: number }[] { return this._pages; }
public get pages(): { canvas: HTMLCanvasElement, version: number }[] {
return this._pages;
}
// The set of atlas pages that can be written to
private _activePages: AtlasPage[] = [];
@@ -133,7 +135,9 @@ export class TextureAtlas implements ITextureAtlas {
private _requestClearModel = false;
public beginFrame(): boolean {
return this._requestClearModel;
const result = this._requestClearModel;
this._requestClearModel = false;
return result;
}
public clearTexture(): void {
@@ -193,7 +197,7 @@ export class TextureAtlas implements ITextureAtlas {
// Merge into the new page
const mergedPage = this._mergePages(mergingPages, mergedPageIndex);
mergedPage.version++;
mergedPage.version = ++AtlasPage.nextVersion;
// Delete the pages, shifting glyph texture pages as needed
for (let i = sortedMergingPagesIndexes.length - 1; i >= 0; i--) {
@@ -251,7 +255,7 @@ export class TextureAtlas implements ITextureAtlas {
for (const g of adjustingPage.glyphs) {
g.texturePage--;
}
adjustingPage.version++;
adjustingPage.version = ++AtlasPage.nextVersion;
}
}
@@ -937,7 +941,7 @@ export class TextureAtlas implements ITextureAtlas {
rasterizedGlyph.size.y
);
activePage.addGlyph(rasterizedGlyph);
activePage.version++;
activePage.version = ++AtlasPage.nextVersion;
return rasterizedGlyph;
}
@@ -1037,19 +1041,27 @@ class AtlasPage {
public readonly ctx: CanvasRenderingContext2D;
private _usedPixels: number = 0;
public get percentageUsed(): number { return this._usedPixels / (this.canvas.width * this.canvas.height); }
public get percentageUsed(): number {
return this._usedPixels / (this.canvas.width * this.canvas.height);
}
private readonly _glyphs: IRasterizedGlyph[] = [];
public get glyphs(): ReadonlyArray<IRasterizedGlyph> { return this._glyphs; }
public get glyphs(): ReadonlyArray<IRasterizedGlyph> {
return this._glyphs;
}
public addGlyph(glyph: IRasterizedGlyph): void {
this._glyphs.push(glyph);
this._usedPixels += glyph.size.x * glyph.size.y;
}
/**
* Used to check whether the canvas of the atlas page has changed.
* Monotonically increasing across all atlas pages globally. Used to detect when the texture
* unit at a given index needs to be re-uploaded — both for content changes within the same
* page and for a page object swap at the same index (which happens after a page merge,
* where a per-page counter could coincide with the previously-bound page's value).
*/
public version = 0;
public static nextVersion: number = 0;
public version = ++AtlasPage.nextVersion;
// Texture atlas current positioning data. The texture packing strategy used is to fill from
// left-to-right and top-to-bottom. When the glyph being written is less than half of the current
@@ -1092,7 +1104,7 @@ class AtlasPage {
this.currentRow.y = 0;
this.currentRow.height = 0;
this.fixedRows.length = 0;
this.version++;
this.version = ++AtlasPage.nextVersion;
}
}
+17
View File
@@ -28,6 +28,10 @@ import { addDisposableListener } from 'browser/Dom';
import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
const enum Constants {
MERGE_RETRY_LIMIT = 32
}
export class WebglRenderer extends Disposable implements IRenderer {
private _renderLayers: IRenderLayer[];
private _cursorBlinkStateManager: MutableDisposable<CursorBlinkStateManager> = this._register(new MutableDisposable());
@@ -375,6 +379,19 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._updateModel(start, end);
}
// A mid-update atlas page merge invalidates vertex data and may not bump the host
// page's version, so re-run the update and force a full texture rebind.
let merged = false;
let mergeRetries = 0;
while (this._charAtlas && this._glyphRenderer.value.beginFrame() && mergeRetries++ < Constants.MERGE_RETRY_LIMIT) {
merged = true;
this._clearModel(true);
this._updateModel(0, this._terminal.rows - 1);
}
if (merged) {
this._glyphRenderer.value.invalidateAtlasTextures();
}
// Render
this._rectangleRenderer.value.renderBackgrounds();
this._glyphRenderer.value.render(this._model);
-196
View File
@@ -1,196 +0,0 @@
from termios import tcgetattr, tcsetattr, TCSADRAIN, TIOCGWINSZ, TCSAFLUSH
from tty import setcbreak, setraw
import os
import sys
from contextlib import contextmanager
from select import select
from time import sleep
from json import dumps, loads
from typing import Optional, Tuple, Union
class TerminalContext:
def __init__(self, fd: int, close_fd=False) -> None:
if not os.isatty(fd):
raise TypeError('fd is not a terminal')
self.close_fd = close_fd
self.fd = fd
self.is_cbreak = False
self.is_raw = False
self._initial_attr = self.termios_attributes
@classmethod
def from_cterm(cls):
fd = os.open(os.ctermid(), os.O_RDWR)
return TerminalContext(fd, True)
def close(self) -> None:
tcsetattr(self.fd, TCSADRAIN, self._initial_attr)
if self.close_fd:
os.close(self.fd)
@property
def termios_attributes(self) -> list:
return tcgetattr(self.fd)
@property
def ttyname(self) -> str:
return os.ttyname(self.fd)
@contextmanager
def cbreak_mode(self):
"""
Enter cbreak mode context.
"""
if self.is_cbreak:
yield
return
tattr = self.termios_attributes
try:
setcbreak(self.fd, TCSADRAIN)
self.is_cbreak = True
yield
finally:
tcsetattr(self.fd, TCSADRAIN, tattr)
self.is_cbreak = False
@contextmanager
def raw_mode(self):
"""
Enter cbreak mode context.
"""
if self.is_raw:
yield
return
tattr = self.termios_attributes
try:
setraw(self.fd, TCSADRAIN)
self.is_raw = True
yield
finally:
tcsetattr(self.fd, TCSADRAIN, tattr)
self.is_raw = False
@contextmanager
def custom_state(self, undo=None):
"""
Enter custom terminal state, that needs to to be undone by ``undo``.
Useful, if you want to apply a custom terminal state and
have to make sure, that it gets properly reset to previous state.
"""
try:
yield
finally:
if undo:
undo()
def write(self, data: Union[str, bytes]) -> None:
"""
Write string or bytes directly to the terminal.
"""
if isinstance(data, str):
data = data.encode('utf-8')
sent = os.write(self.fd, data)
while sent:
data = data[sent:]
sent = os.write(self.fd, data)
def read(self, amount: int = 1024, timeout: Optional[float] = None) -> bytes:
"""
Blocking read from the terminal.
If nothing was sent from the terminal within ``timeout``,
empty bytes are returned.
"""
can_read, _, _ = select([self.fd], [], [], timeout)
if can_read:
return os.read(self.fd, amount)
return b''
@contextmanager
def cterminal_context():
t = TerminalContext.from_cterm()
try:
yield t
finally:
t.close()
def extract_events(data: list[str]):
if len(data) < 5:
raise Exception('not enough reports')
types = set(data)
if len(types) == 1:
return {'PRESS': data[0], 'REPEAT': data[0], 'RELEASE': None}
if len(types) == 2:
last = data.pop()
if last != data[0] and len(set(data)) == 1:
return {'PRESS': data[0], 'REPEAT': data[0], 'RELEASE': last}
raise Exception('weird reports, 2 types')
if len(types) == 3:
first = data.pop(0)
last = data.pop()
if first != last and first != data[0] and last != data[0]:
return {'PRESS': first, 'REPEAT': data[0], 'RELEASE': last}
raise Exception('weird reports, 3 types')
raise Exception('more than 3 types')
def query(term: TerminalContext, mode: int):
with term.custom_state(undo=lambda:term.write('\x1b[<u')):
term.write(f'\x1b[>{mode}u')
term.read(timeout=.1)
print('PRESS (within 5s) and HOLD (for 5s)\r')
data: list[bytes] = []
cur = term.read(timeout=5)
while cur:
data.append(cur)
cur = term.read(timeout=.5)
if len(data) > 5:
print('RELEASE\r', end='')
try:
return extract_events([b.decode('utf-8') for b in data])
except Exception as e:
print('Error:', e, '\r')
print(data, '\r')
term.read(timeout=.1)
def save(filedata: dict[str, dict[str, str]], filename, entry, mode, events):
try:
filedata[entry][mode] = events
except KeyError:
filedata[entry] = {mode: events}
with open(filename, 'w') as f:
f.write(dumps(filedata, indent=2))
def main():
mode = 1
filedata = {}
print(sys.argv)
if len(sys.argv) != 3:
print('ERROR: not enough arguments')
print('Usage: python kitty_keytester.py <mode> <json-file>')
return
mode = int(sys.argv[1])
filename = sys.argv[2]
if os.path.exists(filename):
with open(filename) as f:
filedata = loads(f.read())
with cterminal_context() as term:
while True:
with term.raw_mode():
events = query(term, mode)
if events:
print(events)
entry = input('Entry: ')
if entry:
save(filedata, filename, entry, str(mode), events)
cont = input('Continue? (y)')
if cont not in ['y', '']:
break
if __name__ == '__main__':
main()
+1 -2
View File
@@ -521,8 +521,7 @@ function initAddons(term: Terminal): void {
} else if (name === 'webLinks') {
controlBar.setTabVisible('addon-web-links', true);
}
}
catch {
} catch {
addon.instance = undefined;
checkbox.checked = false;
checkbox.disabled = true;
@@ -30,7 +30,9 @@ export class AddonWebFontsWindow extends BaseWindow implements IControlWindow {
this._terminal.options.lineHeight = 1.3;
this._addons.fit.instance?.fit();
setTimeout(() => this._terminal.write('\x1b[?12h\x1b]12;#776CF9\x07\x1b[38;2;119;108;249;48;2;21;8;150m\x1b[2J\x1b[2;5H**** COMMODORE 64 BASIC V2 ****\r\n\r\n 64K RAM SYSTEM 38911 BASIC BYTES FREE\r\n\r\nREADY.\r\nLOAD '), 1000);
setTimeout(() => { this._terminal.write('🤣\x1b[m\x1b[99;1H'); this._terminal.input('\r'); }, 5000);
setTimeout(() => {
this._terminal.write('🤣\x1b[m\x1b[99;1H'); this._terminal.input('\r');
}, 5000);
});
ddKongtext.appendChild(btnKongtext);
dl.appendChild(ddKongtext);
+3 -1
View File
@@ -8,7 +8,9 @@ import type { IControlWindow } from '../controlBar';
import type { Terminal } from '@xterm/xterm';
export abstract class BaseWindow implements IControlWindow {
protected get _terminal(): Terminal { return this._terminalPrivate; }
protected get _terminal(): Terminal {
return this._terminalPrivate;
}
constructor(
private _terminalPrivate: Terminal,
@@ -252,6 +252,11 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
input.value = 'auto';
this._handlers.updateTerminalSize();
}
const screenElement = document.querySelector('.xterm-screen');
if (screenElement instanceof HTMLElement) {
screenElement.style.outline = this._autoResize ? ''
: 'solid thin red';
}
} else if (o === 'theme') {
value = this._getTheme();
}
+1
View File
@@ -128,6 +128,7 @@ export default tseslint.config(
'no-fallthrough': 'off',
'prefer-spread': 'off',
'object-curly-spacing': ['warn', 'always'],
'brace-style': ['warn', '1tbs', { allowSingleLine: false }],
'prefer-const': 'warn',
'spaced-comment': ['warn', 'always', { markers: ['/'], exceptions: ['-'] }]
}
@@ -1,373 +0,0 @@
{
"Escape +CapsLock": {
"1": {
"PRESS": "\u001b[27;65u",
"REPEAT": "\u001b[27;65u",
"RELEASE": null
}
},
"F1 +CapsLock": {
"1": {
"PRESS": "\u001b[1;65P",
"REPEAT": "\u001b[1;65P",
"RELEASE": null
}
},
"Insert +CapsLock": {
"1": {
"PRESS": "\u001b[2;65~",
"REPEAT": "\u001b[2;65~",
"RELEASE": null
}
},
"Delete +CapsLock": {
"1": {
"PRESS": "\u001b[3;65~",
"REPEAT": "\u001b[3;65~",
"RELEASE": null
}
},
"PageUp +CapsLock": {
"1": {
"PRESS": "\u001b[5;65~",
"REPEAT": "\u001b[5;65~",
"RELEASE": null
}
},
"Dead (Backquote) +CapsLock": {
"1": {
"PRESS": "^",
"REPEAT": "^",
"RELEASE": null
}
},
"1 (Digit1) +CapsLock": {
"1": {
"PRESS": "1",
"REPEAT": "1",
"RELEASE": null
}
},
"\u00df (Minus) +CapsLock": {
"1": {
"PRESS": "\u1e9e",
"REPEAT": "\u1e9e",
"RELEASE": null
}
},
"Dead (Equal) +CapsLock": {
"1": {
"PRESS": "\u00b4",
"REPEAT": "\u00b4",
"RELEASE": null
}
},
"Backspace +CapsLock": {
"1": {
"PRESS": "\u007f",
"REPEAT": "\u007f",
"RELEASE": null
}
},
"Tab +CapsLock": {
"1": {
"PRESS": "\t",
"REPEAT": "\t",
"RELEASE": null
}
},
"Q (KeyQ) +CapsLock": {
"1": {
"PRESS": "Q",
"REPEAT": "Q",
"RELEASE": null
}
},
"\u00dc (BracketLeft) +CapsLock": {
"1": {
"PRESS": "\u00dc",
"REPEAT": "\u00dc",
"RELEASE": null
}
},
"+ (BracketRight) +CapsLock": {
"1": {
"PRESS": "+",
"REPEAT": "+",
"RELEASE": null
}
},
"Enter +CapsLock": {
"1": {
"PRESS": "\r",
"REPEAT": "\r",
"RELEASE": null
}
},
"\u00d6 (Semicolon) +CapsLock": {
"1": {
"PRESS": "\u00d6",
"REPEAT": "\u00d6",
"RELEASE": null
}
},
"\u00c4 (Quote) +CapsLock": {
"1": {
"PRESS": "\u00c4",
"REPEAT": "\u00c4",
"RELEASE": null
}
},
"# (Bashslash) +CapsLock": {
"1": {
"PRESS": "#",
"REPEAT": "#",
"RELEASE": null
}
},
"< (IntlBackslash) +CapsLock": {
"1": {
"PRESS": "<",
"REPEAT": "<",
"RELEASE": null
}
},
", (Comma) +CapsLock": {
"1": {
"PRESS": ",",
"REPEAT": ",",
"RELEASE": null
}
},
". (Period) +CapsLock": {
"1": {
"PRESS": ".",
"REPEAT": ".",
"RELEASE": null
}
},
"- (Slash) +CapsLock": {
"1": {
"PRESS": "-",
"REPEAT": "-",
"RELEASE": null
}
},
"ArrowUp +CapsLock": {
"1": {
"PRESS": "\u001b[1;65A",
"REPEAT": "\u001b[1;65A",
"RELEASE": null
}
},
"PageDown +CapsLock": {
"1": {
"PRESS": "\u001b[6;65~",
"REPEAT": "\u001b[6;65~",
"RELEASE": null
}
},
"Home +CapsLock": {
"1": {
"PRESS": "\u001b[1;65H",
"REPEAT": "\u001b[1;65H",
"RELEASE": null
}
},
"End +CapsLock": {
"1": {
"PRESS": "\u001b[1;65F",
"REPEAT": "\u001b[1;65F",
"RELEASE": null
}
},
"+ (NumpadAdd) +CapsLock": {
"1": {
"PRESS": "+",
"REPEAT": "+",
"RELEASE": null
}
},
"Enter (NumpadEnter) +CapsLock": {
"1": {
"PRESS": "\u001b[57414;65u",
"REPEAT": "\u001b[57414;65u",
"RELEASE": null
}
},
"Insert (Numpad0) +CapsLock": {
"1": {
"PRESS": "\u001b[57425;65u",
"REPEAT": "\u001b[57425;65u",
"RELEASE": null
}
},
"\u0000 (NumpadDecimal) +CapsLock": {
"1": {
"PRESS": "\u001b[57426;65u",
"REPEAT": "\u001b[57426;65u",
"RELEASE": null
}
},
"Numlock +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"CapsLock +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Shift (ShiftLeft) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Shift (ShiftRight) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Control (ControlLeft) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Meta (MetaLeft) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Alt (AltLeft) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"AltGraph (AltRight) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Control (ControlRight) +CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"/ (NumpadDivide) +NumLock": {
"1": {
"PRESS": "/",
"REPEAT": "/",
"RELEASE": null
}
},
"* (NumpadMultiply) +NumLock": {
"1": {
"PRESS": "*",
"REPEAT": "*",
"RELEASE": null
}
},
"- (NumpadSubtract) +NumLock": {
"1": {
"PRESS": "-",
"REPEAT": "-",
"RELEASE": null
}
},
"0 (Numpad0) +NumLock": {
"1": {
"PRESS": "0",
"REPEAT": "0",
"RELEASE": null
}
},
"1 (Numpad1) +NumLock": {
"1": {
"PRESS": "1",
"REPEAT": "1",
"RELEASE": null
}
},
"2 (Numpad2) +NumLock": {
"1": {
"PRESS": "2",
"REPEAT": "2",
"RELEASE": null
}
},
"3 (Numpad3) +NumLock": {
"1": {
"PRESS": "3",
"REPEAT": "3",
"RELEASE": null
}
},
"4 (Numpad4) +NumLock": {
"1": {
"PRESS": "4",
"REPEAT": "4",
"RELEASE": null
}
},
"5 (Numpad5) +NumLock": {
"1": {
"PRESS": "5",
"REPEAT": "5",
"RELEASE": null
}
},
"6 (Numpad6) +NumLock": {
"1": {
"PRESS": "6",
"REPEAT": "6",
"RELEASE": null
}
},
"7 (Numpad7) +NumLock": {
"1": {
"PRESS": "7",
"REPEAT": "7",
"RELEASE": null
}
},
"8 (Numpad8) +NumLock": {
"1": {
"PRESS": "8",
"REPEAT": "8",
"RELEASE": null
}
},
"9 (Numpad9) +NumLock": {
"1": {
"PRESS": "9",
"REPEAT": "9",
"RELEASE": null
}
},
", (NumpadDecimal) +NumLock": {
"1": {
"PRESS": ",",
"REPEAT": ",",
"RELEASE": null
}
}
}
@@ -1,702 +0,0 @@
{
"Escape": {
"1": {
"PRESS": "\u001b[27u",
"REPEAT": "\u001b[27u",
"RELEASE": null
}
},
"F1": {
"1": {
"PRESS": "\u001b[P",
"REPEAT": "\u001b[P",
"RELEASE": null
}
},
"F2": {
"1": {
"PRESS": "\u001b[Q",
"REPEAT": "\u001b[Q",
"RELEASE": null
}
},
"F3": {
"1": {
"PRESS": "\u001b[13~",
"REPEAT": "\u001b[13~",
"RELEASE": null
}
},
"F4": {
"1": {
"PRESS": "\u001b[S",
"REPEAT": "\u001b[S",
"RELEASE": null
}
},
"F5": {
"1": {
"PRESS": "\u001b[15~",
"REPEAT": "\u001b[15~",
"RELEASE": null
}
},
"F6": {
"1": {
"PRESS": "\u001b[17~",
"REPEAT": "\u001b[17~",
"RELEASE": null
}
},
"F7": {
"1": {
"PRESS": "\u001b[18~",
"REPEAT": "\u001b[18~",
"RELEASE": null
}
},
"F8": {
"1": {
"PRESS": "\u001b[19~",
"REPEAT": "\u001b[19~",
"RELEASE": null
}
},
"F9": {
"1": {
"PRESS": "\u001b[20~",
"REPEAT": "\u001b[20~",
"RELEASE": null
}
},
"F10": {
"1": {
"PRESS": "\u001b[21~",
"REPEAT": "\u001b[21~",
"RELEASE": null
}
},
"F11": {
"1": {
"PRESS": "\u001b[23~",
"REPEAT": "\u001b[23~",
"RELEASE": null
}
},
"F12": {
"1": {
"PRESS": "\u001b[24~",
"REPEAT": "\u001b[24~",
"RELEASE": null
}
},
"Insert": {
"1": {
"PRESS": "\u001b[2~",
"REPEAT": "\u001b[2~",
"RELEASE": null
}
},
"Delete": {
"1": {
"PRESS": "\u001b[3~",
"REPEAT": "\u001b[3~",
"RELEASE": null
}
},
"PageUp": {
"1": {
"PRESS": "\u001b[5~",
"REPEAT": "\u001b[5~",
"RELEASE": null
}
},
"PageDown": {
"1": {
"PRESS": "\u001b[6~",
"REPEAT": "\u001b[6~",
"RELEASE": null
}
},
"Home": {
"1": {
"PRESS": "\u001b[H",
"REPEAT": "\u001b[H",
"RELEASE": null
}
},
"End": {
"1": {
"PRESS": "\u001b[F",
"REPEAT": "\u001b[F",
"RELEASE": null
}
},
"Dead (Backquote)": {
"1": {
"PRESS": "^",
"REPEAT": "^",
"RELEASE": null
}
},
"1 (Digit1)": {
"1": {
"PRESS": "1",
"REPEAT": "1",
"RELEASE": null
}
},
"2 (Digit2)": {
"1": {
"PRESS": "2",
"REPEAT": "2",
"RELEASE": null
}
},
"3 (Digit3)": {
"1": {
"PRESS": "3",
"REPEAT": "3",
"RELEASE": null
}
},
"4 (Digit4)": {
"1": {
"PRESS": "4",
"REPEAT": "4",
"RELEASE": null
}
},
"5 (Digit5)": {
"1": {
"PRESS": "5",
"REPEAT": "5",
"RELEASE": null
}
},
"6 (Digit6)": {
"1": {
"PRESS": "6",
"REPEAT": "6",
"RELEASE": null
}
},
"7 (Digit7)": {
"1": {
"PRESS": "7",
"REPEAT": "7",
"RELEASE": null
}
},
"8 (Digit8)": {
"1": {
"PRESS": "8",
"REPEAT": "8",
"RELEASE": null
}
},
"9 (Digit9)": {
"1": {
"PRESS": "9",
"REPEAT": "9",
"RELEASE": null
}
},
"0 (Digit0)": {
"1": {
"PRESS": "0",
"REPEAT": "0",
"RELEASE": null
}
},
"\u00df (Minus)": {
"1": {
"PRESS": "\u00df",
"REPEAT": "\u00df",
"RELEASE": null
}
},
"Dead (Equal)": {
"1": {
"PRESS": "\u00b4",
"REPEAT": "\u00b4",
"RELEASE": null
}
},
"Backspace": {
"1": {
"PRESS": "\u007f",
"REPEAT": "\u007f",
"RELEASE": null
}
},
"Tab": {
"1": {
"PRESS": "\t",
"REPEAT": "\t",
"RELEASE": null
}
},
"q (KeyQ)": {
"1": {
"PRESS": "q",
"REPEAT": "q",
"RELEASE": null
}
},
"w (KeyW)": {
"1": {
"PRESS": "w",
"REPEAT": "w",
"RELEASE": null
}
},
"e (KeyE)": {
"1": {
"PRESS": "e",
"REPEAT": "e",
"RELEASE": null
}
},
"r (KeyR)": {
"1": {
"PRESS": "r",
"REPEAT": "r",
"RELEASE": null
}
},
"t (KeyT)": {
"1": {
"PRESS": "t",
"REPEAT": "t",
"RELEASE": null
}
},
"z (KeyY)": {
"1": {
"PRESS": "z",
"REPEAT": "z",
"RELEASE": null
}
},
"u (KeyU)": {
"1": {
"PRESS": "u",
"REPEAT": "u",
"RELEASE": null
}
},
"i (KeyI)": {
"1": {
"PRESS": "i",
"REPEAT": "i",
"RELEASE": null
}
},
"o (KeyO)": {
"1": {
"PRESS": "o",
"REPEAT": "o",
"RELEASE": null
}
},
"p (KeyP)": {
"1": {
"PRESS": "p",
"REPEAT": "p",
"RELEASE": null
}
},
"\u00fc (BracketLeft)": {
"1": {
"PRESS": "\u00fc",
"REPEAT": "\u00fc",
"RELEASE": null
}
},
"+ (BracketRight)": {
"1": {
"PRESS": "+",
"REPEAT": "+",
"RELEASE": null
}
},
"Enter": {
"1": {
"PRESS": "\r",
"REPEAT": "\r",
"RELEASE": null
}
},
"a (KeyA)": {
"1": {
"PRESS": "a",
"REPEAT": "a",
"RELEASE": null
}
},
"s (KeyS)": {
"1": {
"PRESS": "s",
"REPEAT": "s",
"RELEASE": null
}
},
"d (KeyD)": {
"1": {
"PRESS": "d",
"REPEAT": "d",
"RELEASE": null
}
},
"f (KeyF)": {
"1": {
"PRESS": "f",
"REPEAT": "f",
"RELEASE": null
}
},
"g (KeyG)": {
"1": {
"PRESS": "g",
"REPEAT": "g",
"RELEASE": null
}
},
"h (KeyH)": {
"1": {
"PRESS": "h",
"REPEAT": "h",
"RELEASE": null
}
},
"j (KeyJ)": {
"1": {
"PRESS": "j",
"REPEAT": "j",
"RELEASE": null
}
},
"k (KeyK)": {
"1": {
"PRESS": "k",
"REPEAT": "k",
"RELEASE": null
}
},
"l (KeyL)": {
"1": {
"PRESS": "l",
"REPEAT": "l",
"RELEASE": null
}
},
"\u00f6 (Semicolon)": {
"1": {
"PRESS": "\u00f6",
"REPEAT": "\u00f6",
"RELEASE": null
}
},
"\u00e4 (Quote)": {
"1": {
"PRESS": "\u00e4",
"REPEAT": "\u00e4",
"RELEASE": null
}
},
"# (Backslash)": {
"1": {
"PRESS": "#",
"REPEAT": "#",
"RELEASE": null
}
},
"< (IntlBackslash)": {
"1": {
"PRESS": "<",
"REPEAT": "<",
"RELEASE": null
}
},
"y (KeyZ)": {
"1": {
"PRESS": "y",
"REPEAT": "y",
"RELEASE": null
}
},
"x (KeyX)": {
"1": {
"PRESS": "x",
"REPEAT": "x",
"RELEASE": null
}
},
"c (KeyC)": {
"1": {
"PRESS": "c",
"REPEAT": "c",
"RELEASE": null
}
},
"v (KeyV)": {
"1": {
"PRESS": "v",
"REPEAT": "v",
"RELEASE": null
}
},
"b (KeyB)": {
"1": {
"PRESS": "b",
"REPEAT": "b",
"RELEASE": null
}
},
"n (KeyN)": {
"1": {
"PRESS": "n",
"REPEAT": "n",
"RELEASE": null
}
},
"m (KeyM)": {
"1": {
"PRESS": "m",
"REPEAT": "m",
"RELEASE": null
}
},
", (Comma)": {
"1": {
"PRESS": ",",
"REPEAT": ",",
"RELEASE": null
}
},
". (Period)": {
"1": {
"PRESS": ".",
"REPEAT": ".",
"RELEASE": null
}
},
"- (Slash)": {
"1": {
"PRESS": "-",
"REPEAT": "-",
"RELEASE": null
}
},
"ArrowLeft": {
"1": {
"PRESS": "\u001b[D",
"REPEAT": "\u001b[D",
"RELEASE": null
}
},
"ArrowUp": {
"1": {
"PRESS": "\u001b[A",
"REPEAT": "\u001b[A",
"RELEASE": null
}
},
"ArrowRight": {
"1": {
"PRESS": "\u001b[C",
"REPEAT": "\u001b[C",
"RELEASE": null
}
},
"ArrowDown": {
"1": {
"PRESS": "\u001b[B",
"REPEAT": "\u001b[B",
"RELEASE": null
}
},
"/ (NumpadDivide)": {
"1": {
"PRESS": "/",
"REPEAT": "/",
"RELEASE": null
}
},
"* (NumpadMultiply)": {
"1": {
"PRESS": "*",
"REPEAT": "*",
"RELEASE": null
}
},
"- (NumpadSubtract)": {
"1": {
"PRESS": "-",
"REPEAT": "-",
"RELEASE": null
}
},
"Home (Numpad7)": {
"1": {
"PRESS": "\u001b[57423u",
"REPEAT": "\u001b[57423u",
"RELEASE": null
}
},
"ArrowUp (Numpad8)": {
"1": {
"PRESS": "\u001b[57419u",
"REPEAT": "\u001b[57419u",
"RELEASE": null
}
},
"PageUp (Numpad9)": {
"1": {
"PRESS": "\u001b[57421u",
"REPEAT": "\u001b[57421u",
"RELEASE": null
}
},
"+ (NumpadAdd)": {
"1": {
"PRESS": "+",
"REPEAT": "+",
"RELEASE": null
}
},
"ArrowLeft (Numpad4)": {
"1": {
"PRESS": "\u001b[57417u",
"REPEAT": "\u001b[57417u",
"RELEASE": null
}
},
"Clear (Numpad5)": {
"1": {
"PRESS": "\u001b[E",
"REPEAT": "\u001b[E",
"RELEASE": null
}
},
"ArrowRight (Numpad6)": {
"1": {
"PRESS": "\u001b[57418u",
"REPEAT": "\u001b[57418u",
"RELEASE": null
}
},
"End (Numpad1)": {
"1": {
"PRESS": "\u001b[57424u",
"REPEAT": "\u001b[57424u",
"RELEASE": null
}
},
"ArrowDown (Numpad2)": {
"1": {
"PRESS": "\u001b[57420u",
"REPEAT": "\u001b[57420u",
"RELEASE": null
}
},
"PageDown (Numpad3)": {
"1": {
"PRESS": "\u001b[57422u",
"REPEAT": "\u001b[57422u",
"RELEASE": null
}
},
"Enter (NumpadEnter)": {
"1": {
"PRESS": "\u001b[57414u",
"REPEAT": "\u001b[57414u",
"RELEASE": null
}
},
"Insert (Numpad0)": {
"1": {
"PRESS": "\u001b[57425u",
"REPEAT": "\u001b[57425u",
"RELEASE": null
}
},
"\u0000 (NumpadDecimal)": {
"1": {
"PRESS": "\u001b[57426u",
"REPEAT": "\u001b[57426u",
"RELEASE": null
}
},
"Numlock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"CapsLock": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Shift (ShiftLeft)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Shift (ShiftRight)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Control (ControlLeft)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Meta (MetaLeft)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Alt (AltLeft)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
" (Space)": {
"1": {
"PRESS": " ",
"REPEAT": " ",
"RELEASE": null
}
},
"AltGraph (AltRight)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Control (ControlRight)": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
}
}
@@ -1,331 +0,0 @@
{
"Escape +Shift": {
"1": {
"PRESS": "\u001b[27;2u",
"REPEAT": "\u001b[27;2u",
"RELEASE": null
}
},
"F1 +Shift": {
"1": {
"PRESS": "\u001b[1;2P",
"REPEAT": "\u001b[1;2P",
"RELEASE": null
}
},
"Delete +Shift": {
"1": {
"PRESS": "\u001b[3;2~",
"REPEAT": "\u001b[3;2~",
"RELEASE": null
}
},
"PageUp +Shift": {
"1": {
"PRESS": "\u001b[5;2~",
"REPEAT": "\u001b[5;2~",
"RELEASE": null
}
},
"Dead (Backquote) +Shift": {
"1": {
"PRESS": "\u00b0",
"REPEAT": "\u00b0",
"RELEASE": null
}
},
"! (Digit1) +Shift": {
"1": {
"PRESS": "!",
"REPEAT": "!",
"RELEASE": null
}
},
"\" (Digit2) +Shift": {
"1": {
"PRESS": "\"",
"REPEAT": "\"",
"RELEASE": null
}
},
"\u00a7 (Digit3) +Shift": {
"1": {
"PRESS": "\u00a7",
"REPEAT": "\u00a7",
"RELEASE": null
}
},
"$ (Digit4) +Shifft": {
"1": {
"PRESS": "$",
"REPEAT": "$",
"RELEASE": null
}
},
"% (Digit5) +Shift": {
"1": {
"PRESS": "%",
"REPEAT": "%",
"RELEASE": null
}
},
"& (Digit6) +Shift": {
"1": {
"PRESS": "&",
"REPEAT": "&",
"RELEASE": null
}
},
"/ (Digit7) +Shift": {
"1": {
"PRESS": "/",
"REPEAT": "/",
"RELEASE": null
}
},
"( (Digit8) +Shift": {
"1": {
"PRESS": "(",
"REPEAT": "(",
"RELEASE": null
}
},
") (Digit9) +Shift": {
"1": {
"PRESS": ")",
"REPEAT": ")",
"RELEASE": null
}
},
"= (Digit0) +Shift": {
"1": {
"PRESS": "=",
"REPEAT": "=",
"RELEASE": null
}
},
"? (Minus) +Shift": {
"1": {
"PRESS": "?",
"REPEAT": "?",
"RELEASE": null
}
},
"Backspace +Shift": {
"1": {
"PRESS": "\u001b[127;2u",
"REPEAT": "\u001b[127;2u",
"RELEASE": null
}
},
"Tab +Shift": {
"1": {
"PRESS": "\u001b[9;2u",
"REPEAT": "\u001b[9;2u",
"RELEASE": null
}
},
"Q (KeyQ) +Shift": {
"1": {
"PRESS": "Q",
"REPEAT": "Q",
"RELEASE": null
}
},
"\u00dc (BracketLeft) +Shift": {
"1": {
"PRESS": "\u00dc",
"REPEAT": "\u00dc",
"RELEASE": null
}
},
"* (BracketRight) +Shift": {
"1": {
"PRESS": "*",
"REPEAT": "*",
"RELEASE": null
}
},
"Enter +Shift": {
"1": {
"PRESS": "\u001b[13;2u",
"REPEAT": "\u001b[13;2u",
"RELEASE": null
}
},
"\u00d6 (Semicolon) +Shift": {
"1": {
"PRESS": "\u00d6",
"REPEAT": "\u00d6",
"RELEASE": null
}
},
"\u00c4 (Quote) +Shift": {
"1": {
"PRESS": "\u00c4",
"REPEAT": "\u00c4",
"RELEASE": null
}
},
"' (Backslash) +Shift": {
"1": {
"PRESS": "'",
"REPEAT": "'",
"RELEASE": null
}
},
"> (IntlBackslash) +Shift": {
"1": {
"PRESS": ">",
"REPEAT": ">",
"RELEASE": null
}
},
"; (Comma) +Shift": {
"1": {
"PRESS": ";",
"REPEAT": ";",
"RELEASE": null
}
},
": (Period) +Shift": {
"1": {
"PRESS": ":",
"REPEAT": ":",
"RELEASE": null
}
},
"_ (Slash) +Shift": {
"1": {
"PRESS": "_",
"REPEAT": "_",
"RELEASE": null
}
},
"ArrowUp +Shift": {
"1": {
"PRESS": "\u001b[1;2A",
"REPEAT": "\u001b[1;2A",
"RELEASE": null
}
},
"PageDown +Shift": {
"1": {
"PRESS": "\u001b[6;2~",
"REPEAT": "\u001b[6;2~",
"RELEASE": null
}
},
"Home +Shift": {
"1": {
"PRESS": "\u001b[1;2H",
"REPEAT": "\u001b[1;2H",
"RELEASE": null
}
},
"Home (Numpad7) +Shift": {
"1": {
"PRESS": "\u001b[57423;2u",
"REPEAT": "\u001b[57423;2u",
"RELEASE": null
}
},
"ArrowUp (Numapd8) +Shift": {
"1": {
"PRESS": "\u001b[57419;2u",
"REPEAT": "\u001b[57419;2u",
"RELEASE": null
}
},
"Clear (Numpad5) +Shift": {
"1": {
"PRESS": "\u001b[1;2E",
"REPEAT": "\u001b[1;2E",
"RELEASE": null
}
},
"Enter (NumpadEnter) +Shift": {
"1": {
"PRESS": "\u001b[57414;2u",
"REPEAT": "\u001b[57414;2u",
"RELEASE": null
}
},
"Insert (Numpad0) +Shift": {
"1": {
"PRESS": "\u001b[57425;2u",
"REPEAT": "\u001b[57425;2u",
"RELEASE": null
}
},
"\u0000 (NumpadDecimal) +Shift": {
"1": {
"PRESS": "\u001b[57426;2u",
"REPEAT": "\u001b[57426;2u",
"RELEASE": null
}
},
"Numlock +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"CapsLock +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Shift (ShiftRight) +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Control (ControlLeft) +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Meta (MetaLeft) +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Alt (AltLeft) +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
" (Space) +Shift": {
"1": {
"PRESS": " ",
"REPEAT": " ",
"RELEASE": null
}
},
"AltGraph (AltRight) +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
},
"Control (ControlRight) +Shift": {
"1": {
"PRESS": null,
"REPEAT": null,
"RELEASE": null
}
}
}
-698
View File
@@ -16,15 +16,11 @@
"@playwright/test": "^1.57.0",
"@stylistic/eslint-plugin": "^4.4.1",
"@types/chai": "^4.2.22",
"@types/debug": "^4.1.7",
"@types/deep-equal": "^1.0.1",
"@types/express": "4",
"@types/express-ws": "^3.0.1",
"@types/jsdom": "^27.0.0",
"@types/mocha": "^9.0.0",
"@types/node": "^22.19.3",
"@types/trusted-types": "^1.0.6",
"@types/utf8": "^3.0.0",
"@types/webpack": "^5.28.0",
"@types/ws": "^8.2.0",
"@typescript-eslint/eslint-plugin": "^8.50.1",
@@ -32,8 +28,6 @@
"@typescript/native-preview": "^7.0.0-dev.20260213.1",
"chai": "^4.3.4",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"deep-equal": "^2.0.5",
"esbuild": "~0.25.2",
"eslint": "^9.39.2",
"eslint-plugin-jsdoc": "^50.8.0",
@@ -49,7 +43,6 @@
"ts-loader": "^9.3.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.1",
"utf8": "^3.0.0",
"webpack": "^5.61.0",
"webpack-cli": "^4.9.1",
"ws": "^8.2.3",
@@ -242,7 +235,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -556,7 +548,6 @@
"url": "https://opencollective.com/csstools"
}
],
"peer": true,
"engines": {
"node": ">=18"
},
@@ -598,7 +589,6 @@
"url": "https://opencollective.com/csstools"
}
],
"peer": true,
"engines": {
"node": ">=18"
}
@@ -1525,21 +1515,6 @@
"@types/node": "*"
}
},
"node_modules/@types/debug": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
"dev": true,
"dependencies": {
"@types/ms": "*"
}
},
"node_modules/@types/deep-equal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/deep-equal/-/deep-equal-1.0.4.tgz",
"integrity": "sha512-tqdiS4otQP4KmY0PR3u6KbZ5EWvhNdUoS/jc93UuK23C220lOZ/9TvjfxdPcKvqwwDVtmtSCrnr0p/2dirAxkA==",
"dev": true
},
"node_modules/@types/eslint": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@@ -1652,12 +1627,6 @@
"integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==",
"dev": true
},
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
"dev": true
},
"node_modules/@types/node": {
"version": "22.19.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz",
@@ -1731,18 +1700,6 @@
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
"dev": true
},
"node_modules/@types/trusted-types": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz",
"integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==",
"dev": true
},
"node_modules/@types/utf8": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/utf8/-/utf8-3.0.3.tgz",
"integrity": "sha512-+lqLGxWZsEe4Z6OrzBI7Ym4SMUTaMS5yOrHZ0/IL0bpIye1Qbs4PpobJL2mLDbftUXlPFZR7fu6d1yM+bHLX1w==",
"dev": true
},
"node_modules/@types/webpack": {
"version": "5.28.5",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.5.tgz",
@@ -1796,7 +1753,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.1.tgz",
"integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==",
"dev": true,
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.50.1",
"@typescript-eslint/types": "8.50.1",
@@ -2362,7 +2318,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2569,22 +2524,6 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.3",
"is-array-buffer": "^3.0.5"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -2606,21 +2545,6 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"dev": true,
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz",
@@ -2754,7 +2678,6 @@
"url": "https://github.com/sponsors/ai"
}
],
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -2808,24 +2731,6 @@
"node": ">=8"
}
},
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"dev": true,
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -3264,24 +3169,6 @@
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"dev": true
},
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.1"
},
"bin": {
"cross-env": "src/bin/cross-env.js",
"cross-env-shell": "src/bin/cross-env-shell.js"
},
"engines": {
"node": ">=10.14",
"npm": ">=6",
"yarn": ">=1"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -3380,38 +3267,6 @@
"node": ">=6"
}
},
"node_modules/deep-equal": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
"integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
"dev": true,
"dependencies": {
"array-buffer-byte-length": "^1.0.0",
"call-bind": "^1.0.5",
"es-get-iterator": "^1.1.3",
"get-intrinsic": "^1.2.2",
"is-arguments": "^1.1.1",
"is-array-buffer": "^3.0.2",
"is-date-object": "^1.0.5",
"is-regex": "^1.1.4",
"is-shared-array-buffer": "^1.0.2",
"isarray": "^2.0.5",
"object-is": "^1.1.5",
"object-keys": "^1.1.1",
"object.assign": "^4.1.4",
"regexp.prototype.flags": "^1.5.1",
"side-channel": "^1.0.4",
"which-boxed-primitive": "^1.0.2",
"which-collection": "^1.0.1",
"which-typed-array": "^1.1.13"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -3445,40 +3300,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"dev": true,
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -3612,26 +3433,6 @@
"node": ">= 0.4"
}
},
"node_modules/es-get-iterator": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
"integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.3",
"has-symbols": "^1.0.3",
"is-arguments": "^1.1.1",
"is-map": "^2.0.2",
"is-set": "^2.0.2",
"is-string": "^1.0.7",
"isarray": "^2.0.5",
"stop-iteration-iterator": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es-module-lexer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
@@ -3750,7 +3551,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -4290,21 +4090,6 @@
"node": ">8.0.0"
}
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"dev": true,
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -4429,15 +4214,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -4602,18 +4378,6 @@
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
},
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
"integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -4623,18 +4387,6 @@
"node": ">=8"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -4854,20 +4606,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
"dev": true,
"dependencies": {
"es-errors": "^1.3.0",
"hasown": "^2.0.2",
"side-channel": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/interpret": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
@@ -4893,54 +4631,6 @@
"node": ">= 0.10"
}
},
"node_modules/is-arguments": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
"integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-bigint": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
"dev": true,
"dependencies": {
"has-bigints": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -4953,34 +4643,6 @@
"node": ">=8"
}
},
"node_modules/is-boolean-object": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
@@ -4996,22 +4658,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-date-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5042,18 +4688,6 @@
"node": ">=0.10.0"
}
},
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -5063,22 +4697,6 @@
"node": ">=0.12.0"
}
},
"node_modules/is-number-object": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
@@ -5106,51 +4724,6 @@
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
"dev": true
},
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.2",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-set": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-shared-array-buffer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -5163,39 +4736,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-string": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-symbol": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.2",
"has-symbols": "^1.1.0",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -5214,34 +4754,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakset": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -5251,12 +4763,6 @@
"node": ">=0.10.0"
}
},
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"dev": true
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -6206,51 +5712,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-is": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.assign": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0",
"has-symbols": "^1.1.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -6602,15 +6063,6 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -6760,26 +6212,6 @@
"node": ">= 0.10"
}
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-errors": "^1.3.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"set-function-name": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/release-zalgo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
@@ -6956,23 +6388,6 @@
}
]
},
"node_modules/safe-regex-test": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
"dev": true,
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-regex": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -7015,7 +6430,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -7132,38 +6546,6 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dev": true,
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-function-name": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
"dev": true,
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"functions-have-names": "^1.2.3",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -7428,19 +6810,6 @@
"node": ">= 0.8"
}
},
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
"integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
"dev": true,
"dependencies": {
"es-errors": "^1.3.0",
"internal-slot": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -7856,7 +7225,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7942,12 +7310,6 @@
"punycode": "^2.1.0"
}
},
"node_modules/utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
"integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==",
"dev": true
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -8023,7 +7385,6 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
"integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
"dev": true,
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",
@@ -8072,7 +7433,6 @@
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
"integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
"dev": true,
"peer": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.2.0",
@@ -8230,70 +7590,12 @@
"node": ">= 8"
}
},
"node_modules/which-boxed-primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
"dev": true,
"dependencies": {
"is-bigint": "^1.1.0",
"is-boolean-object": "^1.2.1",
"is-number-object": "^1.1.1",
"is-string": "^1.1.1",
"is-symbol": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
"dev": true,
"dependencies": {
"is-map": "^2.0.3",
"is-set": "^2.0.3",
"is-weakmap": "^2.0.2",
"is-weakset": "^2.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
"dev": true
},
"node_modules/which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"dev": true,
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wildcard": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
-8
View File
@@ -56,7 +56,6 @@
"test-unit": "node ./bin/test_unit.js",
"test-unit-slow-tests": "npm run test-unit | grep \"ms)\"",
"test-unit-coverage": "node ./bin/test_unit.js --coverage",
"test-unit-dev": "cross-env NODE_PATH='./out' mocha",
"test-integration": "node ./bin/test_integration.js --workers=75%",
"test-integration-chromium": "node ./bin/test_integration.js --workers=75% \"--project=Chromium\"",
"test-integration-firefox": "node ./bin/test_integration.js --workers=75% \"--project=FirefoxStable\"",
@@ -80,15 +79,11 @@
"@playwright/test": "^1.57.0",
"@stylistic/eslint-plugin": "^4.4.1",
"@types/chai": "^4.2.22",
"@types/debug": "^4.1.7",
"@types/deep-equal": "^1.0.1",
"@types/express": "4",
"@types/express-ws": "^3.0.1",
"@types/jsdom": "^27.0.0",
"@types/mocha": "^9.0.0",
"@types/node": "^22.19.3",
"@types/trusted-types": "^1.0.6",
"@types/utf8": "^3.0.0",
"@types/webpack": "^5.28.0",
"@types/ws": "^8.2.0",
"@typescript-eslint/eslint-plugin": "^8.50.1",
@@ -96,8 +91,6 @@
"@typescript/native-preview": "^7.0.0-dev.20260213.1",
"chai": "^4.3.4",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"deep-equal": "^2.0.5",
"esbuild": "~0.25.2",
"eslint": "^9.39.2",
"eslint-plugin-jsdoc": "^50.8.0",
@@ -113,7 +106,6 @@
"ts-loader": "^9.3.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.1",
"utf8": "^3.0.0",
"webpack": "^5.61.0",
"webpack-cli": "^4.9.1",
"ws": "^8.2.3",
+19 -8
View File
@@ -71,7 +71,9 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
private _compositionView: HTMLElement | undefined;
private readonly _linkifier: MutableDisposable<ILinkifier2> = this._register(new MutableDisposable());
public get linkifier(): ILinkifier2 | undefined { return this._linkifier.value; }
public get linkifier(): ILinkifier2 | undefined {
return this._linkifier.value;
}
private _overviewRulerRenderer: OverviewRulerRenderer | undefined;
private _viewport: Viewport | undefined;
@@ -136,15 +138,25 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
public readonly onBell = this._onBell.event;
private _onFocus = this._register(new Emitter<void>());
public get onFocus(): IEvent<void> { return this._onFocus.event; }
public get onFocus(): IEvent<void> {
return this._onFocus.event;
}
private _onBlur = this._register(new Emitter<void>());
public get onBlur(): IEvent<void> { return this._onBlur.event; }
public get onBlur(): IEvent<void> {
return this._onBlur.event;
}
private _onA11yCharEmitter = this._register(new Emitter<string>());
public get onA11yChar(): IEvent<string> { return this._onA11yCharEmitter.event; }
public get onA11yChar(): IEvent<string> {
return this._onA11yCharEmitter.event;
}
private _onA11yTabEmitter = this._register(new Emitter<number>());
public get onA11yTab(): IEvent<number> { return this._onA11yTabEmitter.event; }
public get onA11yTab(): IEvent<number> {
return this._onA11yTabEmitter.event;
}
private _onWillOpen = this._register(new Emitter<HTMLElement>());
public get onWillOpen(): IEvent<HTMLElement> { return this._onWillOpen.event; }
public get onWillOpen(): IEvent<HTMLElement> {
return this._onWillOpen.event;
}
private readonly _onDimensionsChange = this._register(new Emitter<IRenderDimensionsApi>());
public readonly onDimensionsChange = this._onDimensionsChange.event;
@@ -563,8 +575,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
try {
this._onWillOpen.fire(this.element);
}
catch { /* fails to load addon for some reason */ }
} catch { /* fails to load addon for some reason */ }
if (!this._renderService.hasRenderer()) {
this._renderService.setRenderer(this._createRenderer());
}
+3 -1
View File
@@ -12,7 +12,9 @@ import { Emitter } from 'common/Event';
import { addDisposableListener } from 'browser/Dom';
export class Linkifier extends Disposable implements ILinkifier2 {
public get currentLink(): ILinkWithState | undefined { return this._currentLink; }
public get currentLink(): ILinkWithState | undefined {
return this._currentLink;
}
protected _currentLink: ILinkWithState | undefined;
private _mouseDownLink: ILinkWithState | undefined;
private _lastMouseEvent: MouseEvent | undefined;
+15 -5
View File
@@ -21,9 +21,15 @@ import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
import { Emitter, type IEvent } from 'common/Event';
export class TestTerminal extends CoreBrowserTerminal {
public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; }
public keyDown(ev: any): boolean | undefined { return this._keyDown(ev); }
public keyPress(ev: any): boolean { return this._keyPress(ev); }
public get curAttrData(): IAttributeData {
return (this as any)._inputHandler._curAttrData;
}
public keyDown(ev: any): boolean | undefined {
return this._keyDown(ev);
}
public keyPress(ev: any): boolean {
return this._keyPress(ev);
}
public writeP(data: string | Uint8Array): Promise<void> {
return new Promise(r => this.write(data, r));
}
@@ -213,7 +219,9 @@ export class MockTerminal implements ITerminal {
public refresh(start: number, end: number): void {
throw new Error('Method not implemented.');
}
public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; }
public registerCharacterJoiner(handler: CharacterJoinerHandler): number {
return 0;
}
public deregisterCharacterJoiner(joinerId: number): void { }
}
@@ -377,7 +385,9 @@ export class MockCoreBrowserService implements ICoreBrowserService {
export class MockCharSizeService implements ICharSizeService {
public serviceBrand: undefined;
public get hasValidSize(): boolean { return this.width > 0 && this.height > 0; }
public get hasValidSize(): boolean {
return this.width > 0 && this.height > 0;
}
public onCharSizeChange: IEvent<void> = new Emitter<void>().event;
constructor(public width: number, public height: number) {}
public measure(): void {}
+3 -1
View File
@@ -23,7 +23,9 @@ export class CompositionHelper {
* IME. This variable determines whether the compositionText should be displayed on the UI.
*/
private _isComposing: boolean;
public get isComposing(): boolean { return this._isComposing; }
public get isComposing(): boolean {
return this._isComposing;
}
/**
* The position within the input textarea's value of the current composition.
+66 -22
View File
@@ -68,22 +68,52 @@ export class Terminal extends Disposable implements ITerminalApi {
}
}
public get onBell(): IEvent<void> { return this._core.onBell; }
public get onBinary(): IEvent<string> { return this._core.onBinary; }
public get onCursorMove(): IEvent<void> { return this._core.onCursorMove; }
public get onData(): IEvent<string> { return this._core.onData; }
public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> { return this._core.onKey; }
public get onLineFeed(): IEvent<void> { return this._core.onLineFeed; }
public get onRender(): IEvent<{ start: number, end: number }> { return this._core.onRender; }
public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; }
public get onScroll(): IEvent<number> { return this._core.onScroll; }
public get onSelectionChange(): IEvent<void> { return this._core.onSelectionChange; }
public get onTitleChange(): IEvent<string> { return this._core.onTitleChange; }
public get onWriteParsed(): IEvent<void> { return this._core.onWriteParsed; }
public get onDimensionsChange(): IEvent<IRenderDimensions> { return this._core.onDimensionsChange; }
public get onBell(): IEvent<void> {
return this._core.onBell;
}
public get onBinary(): IEvent<string> {
return this._core.onBinary;
}
public get onCursorMove(): IEvent<void> {
return this._core.onCursorMove;
}
public get onData(): IEvent<string> {
return this._core.onData;
}
public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> {
return this._core.onKey;
}
public get onLineFeed(): IEvent<void> {
return this._core.onLineFeed;
}
public get onRender(): IEvent<{ start: number, end: number }> {
return this._core.onRender;
}
public get onResize(): IEvent<{ cols: number, rows: number }> {
return this._core.onResize;
}
public get onScroll(): IEvent<number> {
return this._core.onScroll;
}
public get onSelectionChange(): IEvent<void> {
return this._core.onSelectionChange;
}
public get onTitleChange(): IEvent<string> {
return this._core.onTitleChange;
}
public get onWriteParsed(): IEvent<void> {
return this._core.onWriteParsed;
}
public get onDimensionsChange(): IEvent<IRenderDimensions> {
return this._core.onDimensionsChange;
}
public get element(): HTMLElement | undefined { return this._core.element; }
public get screenElement(): HTMLElement | undefined { return this._core.screenElement; }
public get element(): HTMLElement | undefined {
return this._core.element;
}
public get screenElement(): HTMLElement | undefined {
return this._core.screenElement;
}
public get parser(): IParser {
return this._parser ??= new ParserApi(this._core);
}
@@ -91,9 +121,15 @@ export class Terminal extends Disposable implements ITerminalApi {
this._checkProposedApi();
return new UnicodeApi(this._core);
}
public get textarea(): HTMLTextAreaElement | undefined { return this._core.textarea; }
public get rows(): number { return this._core.rows; }
public get cols(): number { return this._core.cols; }
public get textarea(): HTMLTextAreaElement | undefined {
return this._core.textarea;
}
public get rows(): number {
return this._core.rows;
}
public get cols(): number {
return this._core.cols;
}
public get buffer(): IBufferNamespaceApi {
return this._buffer ??= this._register(new BufferNamespaceApi(this._core));
}
@@ -247,10 +283,18 @@ export class Terminal extends Disposable implements ITerminalApi {
public static get strings(): ILocalizableStrings {
// A wrapper is required here because esbuild prevents setting an `export let`
return {
get promptLabel(): string { return Strings.promptLabel.get(); },
set promptLabel(value: string) { Strings.promptLabel.set(value); },
get tooMuchOutput(): string { return Strings.tooMuchOutput.get(); },
set tooMuchOutput(value: string) { Strings.tooMuchOutput.set(value); }
get promptLabel(): string {
return Strings.promptLabel.get();
},
set promptLabel(value: string) {
Strings.promptLabel.set(value);
},
get tooMuchOutput(): string {
return Strings.tooMuchOutput.get();
},
set tooMuchOutput(value: string) {
Strings.tooMuchOutput.set(value);
}
};
}
+3 -1
View File
@@ -15,7 +15,9 @@ export class CharSizeService extends Disposable implements ICharSizeService {
public height: number = 0;
private _measureStrategy: IMeasureStrategy;
public get hasValidSize(): boolean { return this.width > 0 && this.height > 0; }
public get hasValidSize(): boolean {
return this.width > 0 && this.height > 0;
}
private readonly _onCharSizeChange = this._register(new Emitter<void>());
public readonly onCharSizeChange = this._onCharSizeChange.event;
+3 -1
View File
@@ -52,7 +52,9 @@ export class RenderService extends Disposable implements IRenderService {
private readonly _onRefreshRequest = this._register(new Emitter<{ start: number, end: number }>());
public readonly onRefreshRequest = this._onRefreshRequest.event;
public get dimensions(): IRenderDimensions { return this._renderer.value!.dimensions; }
public get dimensions(): IRenderDimensions {
return this._renderer.value!.dimensions;
}
constructor(
private _rowCount: number,
+15 -5
View File
@@ -27,13 +27,23 @@ class TestSelectionService extends SelectionService {
super(null!, null!, null!, bufferService, new MockCoreService(), new MockMouseService(), optionsService, renderService, new MockCoreBrowserService());
}
public get model(): SelectionModel { return this._model; }
public get model(): SelectionModel {
return this._model;
}
public set selectionMode(mode: SelectionMode) { this._activeSelectionMode = mode; }
public set selectionMode(mode: SelectionMode) {
this._activeSelectionMode = mode;
}
public selectLineAt(line: number): void { this._selectLineAt(line); }
public selectWordAt(coords: [number, number]): void { this._selectWordAt(coords, true); }
public areCoordsInSelection(coords: [number, number], start: [number, number], end: [number, number]): boolean { return this._areCoordsInSelection(coords, start, end); }
public selectLineAt(line: number): void {
this._selectLineAt(line);
}
public selectWordAt(coords: [number, number]): void {
this._selectWordAt(coords, true);
}
public areCoordsInSelection(coords: [number, number], start: [number, number], end: [number, number]): boolean {
return this._areCoordsInSelection(coords, start, end);
}
// Disable DOM interaction
public enable(): void {}
+6 -2
View File
@@ -181,8 +181,12 @@ export class SelectionService extends Disposable implements ISelectionService {
this._enabled = true;
}
public get selectionStart(): [number, number] | undefined { return this._model.finalSelectionStart; }
public get selectionEnd(): [number, number] | undefined { return this._model.finalSelectionEnd; }
public get selectionStart(): [number, number] | undefined {
return this._model.finalSelectionStart;
}
public get selectionEnd(): [number, number] | undefined {
return this._model.finalSelectionEnd;
}
/**
* Gets whether there is an active text selection.
+3 -1
View File
@@ -38,7 +38,9 @@ export class ThemeService extends Disposable implements IThemeService {
private _halfContrastCache: IColorContrastCache = new ColorContrastCache();
private _restoreColors!: IRestoreColorSet;
public get colors(): ReadonlyColorSet { return this._colors; }
public get colors(): ReadonlyColorSet {
return this._colors;
}
private readonly _onChangeColors = this._register(new Emitter<ReadonlyColorSet>());
public readonly onChangeColors = this._onChangeColors.event;
+1 -2
View File
@@ -132,8 +132,7 @@ export namespace css {
$ctx.globalCompositeOperation = 'copy';
$litmusColor = $ctx.createLinearGradient(0, 0, 1, 1);
}
}
catch {
} catch {
// noop
}
+12 -4
View File
@@ -88,10 +88,18 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
return this._onScrollApi.event;
}
public get cols(): number { return this._bufferService.cols; }
public get rows(): number { return this._bufferService.rows; }
public get buffers(): IBufferSet { return this._bufferService.buffers; }
public get options(): Required<ITerminalOptions> { return this.optionsService.options; }
public get cols(): number {
return this._bufferService.cols;
}
public get rows(): number {
return this._bufferService.rows;
}
public get buffers(): IBufferSet {
return this._bufferService.buffers;
}
public get options(): Required<ITerminalOptions> {
return this.optionsService.options;
}
public set options(options: ITerminalOptions) {
for (const key in options) {
this.optionsService.options[key] = options[key];
+12 -4
View File
@@ -15,14 +15,18 @@ describe('Emitter', () => {
it('should fire with 1 listener', () => {
const emitter = new Emitter<number>();
let received: number | undefined;
emitter.event(e => { received = e; });
emitter.event(e => {
received = e;
});
emitter.fire(42);
assert.strictEqual(received, 42);
});
it('should fire with 1 listener using thisArgs', () => {
const emitter = new Emitter<number>();
const obj = { value: 0, handler(e: number) { this.value = e; } };
const obj = { value: 0, handler(e: number) {
this.value = e;
} };
emitter.event(obj.handler, obj);
emitter.fire(42);
assert.strictEqual(obj.value, 42);
@@ -54,7 +58,9 @@ describe('Emitter', () => {
it('should not fire after dispose', () => {
const emitter = new Emitter<number>();
let called = false;
emitter.event(() => { called = true; });
emitter.event(() => {
called = true;
});
emitter.dispose();
emitter.fire(42);
assert.strictEqual(called, false);
@@ -63,7 +69,9 @@ describe('Emitter', () => {
it('should allow disposing a listener', () => {
const emitter = new Emitter<number>();
let count = 0;
const disposable = emitter.event(() => { count++; });
const disposable = emitter.event(() => {
count++;
});
emitter.fire(1);
disposable.dispose();
emitter.fire(2);
+12 -4
View File
@@ -39,9 +39,15 @@ function getLines(bufferService: IBufferService, limit: number = bufferService.r
}
class TestInputHandler extends InputHandler {
public get curAttrData(): IAttributeData { return (this as any)._curAttrData; }
public get windowTitleStack(): string[] { return this._windowTitleStack; }
public get iconNameStack(): string[] { return this._iconNameStack; }
public get curAttrData(): IAttributeData {
return (this as any)._curAttrData;
}
public get windowTitleStack(): string[] {
return this._windowTitleStack;
}
public get iconNameStack(): string[] {
return this._iconNameStack;
}
/**
* Promise based parse call to await the full resolve of given input data.
@@ -2511,7 +2517,9 @@ describe('InputHandler', () => {
bufferService = new BufferService(optionsService, new MockLogService());
bufferService.resize(80, 30);
coreService = new CoreService(bufferService, new MockLogService(), optionsService);
coreService.onData(data => { console.log(data); });
coreService.onData(data => {
console.log(data);
});
inputHandler = new TestInputHandler(bufferService, new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockMouseStateService(), new MockUnicodeService());
});
+7 -4
View File
@@ -107,7 +107,9 @@ export class InputHandler extends Disposable implements IInputHandler {
protected _iconNameStack: string[] = [];
private _curAttrData: IAttributeData = DEFAULT_ATTR_DATA.clone();
public getAttrData(): IAttributeData { return this._curAttrData; }
public getAttrData(): IAttributeData {
return this._curAttrData;
}
private _eraseAttrDataInternal: IAttributeData = DEFAULT_ATTR_DATA.clone();
private _activeBuffer: IBuffer;
@@ -283,7 +285,9 @@ export class InputHandler extends Disposable implements IInputHandler {
* OSC handler
*/
// 0 - icon name + title
this._parser.registerOscHandler(0, new OscHandler(data => { this.setTitle(data); this.setIconName(data); return true; }));
this._parser.registerOscHandler(0, new OscHandler(data => {
this.setTitle(data); this.setIconName(data); return true;
}));
// 1 - icon name
this._parser.registerOscHandler(1, new OscHandler(data => this.setIconName(data)));
// 2 - title
@@ -1268,8 +1272,7 @@ export class InputHandler extends Disposable implements IInputHandler {
for (; j >= 0; j--) {
this._bufferService.scroll(this._eraseAttrData());
}
}
else {
} else {
j = this._bufferService.rows;
this._dirtyRowTracker.markDirty(j - 1);
while (j--) {
+18 -6
View File
@@ -30,7 +30,9 @@ export const NULL_CELL_DATA = Object.freeze(createCellData(DEFAULT_ATTR, NULL_CE
export class MockBufferService implements IBufferService {
public serviceBrand: any;
public get buffer(): IBuffer { return this.buffers.active; }
public get buffer(): IBuffer {
return this.buffers.active;
}
public buffers: IBufferSet = {} as any;
public onResize: IEvent<IBufferResizeEvent> = new Emitter<IBufferResizeEvent>().event;
public onScroll: IEvent<number> = new Emitter<number>().event;
@@ -83,10 +85,16 @@ export class MockMouseStateService implements IMouseStateService {
public addProtocol(name: string): void { }
public reset(): void { }
public onProtocolChange: IEvent<CoreMouseEventType> = new Emitter<CoreMouseEventType>().event;
public restrictMouseEvent(event: ICoreMouseEvent): boolean { return true; }
public encodeMouseEvent(event: ICoreMouseEvent): string { return ''; }
public restrictMouseEvent(event: ICoreMouseEvent): boolean {
return true;
}
public encodeMouseEvent(event: ICoreMouseEvent): string {
return '';
}
public setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void { }
public allowCustomWheelEvent(ev: WheelEvent): boolean { return true; }
public allowCustomWheelEvent(ev: WheelEvent): boolean {
return true;
}
}
export class MockCharsetService implements ICharsetService {
@@ -233,10 +241,14 @@ export class MockUnicodeService implements IUnicodeService {
export class MockDecorationService implements IDecorationService {
public serviceBrand: any;
public get decorations(): IterableIterator<IInternalDecoration> { return [].values(); }
public get decorations(): IterableIterator<IInternalDecoration> {
return [].values();
}
public onDecorationRegistered = new Emitter<IInternalDecoration>().event;
public onDecorationRemoved = new Emitter<IInternalDecoration>().event;
public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined { return undefined; }
public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined {
return undefined;
}
public reset(): void { }
public forEachDecorationAtCell(x: number, line: number, layer: 'bottom' | 'top' | undefined, callback: (decoration: IInternalDecoration) => void): void { }
public dispose(): void { }
+57 -19
View File
@@ -33,32 +33,68 @@ export class AttributeData implements IAttributeData {
public extended: IExtendedAttrs = new ExtendedAttrs();
// flags
public isInverse(): number { return this.fg & FgFlags.INVERSE; }
public isBold(): number { return this.fg & FgFlags.BOLD; }
public isInverse(): number {
return this.fg & FgFlags.INVERSE;
}
public isBold(): number {
return this.fg & FgFlags.BOLD;
}
public isUnderline(): number {
if (this.hasExtendedAttrs() && this.extended.underlineStyle !== UnderlineStyle.NONE) {
return 1;
}
return this.fg & FgFlags.UNDERLINE;
}
public isBlink(): number { return this.fg & FgFlags.BLINK; }
public isInvisible(): number { return this.fg & FgFlags.INVISIBLE; }
public isItalic(): number { return this.bg & BgFlags.ITALIC; }
public isDim(): number { return this.bg & BgFlags.DIM; }
public isStrikethrough(): number { return this.fg & FgFlags.STRIKETHROUGH; }
public isProtected(): number { return this.bg & BgFlags.PROTECTED; }
public isOverline(): number { return this.bg & BgFlags.OVERLINE; }
public isBlink(): number {
return this.fg & FgFlags.BLINK;
}
public isInvisible(): number {
return this.fg & FgFlags.INVISIBLE;
}
public isItalic(): number {
return this.bg & BgFlags.ITALIC;
}
public isDim(): number {
return this.bg & BgFlags.DIM;
}
public isStrikethrough(): number {
return this.fg & FgFlags.STRIKETHROUGH;
}
public isProtected(): number {
return this.bg & BgFlags.PROTECTED;
}
public isOverline(): number {
return this.bg & BgFlags.OVERLINE;
}
// color modes
public getFgColorMode(): number { return this.fg & Attributes.CM_MASK; }
public getBgColorMode(): number { return this.bg & Attributes.CM_MASK; }
public isFgRGB(): boolean { return (this.fg & Attributes.CM_MASK) === Attributes.CM_RGB; }
public isBgRGB(): boolean { return (this.bg & Attributes.CM_MASK) === Attributes.CM_RGB; }
public isFgPalette(): boolean { return (this.fg & Attributes.CM_MASK) === Attributes.CM_P16 || (this.fg & Attributes.CM_MASK) === Attributes.CM_P256; }
public isBgPalette(): boolean { return (this.bg & Attributes.CM_MASK) === Attributes.CM_P16 || (this.bg & Attributes.CM_MASK) === Attributes.CM_P256; }
public isFgDefault(): boolean { return (this.fg & Attributes.CM_MASK) === 0; }
public isBgDefault(): boolean { return (this.bg & Attributes.CM_MASK) === 0; }
public isAttributeDefault(): boolean { return this.fg === 0 && this.bg === 0; }
public getFgColorMode(): number {
return this.fg & Attributes.CM_MASK;
}
public getBgColorMode(): number {
return this.bg & Attributes.CM_MASK;
}
public isFgRGB(): boolean {
return (this.fg & Attributes.CM_MASK) === Attributes.CM_RGB;
}
public isBgRGB(): boolean {
return (this.bg & Attributes.CM_MASK) === Attributes.CM_RGB;
}
public isFgPalette(): boolean {
return (this.fg & Attributes.CM_MASK) === Attributes.CM_P16 || (this.fg & Attributes.CM_MASK) === Attributes.CM_P256;
}
public isBgPalette(): boolean {
return (this.bg & Attributes.CM_MASK) === Attributes.CM_P16 || (this.bg & Attributes.CM_MASK) === Attributes.CM_P256;
}
public isFgDefault(): boolean {
return (this.fg & Attributes.CM_MASK) === 0;
}
public isBgDefault(): boolean {
return (this.bg & Attributes.CM_MASK) === 0;
}
public isAttributeDefault(): boolean {
return this.fg === 0 && this.bg === 0;
}
// colors
public getFgColor(): number {
@@ -147,7 +183,9 @@ export class ExtendedAttrs implements IExtendedAttrs {
}
return this._ext;
}
public set ext(value: number) { this._ext = value; }
public set ext(value: number) {
this._ext = value;
}
public get underlineStyle(): UnderlineStyle {
// Always return the URL style if it has one
+4 -8
View File
@@ -62,8 +62,7 @@ export class CellData extends AttributeData implements ICellData {
// surrogates and combined strings need special treatment
if (value[CHAR_DATA_CHAR_INDEX].length > 2) {
combined = true;
}
else if (value[CHAR_DATA_CHAR_INDEX].length === 2) {
} else if (value[CHAR_DATA_CHAR_INDEX].length === 2) {
const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0);
// if the 2-char string is a surrogate create single codepoint
// everything else is combined
@@ -71,16 +70,13 @@ export class CellData extends AttributeData implements ICellData {
const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1);
if (0xDC00 <= second && second <= 0xDFFF) {
this.content = ((code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
}
else {
} else {
combined = true;
}
}
else {
} else {
combined = true;
}
}
else {
} else {
this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
}
if (combined) {
+3 -1
View File
@@ -14,7 +14,9 @@ export class Marker implements IMarker {
private readonly _disposables: IDisposable[] = [];
private readonly _id: number = Marker._nextId++;
public get id(): number { return this._id; }
public get id(): number {
return this._id;
}
private readonly _onDispose = this.register(new Emitter<void>());
public readonly onDispose = this._onDispose.event;
+3 -6
View File
@@ -58,22 +58,19 @@ export function evaluateKeyboardEvent(
} else {
result.key = C0.ESC + '[A';
}
}
else if (ev.key === 'UIKeyInputLeftArrow') {
} else if (ev.key === 'UIKeyInputLeftArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OD';
} else {
result.key = C0.ESC + '[D';
}
}
else if (ev.key === 'UIKeyInputRightArrow') {
} else if (ev.key === 'UIKeyInputRightArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OC';
} else {
result.key = C0.ESC + '[C';
}
}
else if (ev.key === 'UIKeyInputDownArrow') {
} else if (ev.key === 'UIKeyInputDownArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OB';
} else {
+33 -5
View File
@@ -5,7 +5,6 @@
import { assert } from 'chai';
import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32, utf32ToString } from 'common/input/TextDecoder';
import { encode } from 'utf8';
// convert UTF32 codepoints to string
@@ -29,6 +28,35 @@ function fromByteString(s: string): Uint8Array {
return result;
}
function stringToUtf8Bytes(s: string): Uint8Array {
const bytes: number[] = [];
for (let i = 0; i < s.length; i++) {
let cp = s.charCodeAt(i);
if (cp >= 0xD800 && cp <= 0xDBFF && i + 1 < s.length) {
const next = s.charCodeAt(i + 1);
if (next >= 0xDC00 && next <= 0xDFFF) {
cp = 0x10000 + ((cp - 0xD800) << 10) + (next - 0xDC00);
i++;
}
}
if (cp < 0x80) {
bytes.push(cp);
} else if (cp < 0x800) {
bytes.push(0xC0 | (cp >> 6), 0x80 | (cp & 0x3F));
} else if (cp < 0x10000) {
bytes.push(0xE0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3F), 0x80 | (cp & 0x3F));
} else {
bytes.push(
0xF0 | (cp >> 18),
0x80 | ((cp >> 12) & 0x3F),
0x80 | ((cp >> 6) & 0x3F),
0x80 | (cp & 0x3F)
);
}
}
return new Uint8Array(bytes);
}
function assertDecodedRange(
min: number,
max: number,
@@ -172,7 +200,7 @@ describe('text encodings', () => {
max,
(i) => (i >= 0xD800 && i <= 0xDFFF) || i === 0xFEFF,
(i) => String.fromCharCode(i),
(input, target) => decoder.decode(fromByteString(encode(input)), target),
(input, target) => decoder.decode(stringToUtf8Bytes(input), target),
(data, length) => toString(data, length)
);
});
@@ -187,7 +215,7 @@ describe('text encodings', () => {
max,
() => false,
(i) => stringFromCodePoint(i),
(input, target) => decoder.decode(fromByteString(encode(input)), target),
(input, target) => decoder.decode(stringToUtf8Bytes(input), target),
(data, length) => toString(data, length)
);
});
@@ -196,7 +224,7 @@ describe('text encodings', () => {
it('0xFEFF(BOM)', () => {
const decoder = new Utf8ToUtf32();
const target = new Uint32Array(5);
const utf8Data = fromByteString(encode(String.fromCharCode(0xFEFF)));
const utf8Data = stringToUtf8Bytes(String.fromCharCode(0xFEFF));
const length = decoder.decode(utf8Data, target);
assert.equal(length, 0);
decoder.clear();
@@ -207,7 +235,7 @@ describe('text encodings', () => {
const decoder = new Utf8ToUtf32();
const target = new Uint32Array(500);
for (let i = 0; i < TEST_STRINGS.length; ++i) {
const utf8Data = fromByteString(encode(TEST_STRINGS[i]));
const utf8Data = stringToUtf8Bytes(TEST_STRINGS[i]);
const length = decoder.decode(utf8Data, target);
assert.equal(toString(target, length), TEST_STRINGS[i]);
decoder.clear();
+1 -2
View File
@@ -230,8 +230,7 @@ export class Utf8ToUtf32 {
&& !((byte1 = input[i]) & 0x80)
&& !((byte2 = input[i + 1]) & 0x80)
&& !((byte3 = input[i + 2]) & 0x80)
&& !((byte4 = input[i + 3]) & 0x80))
{
&& !((byte4 = input[i + 3]) & 0x80)) {
target[size++] = byte1;
target[size++] = byte2;
target[size++] = byte3;
+57 -19
View File
@@ -24,14 +24,20 @@ describe('WriteBuffer', () => {
beforeEach(() => {
stack = [];
cbStack = [];
wb = new WriteBuffer(data => { stack.push(data); });
wb = new WriteBuffer(data => {
stack.push(data);
});
});
describe('write input', () => {
it('string', done => {
wb.write('a._');
wb.write('b.x', () => { cbStack.push('b'); });
wb.write('b.x', () => {
cbStack.push('b');
});
wb.write('c._');
wb.write('d.x', () => { cbStack.push('d'); });
wb.write('d.x', () => {
cbStack.push('d');
});
wb.write('e', () => {
assert.deepEqual(stack, ['a._', 'b.x', 'c._', 'd.x', 'e']);
assert.deepEqual(cbStack, ['b', 'd']);
@@ -40,9 +46,13 @@ describe('WriteBuffer', () => {
});
it('bytes', done => {
wb.write(toBytes('a._'));
wb.write(toBytes('b.x'), () => { cbStack.push('b'); });
wb.write(toBytes('b.x'), () => {
cbStack.push('b');
});
wb.write(toBytes('c._'));
wb.write(toBytes('d.x'), () => { cbStack.push('d'); });
wb.write(toBytes('d.x'), () => {
cbStack.push('d');
});
wb.write(toBytes('e'), () => {
assert.deepEqual(stack.map(val => typeof val === 'string' ? '' : fromBytes(val)), ['a._', 'b.x', 'c._', 'd.x', 'e']);
assert.deepEqual(cbStack, ['b', 'd']);
@@ -51,9 +61,13 @@ describe('WriteBuffer', () => {
});
it('string/bytes mixed', done => {
wb.write('a._');
wb.write('b.x', () => { cbStack.push('b'); });
wb.write('b.x', () => {
cbStack.push('b');
});
wb.write(toBytes('c._'));
wb.write(toBytes('d.x'), () => { cbStack.push('d'); });
wb.write(toBytes('d.x'), () => {
cbStack.push('d');
});
wb.write(toBytes('e'), () => {
assert.deepEqual(stack.map(val => typeof val === 'string' ? val : fromBytes(val)), ['a._', 'b.x', 'c._', 'd.x', 'e']);
assert.deepEqual(cbStack, ['b', 'd']);
@@ -61,10 +75,18 @@ describe('WriteBuffer', () => {
});
});
it('write callback works for empty chunks', done => {
wb.write('a', () => { cbStack.push('a'); });
wb.write('', () => { cbStack.push('b'); });
wb.write(toBytes('c'), () => { cbStack.push('c'); });
wb.write(new Uint8Array(0), () => { cbStack.push('d'); });
wb.write('a', () => {
cbStack.push('a');
});
wb.write('', () => {
cbStack.push('b');
});
wb.write(toBytes('c'), () => {
cbStack.push('c');
});
wb.write(new Uint8Array(0), () => {
cbStack.push('d');
});
wb.write('e', () => {
assert.deepEqual(stack.map(val => typeof val === 'string' ? val : fromBytes(val)), ['a', '', 'c', '', 'e']);
assert.deepEqual(cbStack, ['a', 'b', 'c', 'd']);
@@ -72,13 +94,21 @@ describe('WriteBuffer', () => {
});
});
it('writeSync', done => {
wb.write('a', () => { cbStack.push('a'); });
wb.write('b', () => { cbStack.push('b'); });
wb.write('c', () => { cbStack.push('c'); });
wb.write('a', () => {
cbStack.push('a');
});
wb.write('b', () => {
cbStack.push('b');
});
wb.write('c', () => {
cbStack.push('c');
});
wb.writeSync('d');
assert.deepEqual(stack, ['a', 'b', 'c', 'd']);
assert.deepEqual(cbStack, ['a', 'b', 'c']);
wb.write('x', () => { cbStack.push('x'); });
wb.write('x', () => {
cbStack.push('x');
});
wb.write('', () => {
assert.deepEqual(stack, ['a', 'b', 'c', 'd', 'x', '']);
assert.deepEqual(cbStack, ['a', 'b', 'c', 'x']);
@@ -107,13 +137,21 @@ describe('WriteBuffer', () => {
assert.equal(last, '11'); // 1 + 10 sub calls = 11
});
it('flushSync processes all pending writes', done => {
wb.write('a', () => { cbStack.push('a'); });
wb.write('b', () => { cbStack.push('b'); });
wb.write('c', () => { cbStack.push('c'); });
wb.write('a', () => {
cbStack.push('a');
});
wb.write('b', () => {
cbStack.push('b');
});
wb.write('c', () => {
cbStack.push('c');
});
wb.flushSync();
assert.deepEqual(stack, ['a', 'b', 'c']);
assert.deepEqual(cbStack, ['a', 'b', 'c']);
wb.write('x', () => { cbStack.push('x'); });
wb.write('x', () => {
cbStack.push('x');
});
wb.write('', () => {
assert.deepEqual(stack, ['a', 'b', 'c', 'x', '']);
assert.deepEqual(cbStack, ['a', 'b', 'c', 'x']);
+3 -1
View File
@@ -244,7 +244,9 @@ export class WriteBuffer extends Disposable {
// 2. spawn a promise immediately resolving to `true`
// (executed on the same queue, thus properly aligned before continuation happens)
result.catch(err => {
queueMicrotask(() => {throw err;});
queueMicrotask(() => {
throw err;
});
return Promise.resolve(false);
}).then(continuation);
return;
+42 -14
View File
@@ -185,7 +185,9 @@ describe('ApcParser', () => {
});
it('should be called once on end(true)', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(data); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(data); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -195,7 +197,9 @@ describe('ApcParser', () => {
assert.deepEqual(reports, ['Here comes the mouse!']);
});
it('should not be called on end(false)', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(data); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(data); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -205,8 +209,12 @@ describe('ApcParser', () => {
assert.deepEqual(reports, []);
});
it('should be disposable', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(['one', data]); return true; }));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(['two', data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(['one', data]); return true;
}));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(['two', data]); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -224,8 +232,12 @@ describe('ApcParser', () => {
assert.deepEqual(reports, [['two', 'Here comes the mouse!'], ['one', 'some other data']]);
});
it('should respect return false', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(['one', data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(['two', data]); return false; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(['one', data]); return true;
}));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(['two', data]); return false;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -236,7 +248,9 @@ describe('ApcParser', () => {
});
it('should work up to payload limit', function(): void {
this.timeout(30000);
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(data); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(data); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
const data = toUtf32('A'.repeat(CHUNK_SIZE));
for (let i = 0; i < TEST_PAYLOAD_LIMIT; i += CHUNK_SIZE) {
@@ -247,7 +261,9 @@ describe('ApcParser', () => {
});
it('should abort for payload limit +1', function(): void {
this.timeout(30000);
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => { reports.push(data); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(data => {
reports.push(data); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('A'.repeat(CHUNK_SIZE));
for (let i = 0; i < TEST_PAYLOAD_LIMIT; i += CHUNK_SIZE) {
@@ -408,7 +424,9 @@ describe('ApcParser - async tests', () => {
});
describe('ApcHandlerFactory', () => {
it('should be called once on end(true)', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => { reports.push(data); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => {
reports.push(data); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -418,7 +436,9 @@ describe('ApcParser - async tests', () => {
assert.deepEqual(reports, ['Here comes the mouse!']);
});
it('should not be called on end(false)', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => { reports.push(data); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => {
reports.push(data); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -428,8 +448,12 @@ describe('ApcParser - async tests', () => {
assert.deepEqual(reports, []);
});
it('should be disposable', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => { reports.push(['one', data]); return true; }));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => { reports.push(['two', data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => {
reports.push(['one', data]); return true;
}));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => {
reports.push(['two', data]); return true;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -447,8 +471,12 @@ describe('ApcParser - async tests', () => {
assert.deepEqual(reports, [['two', 'Here comes the mouse!'], ['one', 'some other data']]);
});
it('should respect return false', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => { reports.push(['one', data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => { reports.push(['two', data]); return false; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => {
reports.push(['one', data]); return true;
}));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new ApcHandler(async data => {
reports.push(['two', data]); return false;
}));
parser.start(identifier({intermediates: '+', final: 'p'}));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
+42 -14
View File
@@ -191,7 +191,9 @@ describe('DcsParser', () => {
});
it('should be called once on end(true)', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push([params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -201,7 +203,9 @@ describe('DcsParser', () => {
assert.deepEqual(reports, [[[1, 2, 3], 'Here comes the mouse!']]);
});
it('should not be called on end(false)', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push([params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -211,8 +215,12 @@ describe('DcsParser', () => {
assert.deepEqual(reports, []);
});
it('should be disposable', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['one', params.toArray(), data]); return true; }));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['two', params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push(['one', params.toArray(), data]); return true;
}));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push(['two', params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -230,8 +238,12 @@ describe('DcsParser', () => {
assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!'], ['one', [1, 2, 3], 'some other data']]);
});
it('should respect return false', () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['one', params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push(['two', params.toArray(), data]); return false; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push(['one', params.toArray(), data]); return true;
}));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push(['two', params.toArray(), data]); return false;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -242,7 +254,9 @@ describe('DcsParser', () => {
});
it('should work up to payload limit', function(): void {
this.timeout(30000);
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push([params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
const data = toUtf32('A'.repeat(CHUNK_SIZE));
for (let i = 0; i < TEST_PAYLOAD_LIMIT; i += CHUNK_SIZE) {
@@ -253,7 +267,9 @@ describe('DcsParser', () => {
});
it('should abort for payload limit +1', function(): void {
this.timeout(30000);
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => { reports.push([params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler((data, params) => {
reports.push([params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('A'.repeat(CHUNK_SIZE));
for (let i = 0; i < TEST_PAYLOAD_LIMIT; i += CHUNK_SIZE) {
@@ -419,7 +435,9 @@ describe('DcsParser - async tests', () => {
});
describe('DcsHandlerFactory', () => {
it('should be called once on end(true)', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => { reports.push([params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => {
reports.push([params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -429,7 +447,9 @@ describe('DcsParser - async tests', () => {
assert.deepEqual(reports, [[[1, 2, 3], 'Here comes the mouse!']]);
});
it('should not be called on end(false)', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => { reports.push([params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => {
reports.push([params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -439,8 +459,12 @@ describe('DcsParser - async tests', () => {
assert.deepEqual(reports, []);
});
it('should be disposable', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => { reports.push(['one', params.toArray(), data]); return true; }));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => { reports.push(['two', params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => {
reports.push(['one', params.toArray(), data]); return true;
}));
const dispo = parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => {
reports.push(['two', params.toArray(), data]); return true;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
@@ -458,8 +482,12 @@ describe('DcsParser - async tests', () => {
assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!'], ['one', [1, 2, 3], 'some other data']]);
});
it('should respect return false', async () => {
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => { reports.push(['one', params.toArray(), data]); return true; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => { reports.push(['two', params.toArray(), data]); return false; }));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => {
reports.push(['one', params.toArray(), data]); return true;
}));
parser.registerHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandler(async (data, params) => {
reports.push(['two', params.toArray(), data]); return false;
}));
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
let data = toUtf32('Here comes');
parser.put(data, 0, data.length);
+438 -146
View File
@@ -1451,49 +1451,83 @@ describe('EscapeSequenceParser', () => {
});
describe('ESC custom handlers', () => {
it('prevent fallback', () => {
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('default - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('default - %G'); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom - %G'); return true;
});
parse(parser2, INPUT);
assert.deepEqual(esc, ['custom - %G']);
});
it('allow fallback', () => {
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('default - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom - %G'); return false; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('default - %G'); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom - %G'); return false;
});
parse(parser2, INPUT);
assert.deepEqual(esc, ['custom - %G', 'default - %G']);
});
it('Multiple custom handlers fallback once', () => {
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('default - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom2 - %G'); return false; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('default - %G'); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom - %G'); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom2 - %G'); return false;
});
parse(parser2, INPUT);
assert.deepEqual(esc, ['custom2 - %G', 'custom - %G']);
});
it('Multiple custom handlers no fallback', () => {
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('default - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom2 - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('default - %G'); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom - %G'); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom2 - %G'); return true;
});
parse(parser2, INPUT);
assert.deepEqual(esc, ['custom2 - %G']);
});
it('Execution order should go from latest handler down to the original', () => {
const order: number[] = [];
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { order.push(1); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { order.push(2); return false; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { order.push(3); return false; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
order.push(1); return true;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
order.push(2); return false;
});
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
order.push(3); return false;
});
parse(parser2, '\x1b%G');
assert.deepEqual(order, [3, 2, 1]);
});
it('Dispose should work', () => {
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('default - %G'); return true; });
const dispo = parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('default - %G'); return true;
});
const dispo = parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom - %G'); return true;
});
dispo.dispose();
parse(parser2, INPUT);
assert.deepEqual(esc, ['default - %G']);
});
it('Should not corrupt the parser when dispose is called twice', () => {
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('default - %G'); return true; });
const dispo = parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => { esc.push('custom - %G'); return true; });
parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('default - %G'); return true;
});
const dispo = parser2.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
esc.push('custom - %G'); return true;
});
dispo.dispose();
dispo.dispose();
parse(parser2, INPUT);
@@ -1516,16 +1550,24 @@ describe('EscapeSequenceParser', () => {
describe('CSI custom handlers', () => {
it('Prevent fallback', () => {
const csiCustom: [string, ParamsArray, string][] = [];
parser2.registerCsiHandler({ final: 'm' }, params => { csi.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => {
csi.push(['m', params.toArray(), '']); return true;
});
parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom.push(['m', params.toArray(), '']); return true;
});
parse(parser2, INPUT);
assert.deepEqual(csi, [], 'Should not fallback to original handler');
assert.deepEqual(csiCustom, [['m', [1, 31], ''], ['m', [0], '']]);
});
it('Allow fallback', () => {
const csiCustom: [string, ParamsArray, string][] = [];
parser2.registerCsiHandler({ final: 'm' }, params => { csi.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom.push(['m', params.toArray(), '']); return false; });
parser2.registerCsiHandler({ final: 'm' }, params => {
csi.push(['m', params.toArray(), '']); return true;
});
parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom.push(['m', params.toArray(), '']); return false;
});
parse(parser2, INPUT);
assert.deepEqual(csi, [['m', [1, 31], ''], ['m', [0], '']], 'Should fallback to original handler');
assert.deepEqual(csiCustom, [['m', [1, 31], ''], ['m', [0], '']]);
@@ -1533,9 +1575,15 @@ describe('EscapeSequenceParser', () => {
it('Multiple custom handlers fallback once', () => {
const csiCustom: [string, ParamsArray, string][] = [];
const csiCustom2: [string, ParamsArray, string][] = [];
parser2.registerCsiHandler({ final: 'm' }, params => { csi.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom2.push(['m', params.toArray(), '']); return false; });
parser2.registerCsiHandler({ final: 'm' }, params => {
csi.push(['m', params.toArray(), '']); return true;
});
parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom.push(['m', params.toArray(), '']); return true;
});
parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom2.push(['m', params.toArray(), '']); return false;
});
parse(parser2, INPUT);
assert.deepEqual(csi, [], 'Should not fallback to original handler');
assert.deepEqual(csiCustom, [['m', [1, 31], ''], ['m', [0], '']]);
@@ -1544,9 +1592,15 @@ describe('EscapeSequenceParser', () => {
it('Multiple custom handlers no fallback', () => {
const csiCustom: [string, ParamsArray, string][] = [];
const csiCustom2: [string, ParamsArray, string][] = [];
parser2.registerCsiHandler({ final: 'm' }, params => { csi.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom2.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => {
csi.push(['m', params.toArray(), '']); return true;
});
parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom.push(['m', params.toArray(), '']); return true;
});
parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom2.push(['m', params.toArray(), '']); return true;
});
parse(parser2, INPUT);
assert.deepEqual(csi, [], 'Should not fallback to original handler');
assert.deepEqual(csiCustom, [], 'Should not fallback once');
@@ -1554,16 +1608,26 @@ describe('EscapeSequenceParser', () => {
});
it('Execution order should go from latest handler down to the original', () => {
const order: number[] = [];
parser2.registerCsiHandler({ final: 'm' }, () => { order.push(1); return true; });
parser2.registerCsiHandler({ final: 'm' }, () => { order.push(2); return false; });
parser2.registerCsiHandler({ final: 'm' }, () => { order.push(3); return false; });
parser2.registerCsiHandler({ final: 'm' }, () => {
order.push(1); return true;
});
parser2.registerCsiHandler({ final: 'm' }, () => {
order.push(2); return false;
});
parser2.registerCsiHandler({ final: 'm' }, () => {
order.push(3); return false;
});
parse(parser2, '\x1b[0m');
assert.deepEqual(order, [3, 2, 1]);
});
it('Dispose should work', () => {
const csiCustom: [string, ParamsArray, string][] = [];
parser2.registerCsiHandler({ final: 'm' }, params => { csi.push(['m', params.toArray(), '']); return true; });
const customHandler = parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => {
csi.push(['m', params.toArray(), '']); return true;
});
const customHandler = parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom.push(['m', params.toArray(), '']); return true;
});
customHandler.dispose();
parse(parser2, INPUT);
assert.deepEqual(csi, [['m', [1, 31], ''], ['m', [0], '']]);
@@ -1571,8 +1635,12 @@ describe('EscapeSequenceParser', () => {
});
it('Should not corrupt the parser when dispose is called twice', () => {
const csiCustom: [string, ParamsArray, string][] = [];
parser2.registerCsiHandler({ final: 'm' }, params => { csi.push(['m', params.toArray(), '']); return true; });
const customHandler = parser2.registerCsiHandler({ final: 'm' }, params => { csiCustom.push(['m', params.toArray(), '']); return true; });
parser2.registerCsiHandler({ final: 'm' }, params => {
csi.push(['m', params.toArray(), '']); return true;
});
const customHandler = parser2.registerCsiHandler({ final: 'm' }, params => {
csiCustom.push(['m', params.toArray(), '']); return true;
});
customHandler.dispose();
customHandler.dispose();
parse(parser2, INPUT);
@@ -1613,16 +1681,24 @@ describe('EscapeSequenceParser', () => {
describe('OSC custom handlers', () => {
it('Prevent fallback', () => {
const oscCustom: [number, string][] = [];
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => {
osc.push([1, data]); return true;
}));
parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom.push([1, data]); return true;
}));
parse(parser2, INPUT);
assert.deepEqual(osc, [], 'Should not fallback to original handler');
assert.deepEqual(oscCustom, [[1, 'foo=bar']]);
});
it('Allow fallback', () => {
const oscCustom: [number, string][] = [];
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return false; }));
parser2.registerOscHandler(1, new OscHandler(data => {
osc.push([1, data]); return true;
}));
parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom.push([1, data]); return false;
}));
parse(parser2, INPUT);
assert.deepEqual(osc, [[1, 'foo=bar']], 'Should fallback to original handler');
assert.deepEqual(oscCustom, [[1, 'foo=bar']]);
@@ -1630,9 +1706,15 @@ describe('EscapeSequenceParser', () => {
it('Multiple custom handlers fallback once', () => {
const oscCustom: [number, string][] = [];
const oscCustom2: [number, string][] = [];
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom2.push([1, data]); return false; }));
parser2.registerOscHandler(1, new OscHandler(data => {
osc.push([1, data]); return true;
}));
parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom.push([1, data]); return true;
}));
parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom2.push([1, data]); return false;
}));
parse(parser2, INPUT);
assert.deepEqual(osc, [], 'Should not fallback to original handler');
assert.deepEqual(oscCustom, [[1, 'foo=bar']]);
@@ -1641,9 +1723,15 @@ describe('EscapeSequenceParser', () => {
it('Multiple custom handlers no fallback', () => {
const oscCustom: [number, string][] = [];
const oscCustom2: [number, string][] = [];
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => { oscCustom2.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => {
osc.push([1, data]); return true;
}));
parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom.push([1, data]); return true;
}));
parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom2.push([1, data]); return true;
}));
parse(parser2, INPUT);
assert.deepEqual(osc, [], 'Should not fallback to original handler');
assert.deepEqual(oscCustom, [], 'Should not fallback once');
@@ -1651,16 +1739,26 @@ describe('EscapeSequenceParser', () => {
});
it('Execution order should go from latest handler down to the original', () => {
const order: number[] = [];
parser2.registerOscHandler(1, new OscHandler(() => { order.push(1); return true; }));
parser2.registerOscHandler(1, new OscHandler(() => { order.push(2); return false; }));
parser2.registerOscHandler(1, new OscHandler(() => { order.push(3); return false; }));
parser2.registerOscHandler(1, new OscHandler(() => {
order.push(1); return true;
}));
parser2.registerOscHandler(1, new OscHandler(() => {
order.push(2); return false;
}));
parser2.registerOscHandler(1, new OscHandler(() => {
order.push(3); return false;
}));
parse(parser2, '\x1b]1;foo=bar\x1b\\');
assert.deepEqual(order, [3, 2, 1]);
});
it('Dispose should work', () => {
const oscCustom: [number, string][] = [];
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
const customHandler = parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => {
osc.push([1, data]); return true;
}));
const customHandler = parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom.push([1, data]); return true;
}));
customHandler.dispose();
parse(parser2, INPUT);
assert.deepEqual(osc, [[1, 'foo=bar']]);
@@ -1668,8 +1766,12 @@ describe('EscapeSequenceParser', () => {
});
it('Should not corrupt the parser when dispose is called twice', () => {
const oscCustom: [number, string][] = [];
parser2.registerOscHandler(1, new OscHandler(data => { osc.push([1, data]); return true; }));
const customHandler = parser2.registerOscHandler(1, new OscHandler(data => { oscCustom.push([1, data]); return true; }));
parser2.registerOscHandler(1, new OscHandler(data => {
osc.push([1, data]); return true;
}));
const customHandler = parser2.registerOscHandler(1, new OscHandler(data => {
oscCustom.push([1, data]); return true;
}));
customHandler.dispose();
customHandler.dispose();
parse(parser2, INPUT);
@@ -1712,54 +1814,88 @@ describe('EscapeSequenceParser', () => {
const DCS_INPUT = '\x1bP1;2;3+pabc\x1b\\';
it('Prevent fallback', () => {
const dcsCustom: [string, (number | number[])[], string][] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['A', params.toArray(), data]); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['B', params.toArray(), data]); return true;
}));
parse(parser2, DCS_INPUT);
assert.deepEqual(dcsCustom, [['B', [1, 2, 3], 'abc']]);
});
it('Allow fallback', () => {
const dcsCustom: [string, (number | number[])[], string][] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return false; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['A', params.toArray(), data]); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['B', params.toArray(), data]); return false;
}));
parse(parser2, DCS_INPUT);
assert.deepEqual(dcsCustom, [['B', [1, 2, 3], 'abc'], ['A', [1, 2, 3], 'abc']]);
});
it('Multiple custom handlers fallback once', () => {
const dcsCustom: [string, (number | number[])[], string][] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['C', params.toArray(), data]); return false; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['A', params.toArray(), data]); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['B', params.toArray(), data]); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['C', params.toArray(), data]); return false;
}));
parse(parser2, DCS_INPUT);
assert.deepEqual(dcsCustom, [['C', [1, 2, 3], 'abc'], ['B', [1, 2, 3], 'abc']]);
});
it('Multiple custom handlers no fallback', () => {
const dcsCustom: [string, (number | number[])[], string][] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['C', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['A', params.toArray(), data]); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['B', params.toArray(), data]); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['C', params.toArray(), data]); return true;
}));
parse(parser2, DCS_INPUT);
assert.deepEqual(dcsCustom, [['C', [1, 2, 3], 'abc']]);
});
it('Execution order should go from latest handler down to the original', () => {
const order: number[] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler(() => { order.push(1); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler(() => { order.push(2); return false; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler(() => { order.push(3); return false; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler(() => {
order.push(1); return true;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler(() => {
order.push(2); return false;
}));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler(() => {
order.push(3); return false;
}));
parse(parser2, DCS_INPUT);
assert.deepEqual(order, [3, 2, 1]);
});
it('Dispose should work', () => {
const dcsCustom: [string, (number | number[])[], string][] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
const dispo = parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['A', params.toArray(), data]); return true;
}));
const dispo = parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['B', params.toArray(), data]); return true;
}));
dispo.dispose();
parse(parser2, DCS_INPUT);
assert.deepEqual(dcsCustom, [['A', [1, 2, 3], 'abc']]);
});
it('Should not corrupt the parser when dispose is called twice', () => {
const dcsCustom: [string, (number | number[])[], string][] = [];
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['A', params.toArray(), data]); return true; }));
const dispo = parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => { dcsCustom.push(['B', params.toArray(), data]); return true; }));
parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['A', params.toArray(), data]); return true;
}));
const dispo = parser2.registerDcsHandler({ intermediates: '+', final: 'p' }, new DcsHandler((data, params) => {
dcsCustom.push(['B', params.toArray(), data]); return true;
}));
dispo.dispose();
dispo.dispose();
parse(parser2, DCS_INPUT);
@@ -1801,54 +1937,88 @@ describe('EscapeSequenceParser', () => {
const APC_INPUT = '\x1b_+pabc\x1b\\';
it('Prevent fallback', () => {
const apcCustom: [string, string][] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['A', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['B', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['A', data]); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['B', data]); return true;
}));
parse(parser2, APC_INPUT);
assert.deepEqual(apcCustom, [['B', 'abc']]);
});
it('Allow fallback', () => {
const apcCustom: [string, string][] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['A', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['B', data]); return false; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['A', data]); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['B', data]); return false;
}));
parse(parser2, APC_INPUT);
assert.deepEqual(apcCustom, [['B', 'abc'], ['A', 'abc']]);
});
it('Multiple custom handlers fallback once', () => {
const apcCustom: [string, string][] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['A', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['B', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['C', data]); return false; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['A', data]); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['B', data]); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['C', data]); return false;
}));
parse(parser2, APC_INPUT);
assert.deepEqual(apcCustom, [['C', 'abc'], ['B', 'abc']]);
});
it('Multiple custom handlers no fallback', () => {
const apcCustom: [string, string][] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['A', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['B', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['C', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['A', data]); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['B', data]); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['C', data]); return true;
}));
parse(parser2, APC_INPUT);
assert.deepEqual(apcCustom, [['C', 'abc']]);
});
it('Execution order should go from latest handler down to the original', () => {
const order: number[] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(() => { order.push(1); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(() => { order.push(2); return false; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(() => { order.push(3); return false; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(() => {
order.push(1); return true;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(() => {
order.push(2); return false;
}));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(() => {
order.push(3); return false;
}));
parse(parser2, APC_INPUT);
assert.deepEqual(order, [3, 2, 1]);
});
it('Dispose should work', () => {
const apcCustom: [string, string][] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['A', data]); return true; }));
const dispo = parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['B', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['A', data]); return true;
}));
const dispo = parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['B', data]); return true;
}));
dispo.dispose();
parse(parser2, APC_INPUT);
assert.deepEqual(apcCustom, [['A', 'abc']]);
});
it('Should not corrupt the parser when dispose is called twice', () => {
const apcCustom: [string, string][] = [];
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['A', data]); return true; }));
const dispo = parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => { apcCustom.push(['B', data]); return true; }));
parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['A', data]); return true;
}));
const dispo = parser2.registerApcHandler({ intermediates: '+', final: 'p' }, new ApcHandler(data => {
apcCustom.push(['B', data]); return true;
}));
dispo.dispose();
dispo.dispose();
parse(parser2, APC_INPUT);
@@ -1884,44 +2054,74 @@ describe('EscapeSequenceParser', () => {
const c = String.fromCharCode(i);
assert.equal(parser.identToString(parser.identifier({ prefix: c, final: 'z' })), c + 'z');
}
assert.throws(() => { parser.identifier({ prefix: '\x3b', final: 'z' }); }, 'prefix must be in range 0x3c .. 0x3f');
assert.throws(() => { parser.identifier({ prefix: '\x40', final: 'z' }); }, 'prefix must be in range 0x3c .. 0x3f');
assert.throws(() => { parser.identifier({ prefix: '??', final: 'z' }); }, 'only one byte as prefix supported');
assert.throws(() => {
parser.identifier({ prefix: '\x3b', final: 'z' });
}, 'prefix must be in range 0x3c .. 0x3f');
assert.throws(() => {
parser.identifier({ prefix: '\x40', final: 'z' });
}, 'prefix must be in range 0x3c .. 0x3f');
assert.throws(() => {
parser.identifier({ prefix: '??', final: 'z' });
}, 'only one byte as prefix supported');
});
it('intermediates range 0x20 .. 0x2f, up to two bytes', () => {
for (let i = 0x20; i <= 0x2f; ++i) {
const c = String.fromCharCode(i);
assert.equal(parser.identToString(parser.identifier({ intermediates: c + c, final: 'z' })), c + c + 'z');
}
assert.throws(() => { parser.identifier({ intermediates: '\x1f', final: 'z' }); }, 'intermediate must be in range 0x20 .. 0x2f');
assert.throws(() => { parser.identifier({ intermediates: '\x30', final: 'z' }); }, 'intermediate must be in range 0x20 .. 0x2f');
assert.throws(() => { parser.identifier({ intermediates: '!!!', final: 'z' }); }, 'only two bytes as intermediates are supported');
assert.throws(() => {
parser.identifier({ intermediates: '\x1f', final: 'z' });
}, 'intermediate must be in range 0x20 .. 0x2f');
assert.throws(() => {
parser.identifier({ intermediates: '\x30', final: 'z' });
}, 'intermediate must be in range 0x20 .. 0x2f');
assert.throws(() => {
parser.identifier({ intermediates: '!!!', final: 'z' });
}, 'only two bytes as intermediates are supported');
});
it('final CSI/DCS range 0x40 .. 0x7e (default), one byte', () => {
for (let i = 0x40; i <= 0x7e; ++i) {
const c = String.fromCharCode(i);
assert.equal(parser.identToString(parser.identifier({ final: c })), c);
}
assert.throws(() => { parser.identifier({ final: '\x3f' }); }, 'final must be in range 64 .. 126');
assert.throws(() => { parser.identifier({ final: '\x7f' }); }, 'final must be in range 64 .. 126');
assert.throws(() => { parser.identifier({ final: 'zz' }); }, 'final must be a single byte');
assert.throws(() => {
parser.identifier({ final: '\x3f' });
}, 'final must be in range 64 .. 126');
assert.throws(() => {
parser.identifier({ final: '\x7f' });
}, 'final must be in range 64 .. 126');
assert.throws(() => {
parser.identifier({ final: 'zz' });
}, 'final must be a single byte');
});
it('final ESC + APC range 0x30 .. 0x7e, one byte', () => {
for (let i = 0x30; i <= 0x7e; ++i) {
const final = String.fromCharCode(i);
let handler: IDisposable | undefined;
assert.doesNotThrow(() => { handler = parser.registerEscHandler({ final }, () => true); }, 'final must be in range 48 .. 126');
assert.doesNotThrow(() => {
handler = parser.registerEscHandler({ final }, () => true);
}, 'final must be in range 48 .. 126');
if (handler) handler.dispose();
assert.doesNotThrow(
() => { handler = parser.registerApcHandler({ final }, {start: () => {}, put: ()=>{}, end: ()=>true}); },
() => {
handler = parser.registerApcHandler({ final }, {start: () => {}, put: ()=>{}, end: ()=>true});
},
'final must be in range 48 .. 126'
);
if (handler) handler.dispose();
}
assert.throws(() => { parser.registerEscHandler({ final: '\x2f' }, () => true); }, 'final must be in range 48 .. 126');
assert.throws(() => { parser.registerEscHandler({ final: '\x7f' }, () => true); }, 'final must be in range 48 .. 126');
assert.throws(() => { parser.registerApcHandler({ final: '\x2f' }, {start: () => {}, put: ()=>{}, end: ()=>true}); }, 'final must be in range 48 .. 126');
assert.throws(() => { parser.registerApcHandler({ final: '\x7f' }, {start: () => {}, put: ()=>{}, end: ()=>true}); }, 'final must be in range 48 .. 126');
assert.throws(() => {
parser.registerEscHandler({ final: '\x2f' }, () => true);
}, 'final must be in range 48 .. 126');
assert.throws(() => {
parser.registerEscHandler({ final: '\x7f' }, () => true);
}, 'final must be in range 48 .. 126');
assert.throws(() => {
parser.registerApcHandler({ final: '\x2f' }, {start: () => {}, put: ()=>{}, end: ()=>true});
}, 'final must be in range 48 .. 126');
assert.throws(() => {
parser.registerApcHandler({ final: '\x7f' }, {start: () => {}, put: ()=>{}, end: ()=>true});
}, 'final must be in range 48 .. 126');
});
it('id calculation - should stacking prefix -> intermediate -> final', () => {
assert.equal(parser.identToString(parser.identifier({ final: 'z' })), 'z');
@@ -1934,9 +2134,15 @@ describe('EscapeSequenceParser', () => {
describe('identifier invocation', () => {
it('ESC', () => {
const callstack: string[] = [];
const h1 = parser.registerEscHandler({ final: 'z' }, () => { callstack.push('z'); return true; });
const h2 = parser.registerEscHandler({ intermediates: '!', final: 'z' }, () => { callstack.push('!z'); return true; });
const h3 = parser.registerEscHandler({ intermediates: '!!', final: 'z' }, () => { callstack.push('!!z'); return true; });
const h1 = parser.registerEscHandler({ final: 'z' }, () => {
callstack.push('z'); return true;
});
const h2 = parser.registerEscHandler({ intermediates: '!', final: 'z' }, () => {
callstack.push('!z'); return true;
});
const h3 = parser.registerEscHandler({ intermediates: '!!', final: 'z' }, () => {
callstack.push('!!z'); return true;
});
parse(parser, '\x1bz\x1b!z\x1b!!z');
h1.dispose();
h2.dispose();
@@ -1946,12 +2152,24 @@ describe('EscapeSequenceParser', () => {
});
it('CSI', () => {
const callstack: any[] = [];
const h1 = parser.registerCsiHandler({ final: 'z' }, params => { callstack.push(['z', params.toArray()]); return true; });
const h2 = parser.registerCsiHandler({ intermediates: '!', final: 'z' }, params => { callstack.push(['!z', params.toArray()]); return true; });
const h3 = parser.registerCsiHandler({ intermediates: '!!', final: 'z' }, params => { callstack.push(['!!z', params.toArray()]); return true; });
const h4 = parser.registerCsiHandler({ prefix: '?', final: 'z' }, params => { callstack.push(['?z', params.toArray()]); return true; });
const h5 = parser.registerCsiHandler({ prefix: '?', intermediates: '!', final: 'z' }, params => { callstack.push(['?!z', params.toArray()]); return true; });
const h6 = parser.registerCsiHandler({ prefix: '?', intermediates: '!!', final: 'z' }, params => { callstack.push(['?!!z', params.toArray()]); return true; });
const h1 = parser.registerCsiHandler({ final: 'z' }, params => {
callstack.push(['z', params.toArray()]); return true;
});
const h2 = parser.registerCsiHandler({ intermediates: '!', final: 'z' }, params => {
callstack.push(['!z', params.toArray()]); return true;
});
const h3 = parser.registerCsiHandler({ intermediates: '!!', final: 'z' }, params => {
callstack.push(['!!z', params.toArray()]); return true;
});
const h4 = parser.registerCsiHandler({ prefix: '?', final: 'z' }, params => {
callstack.push(['?z', params.toArray()]); return true;
});
const h5 = parser.registerCsiHandler({ prefix: '?', intermediates: '!', final: 'z' }, params => {
callstack.push(['?!z', params.toArray()]); return true;
});
const h6 = parser.registerCsiHandler({ prefix: '?', intermediates: '!!', final: 'z' }, params => {
callstack.push(['?!!z', params.toArray()]); return true;
});
parse(parser, '\x1b[1;z\x1b[1;!z\x1b[1;!!z\x1b[?1;z\x1b[?1;!z\x1b[?1;!!z');
h1.dispose();
h2.dispose();
@@ -1967,12 +2185,24 @@ describe('EscapeSequenceParser', () => {
});
it('DCS', () => {
const callstack: any[] = [];
const h1 = parser.registerDcsHandler({ final: 'z' }, new DcsHandler((data, params) => { callstack.push(['z', params.toArray(), data]); return true; }));
const h2 = parser.registerDcsHandler({ intermediates: '!', final: 'z' }, new DcsHandler((data, params) => { callstack.push(['!z', params.toArray(), data]); return true; }));
const h3 = parser.registerDcsHandler({ intermediates: '!!', final: 'z' }, new DcsHandler((data, params) => { callstack.push(['!!z', params.toArray(), data]); return true; }));
const h4 = parser.registerDcsHandler({ prefix: '?', final: 'z' }, new DcsHandler((data, params) => { callstack.push(['?z', params.toArray(), data]); return true; }));
const h5 = parser.registerDcsHandler({ prefix: '?', intermediates: '!', final: 'z' }, new DcsHandler((data, params) => { callstack.push(['?!z', params.toArray(), data]); return true; }));
const h6 = parser.registerDcsHandler({ prefix: '?', intermediates: '!!', final: 'z' }, new DcsHandler((data, params) => { callstack.push(['?!!z', params.toArray(), data]); return true; }));
const h1 = parser.registerDcsHandler({ final: 'z' }, new DcsHandler((data, params) => {
callstack.push(['z', params.toArray(), data]); return true;
}));
const h2 = parser.registerDcsHandler({ intermediates: '!', final: 'z' }, new DcsHandler((data, params) => {
callstack.push(['!z', params.toArray(), data]); return true;
}));
const h3 = parser.registerDcsHandler({ intermediates: '!!', final: 'z' }, new DcsHandler((data, params) => {
callstack.push(['!!z', params.toArray(), data]); return true;
}));
const h4 = parser.registerDcsHandler({ prefix: '?', final: 'z' }, new DcsHandler((data, params) => {
callstack.push(['?z', params.toArray(), data]); return true;
}));
const h5 = parser.registerDcsHandler({ prefix: '?', intermediates: '!', final: 'z' }, new DcsHandler((data, params) => {
callstack.push(['?!z', params.toArray(), data]); return true;
}));
const h6 = parser.registerDcsHandler({ prefix: '?', intermediates: '!!', final: 'z' }, new DcsHandler((data, params) => {
callstack.push(['?!!z', params.toArray(), data]); return true;
}));
parse(parser, '\x1bP1;zAB\x1b\\\x1bP1;!zAB\x1b\\\x1bP1;!!zAB\x1b\\\x1bP?1;zAB\x1b\\\x1bP?1;!zAB\x1b\\\x1bP?1;!!zAB\x1b\\');
h1.dispose();
h2.dispose();
@@ -1995,9 +2225,15 @@ describe('EscapeSequenceParser', () => {
});
it('APC', () => {
const callstack: any[] = [];
const h1 = parser.registerApcHandler({ final: 'z' }, new ApcHandler(data => { callstack.push(['z', data]); return true; }));
const h2 = parser.registerApcHandler({ intermediates: '!', final: 'z' }, new ApcHandler(data => { callstack.push(['!z', data]); return true; }));
const h3 = parser.registerApcHandler({ intermediates: '!!', final: 'z' }, new ApcHandler(data => { callstack.push(['!!z', data]); return true; }));
const h1 = parser.registerApcHandler({ final: 'z' }, new ApcHandler(data => {
callstack.push(['z', data]); return true;
}));
const h2 = parser.registerApcHandler({ intermediates: '!', final: 'z' }, new ApcHandler(data => {
callstack.push(['!z', data]); return true;
}));
const h3 = parser.registerApcHandler({ intermediates: '!!', final: 'z' }, new ApcHandler(data => {
callstack.push(['!!z', data]); return true;
}));
parse(parser, '\x1b_zAB\x1b\\\x1b_!zAB\x1b\\\x1b_!!zAB\x1b\\');
h1.dispose();
h2.dispose();
@@ -2106,14 +2342,30 @@ describe('EscapeSequenceParser - async', () => {
}
callstack.push(['PRINT', result]);
});
parser.registerCsiHandler({ final: 'm' }, params => { callstack.push(['SGR', params.toArray()]); return true; });
parser.registerEscHandler({ intermediates: '%', final: 'G' }, () => { callstack.push(['ESC %G']); return true; });
parser.registerEscHandler({ final: 'E' }, () => { callstack.push(['ESC E']); return true; });
parser.setExecuteHandler('\r', () => { callstack.push(['EXE \r']); return true; });
parser.setExecuteHandler('\n', () => { callstack.push(['EXE \n']); return true; });
parser.registerOscHandler(1, new OscHandler(data => { callstack.push(['OSC 1', data]); return true; }));
parser.registerDcsHandler({ final: 'a' }, new DcsHandler((data, params) => { callstack.push(['DCS a', [data, params.toArray()]]); return true; }));
parser.registerApcHandler({ final: 'X' }, new ApcHandler(data => { callstack.push(['APC X', data]); return true; }));
parser.registerCsiHandler({ final: 'm' }, params => {
callstack.push(['SGR', params.toArray()]); return true;
});
parser.registerEscHandler({ intermediates: '%', final: 'G' }, () => {
callstack.push(['ESC %G']); return true;
});
parser.registerEscHandler({ final: 'E' }, () => {
callstack.push(['ESC E']); return true;
});
parser.setExecuteHandler('\r', () => {
callstack.push(['EXE \r']); return true;
});
parser.setExecuteHandler('\n', () => {
callstack.push(['EXE \n']); return true;
});
parser.registerOscHandler(1, new OscHandler(data => {
callstack.push(['OSC 1', data]); return true;
}));
parser.registerDcsHandler({ final: 'a' }, new DcsHandler((data, params) => {
callstack.push(['DCS a', [data, params.toArray()]]); return true;
}));
parser.registerApcHandler({ final: 'X' }, new ApcHandler(data => {
callstack.push(['APC X', data]); return true;
}));
});
it('sync handlers keep being parsed in sync mode', () => {
@@ -2142,14 +2394,30 @@ describe('EscapeSequenceParser - async', () => {
}
callstack.push(['PRINT', result]);
});
parser.registerCsiHandler({ final: 'm' }, async params => { callstack.push(['SGR', params.toArray()]); return true; });
parser.registerEscHandler({ intermediates: '%', final: 'G' }, async () => { callstack.push(['ESC %G']); return true; });
parser.registerEscHandler({ final: 'E' }, async () => { callstack.push(['ESC E']); return true; });
parser.setExecuteHandler('\r', () => { callstack.push(['EXE \r']); return true; });
parser.setExecuteHandler('\n', () => { callstack.push(['EXE \n']); return true; });
parser.registerOscHandler(1, new OscHandler(async data => { callstack.push(['OSC 1', data]); return true; }));
parser.registerDcsHandler({ final: 'a' }, new DcsHandler(async (data, params) => { callstack.push(['DCS a', [data, params.toArray()]]); return true; }));
parser.registerApcHandler({ final: 'X' }, new ApcHandler(async data => { callstack.push(['APC X', data]); return true; }));
parser.registerCsiHandler({ final: 'm' }, async params => {
callstack.push(['SGR', params.toArray()]); return true;
});
parser.registerEscHandler({ intermediates: '%', final: 'G' }, async () => {
callstack.push(['ESC %G']); return true;
});
parser.registerEscHandler({ final: 'E' }, async () => {
callstack.push(['ESC E']); return true;
});
parser.setExecuteHandler('\r', () => {
callstack.push(['EXE \r']); return true;
});
parser.setExecuteHandler('\n', () => {
callstack.push(['EXE \n']); return true;
});
parser.registerOscHandler(1, new OscHandler(async data => {
callstack.push(['OSC 1', data]); return true;
}));
parser.registerDcsHandler({ final: 'a' }, new DcsHandler(async (data, params) => {
callstack.push(['DCS a', [data, params.toArray()]]); return true;
}));
parser.registerApcHandler({ final: 'X' }, new ApcHandler(async data => {
callstack.push(['APC X', data]); return true;
}));
});
it('sync parse call does not work anymore', () => {
@@ -2239,7 +2507,9 @@ describe('EscapeSequenceParser - async', () => {
});
it('multiple async SGR handlers', async () => {
// register with fallback
const SGR2 = parser.registerCsiHandler({ final: 'm' }, async params => { callstack.push(['2# SGR', params.toArray()]); return false; });
const SGR2 = parser.registerCsiHandler({ final: 'm' }, async params => {
callstack.push(['2# SGR', params.toArray()]); return false;
});
await parseP(parser, INPUT);
// should contain [2# SGR, SGR] call pairs
for (let i = 0; i < callstack.length; ++i) {
@@ -2274,7 +2544,9 @@ describe('EscapeSequenceParser - async', () => {
clearAccu();
// register without fallback
const SGR22 = parser.registerCsiHandler({ final: 'm' }, async params => { callstack.push(['2# SGR', params.toArray()]); return true; });
const SGR22 = parser.registerCsiHandler({ final: 'm' }, async params => {
callstack.push(['2# SGR', params.toArray()]); return true;
});
await parseP(parser, INPUT);
// should only contain 2# SGR
for (let i = 0; i < callstack.length; ++i) {
@@ -2307,7 +2579,9 @@ describe('EscapeSequenceParser - async', () => {
});
it('multiple async ESC handlers', async () => {
// register with fallback
const ESC2 = parser.registerEscHandler({ final: 'E' }, async () => { callstack.push(['2# ESC E']); return false; });
const ESC2 = parser.registerEscHandler({ final: 'E' }, async () => {
callstack.push(['2# ESC E']); return false;
});
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2340,7 +2614,9 @@ describe('EscapeSequenceParser - async', () => {
clearAccu();
// register without fallback
const ESC22 = parser.registerEscHandler({ final: 'E' }, async () => { callstack.push(['2# ESC E']); return true; });
const ESC22 = parser.registerEscHandler({ final: 'E' }, async () => {
callstack.push(['2# ESC E']); return true;
});
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2372,9 +2648,13 @@ describe('EscapeSequenceParser - async', () => {
});
it('sync/async SGR mixed', async () => {
// sync with fallback
const SGR2 = parser.registerCsiHandler({ final: 'm' }, params => { callstack.push(['2# SGR', params.toArray()]); return false; });
const SGR2 = parser.registerCsiHandler({ final: 'm' }, params => {
callstack.push(['2# SGR', params.toArray()]); return false;
});
// async with fallback
const SGR3 = parser.registerCsiHandler({ final: 'm' }, async params => { callstack.push(['3# SGR', params.toArray()]); return false; });
const SGR3 = parser.registerCsiHandler({ final: 'm' }, async params => {
callstack.push(['3# SGR', params.toArray()]); return false;
});
await parseP(parser, INPUT);
// should contain [3# SGR, 2# SGR, SGR] call triples
for (let i = 0; i < callstack.length; ++i) {
@@ -2434,7 +2714,9 @@ describe('EscapeSequenceParser - async', () => {
});
it('multiple async OSC handlers', async () => {
// register with fallback
const OSC2 = parser.registerOscHandler(1, new OscHandler(async data => { callstack.push(['2# OSC 1', data]); return false; }));
const OSC2 = parser.registerOscHandler(1, new OscHandler(async data => {
callstack.push(['2# OSC 1', data]); return false;
}));
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2467,7 +2749,9 @@ describe('EscapeSequenceParser - async', () => {
clearAccu();
// register without fallback
const OSC22 = parser.registerOscHandler(1, new OscHandler(async data => { callstack.push(['2# OSC 1', data]); return true; }));
const OSC22 = parser.registerOscHandler(1, new OscHandler(async data => {
callstack.push(['2# OSC 1', data]); return true;
}));
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2500,7 +2784,9 @@ describe('EscapeSequenceParser - async', () => {
});
it('multiple async DCS handlers', async () => {
// register with fallback
const DCS2 = parser.registerDcsHandler({ final: 'a' }, new DcsHandler(async (data, params) => { callstack.push(['#2 DCS a', [data, params.toArray()]]); return false; }));
const DCS2 = parser.registerDcsHandler({ final: 'a' }, new DcsHandler(async (data, params) => {
callstack.push(['#2 DCS a', [data, params.toArray()]]); return false;
}));
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2533,7 +2819,9 @@ describe('EscapeSequenceParser - async', () => {
clearAccu();
// register without fallback
const DCS22 = parser.registerDcsHandler({ final: 'a' }, new DcsHandler(async (data, params) => { callstack.push(['#2 DCS a', [data, params.toArray()]]); return true; }));
const DCS22 = parser.registerDcsHandler({ final: 'a' }, new DcsHandler(async (data, params) => {
callstack.push(['#2 DCS a', [data, params.toArray()]]); return true;
}));
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2566,7 +2854,9 @@ describe('EscapeSequenceParser - async', () => {
});
it('multiple async APC handlers', async () => {
// register with fallback
const APC2 = parser.registerApcHandler({ final: 'X' }, new ApcHandler(async data => { callstack.push(['#2 APC X', data]); return false; }));
const APC2 = parser.registerApcHandler({ final: 'X' }, new ApcHandler(async data => {
callstack.push(['#2 APC X', data]); return false;
}));
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
@@ -2599,7 +2889,9 @@ describe('EscapeSequenceParser - async', () => {
clearAccu();
// register without fallback
const APC22 = parser.registerApcHandler({ final: 'X' }, new ApcHandler(async data => { callstack.push(['#2 APC X', data]); return true; }));
const APC22 = parser.registerApcHandler({ final: 'X' }, new ApcHandler(async data => {
callstack.push(['#2 APC X', data]); return true;
}));
await parseP(parser, INPUT);
for (let i = 0; i < callstack.length; ++i) {
const entry = callstack[i];
+42 -14
View File
@@ -185,7 +185,9 @@ describe('OscParser', () => {
});
it('should be called once on end(true)', () => {
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
parser.registerHandler(1234, new OscHandler(data => {
reports.push([1234, data]); return true;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -195,7 +197,9 @@ describe('OscParser', () => {
assert.deepEqual(reports, [[1234, 'Here comes the mouse!']]);
});
it('should not be called on end(false)', () => {
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
parser.registerHandler(1234, new OscHandler(data => {
reports.push([1234, data]); return true;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -205,8 +209,12 @@ describe('OscParser', () => {
assert.deepEqual(reports, []);
});
it('should be disposable', () => {
parser.registerHandler(1234, new OscHandler(data => { reports.push(['one', data]); return true; }));
const dispo = parser.registerHandler(1234, new OscHandler(data => { reports.push(['two', data]); return true; }));
parser.registerHandler(1234, new OscHandler(data => {
reports.push(['one', data]); return true;
}));
const dispo = parser.registerHandler(1234, new OscHandler(data => {
reports.push(['two', data]); return true;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -224,8 +232,12 @@ describe('OscParser', () => {
assert.deepEqual(reports, [['two', 'Here comes the mouse!'], ['one', 'some other data']]);
});
it('should respect return false', () => {
parser.registerHandler(1234, new OscHandler(data => { reports.push(['one', data]); return true; }));
parser.registerHandler(1234, new OscHandler(data => { reports.push(['two', data]); return false; }));
parser.registerHandler(1234, new OscHandler(data => {
reports.push(['one', data]); return true;
}));
parser.registerHandler(1234, new OscHandler(data => {
reports.push(['two', data]); return false;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -236,7 +248,9 @@ describe('OscParser', () => {
});
it('should work up to payload limit', function(): void {
this.timeout(30000);
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
parser.registerHandler(1234, new OscHandler(data => {
reports.push([1234, data]); return true;
}));
parser.start();
let data = toUtf32('1234;');
parser.put(data, 0, data.length);
@@ -249,7 +263,9 @@ describe('OscParser', () => {
});
it('should abort for payload limit +1', function(): void {
this.timeout(30000);
parser.registerHandler(1234, new OscHandler(data => { reports.push([1234, data]); return true; }));
parser.registerHandler(1234, new OscHandler(data => {
reports.push([1234, data]); return true;
}));
parser.start();
let data = toUtf32('1234;');
parser.put(data, 0, data.length);
@@ -412,7 +428,9 @@ describe('OscParser - async tests', () => {
});
describe('OscHandlerFactory', () => {
it('should be called once on end(true)', async () => {
parser.registerHandler(1234, new OscHandler(async data => { reports.push([1234, data]); return true; }));
parser.registerHandler(1234, new OscHandler(async data => {
reports.push([1234, data]); return true;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -423,7 +441,9 @@ describe('OscParser - async tests', () => {
assert.deepEqual(reports, [[1234, 'Here comes the mouse!']]);
});
it('should not be called on end(false)', async () => {
parser.registerHandler(1234, new OscHandler(async data => { reports.push([1234, data]); return true; }));
parser.registerHandler(1234, new OscHandler(async data => {
reports.push([1234, data]); return true;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -433,8 +453,12 @@ describe('OscParser - async tests', () => {
assert.deepEqual(reports, []);
});
it('should be disposable', async () => {
parser.registerHandler(1234, new OscHandler(async data => { reports.push(['one', data]); return true; }));
const dispo = parser.registerHandler(1234, new OscHandler(async data => { reports.push(['two', data]); return true; }));
parser.registerHandler(1234, new OscHandler(async data => {
reports.push(['one', data]); return true;
}));
const dispo = parser.registerHandler(1234, new OscHandler(async data => {
reports.push(['two', data]); return true;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
@@ -452,8 +476,12 @@ describe('OscParser - async tests', () => {
assert.deepEqual(reports, [['two', 'Here comes the mouse!'], ['one', 'some other data']]);
});
it('should respect return false', async () => {
parser.registerHandler(1234, new OscHandler(async data => { reports.push(['one', data]); return true; }));
parser.registerHandler(1234, new OscHandler(async data => { reports.push(['two', data]); return false; }));
parser.registerHandler(1234, new OscHandler(async data => {
reports.push(['one', data]); return true;
}));
parser.registerHandler(1234, new OscHandler(async data => {
reports.push(['two', data]); return false;
}));
parser.start();
let data = toUtf32('1234;Here comes');
parser.put(data, 0, data.length);
+3 -1
View File
@@ -40,7 +40,9 @@ describe('AddonManager', () => {
let called = 0;
class Addon implements ITerminalAddon {
public activate(): void {}
public dispose(): void { called++; }
public dispose(): void {
called++;
}
}
manager.loadAddon(null!, new Addon());
manager.loadAddon(null!, new Addon());
+18 -6
View File
@@ -19,11 +19,21 @@ export class BufferApiView implements IBufferApi {
return this;
}
public get cursorY(): number { return this._buffer.y; }
public get cursorX(): number { return this._buffer.x; }
public get viewportY(): number { return this._buffer.ydisp; }
public get baseY(): number { return this._buffer.ybase; }
public get length(): number { return this._buffer.lines.length; }
public get cursorY(): number {
return this._buffer.y;
}
public get cursorX(): number {
return this._buffer.x;
}
public get viewportY(): number {
return this._buffer.ydisp;
}
public get baseY(): number {
return this._buffer.ybase;
}
public get length(): number {
return this._buffer.lines.length;
}
public getLine(y: number): IBufferLineApi | undefined {
const line = this._buffer.lines.get(y);
if (!line) {
@@ -31,5 +41,7 @@ export class BufferApiView implements IBufferApi {
}
return new BufferLineApiView(line);
}
public getNullCell(): IBufferCellApi { return new CellData(); }
public getNullCell(): IBufferCellApi {
return new CellData();
}
}
+6 -2
View File
@@ -10,8 +10,12 @@ import { IBufferCell as IBufferCellApi, IBufferLine as IBufferLineApi } from '@x
export class BufferLineApiView implements IBufferLineApi {
constructor(private _line: IBufferLine) { }
public get isWrapped(): boolean { return this._line.isWrapped; }
public get length(): number { return this._line.length; }
public get isWrapped(): boolean {
return this._line.isWrapped;
}
public get length(): number {
return this._line.length;
}
public getCell(x: number, cell?: IBufferCellApi): IBufferCellApi | undefined {
if (x < 0 || x >= this._line.length) {
return undefined;
+6 -2
View File
@@ -23,8 +23,12 @@ export class BufferNamespaceApi extends Disposable implements IBufferNamespaceAp
this._core.buffers.onBufferActivate(() => this._onBufferChange.fire(this.active));
}
public get active(): IBufferApi {
if (this._core.buffers.active === this._core.buffers.normal) { return this.normal; }
if (this._core.buffers.active === this._core.buffers.alt) { return this.alternate; }
if (this._core.buffers.active === this._core.buffers.normal) {
return this.normal;
}
if (this._core.buffers.active === this._core.buffers.alt) {
return this.alternate;
}
throw new Error('Active buffer is neither normal nor alternate');
}
public get normal(): IBufferApi {
+3 -1
View File
@@ -29,7 +29,9 @@ export class BufferService extends Disposable implements IBufferService {
private readonly _onScroll = this._register(new Emitter<number>());
public readonly onScroll = this._onScroll.event;
public get buffer(): IBuffer { return this.buffers.active; }
public get buffer(): IBuffer {
return this.buffers.active;
}
/** An IBufferline to clone/copy from for new blank lines */
private _cachedBlankLine: IBufferLine | undefined;
+3 -1
View File
@@ -32,7 +32,9 @@ export class DecorationService extends Disposable implements IDecorationService
private readonly _onDecorationRemoved = this._register(new Emitter<IInternalDecoration>());
public readonly onDecorationRemoved = this._onDecorationRemoved.event;
public get decorations(): IterableIterator<IInternalDecoration> { return this._decorations.values(); }
public get decorations(): IterableIterator<IInternalDecoration> {
return this._decorations.values();
}
constructor(@ILogService private readonly _logService: ILogService) {
super();
+3 -1
View File
@@ -35,7 +35,9 @@ export class LogService extends Disposable implements ILogService {
public serviceBrand: any;
private _logLevel: LogLevelEnum = LogLevelEnum.OFF;
public get logLevel(): LogLevelEnum { return this._logLevel; }
public get logLevel(): LogLevelEnum {
return this._logLevel;
}
constructor(
@IOptionsService private readonly _optionsService: IOptionsService
@@ -40,8 +40,12 @@ describe('MouseStateService', () => {
cms.reset();
assert.equal(cms.activeEncoding, 'DEFAULT');
assert.equal(cms.activeProtocol, 'NONE');
assert.throws(() => { cms.activeEncoding = 'xyz'; }, 'unknown encoding "xyz"');
assert.throws(() => { cms.activeProtocol = 'xyz'; }, 'unknown protocol "xyz"');
assert.throws(() => {
cms.activeEncoding = 'xyz';
}, 'unknown encoding "xyz"');
assert.throws(() => {
cms.activeProtocol = 'xyz';
}, 'unknown protocol "xyz"');
});
it('addEncoding', () => {
const cms = new MouseStateService();
+6 -2
View File
@@ -25,11 +25,15 @@ describe('unicode provider', () => {
it('default to V6', () => {
assert.equal(us.activeVersion, '6');
assert.deepEqual(us.versions, ['6']);
assert.doesNotThrow(() => { us.activeVersion = '6'; }, `unknown Unicode version "6"`);
assert.doesNotThrow(() => {
us.activeVersion = '6';
}, `unknown Unicode version "6"`);
assert.equal(us.getStringCellWidth('hello'), 5);
});
it('activate should throw for unknown version', () => {
assert.throws(() => { us.activeVersion = '55'; }, 'unknown Unicode version "55"');
assert.throws(() => {
us.activeVersion = '55';
}, 'unknown Unicode version "55"');
});
it('should notify about version change', () => {
const notes: string[] = [];
+18 -6
View File
@@ -35,8 +35,12 @@ describe('Headless API Tests', function (): void {
it('write with callback', async () => {
let result: string | undefined;
await new Promise<void>(r => {
term.write('foo', () => { result = 'a'; });
term.write('bar', () => { result += 'b'; });
term.write('foo', () => {
result = 'a';
});
term.write('bar', () => {
result += 'b';
});
term.write('文', () => {
result += 'c';
r();
@@ -56,8 +60,12 @@ describe('Headless API Tests', function (): void {
it('write - bytes (UTF8) with callback', async () => {
let result: string | undefined;
await new Promise<void>(r => {
term.write(new Uint8Array([102, 111, 111]), () => { result = 'A'; }); // foo
term.write(new Uint8Array([98, 97, 114]), () => { result += 'B'; }); // bar
term.write(new Uint8Array([102, 111, 111]), () => {
result = 'A';
}); // foo
term.write(new Uint8Array([98, 97, 114]), () => {
result += 'B';
}); // bar
term.write(new Uint8Array([230, 150, 135]), () => { // 文
result += 'C';
r();
@@ -79,8 +87,12 @@ describe('Headless API Tests', function (): void {
it('writeln with callback', async () => {
let result: string | undefined;
await new Promise<void>(r => {
term.writeln('foo', () => { result = '1'; });
term.writeln('bar', () => { result += '2'; });
term.writeln('foo', () => {
result = '1';
});
term.writeln('bar', () => {
result += '2';
});
term.writeln('文', () => {
result += '3';
r();
+36 -12
View File
@@ -72,16 +72,36 @@ export class Terminal extends Disposable implements ITerminalApi {
}
}
public get onBell(): IEvent<void> { return this._core.onBell; }
public get onBinary(): IEvent<string> { return this._core.onBinary; }
public get onCursorMove(): IEvent<void> { return this._core.onCursorMove; }
public get onData(): IEvent<string> { return this._core.onData; }
public get onLineFeed(): IEvent<void> { return this._core.onLineFeed; }
public get onRender(): IEvent<{ start: number, end: number }> { return this._core.onRender; }
public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; }
public get onScroll(): IEvent<number> { return this._core.onScroll; }
public get onTitleChange(): IEvent<string> { return this._core.onTitleChange; }
public get onWriteParsed(): IEvent<void> { return this._core.onWriteParsed; }
public get onBell(): IEvent<void> {
return this._core.onBell;
}
public get onBinary(): IEvent<string> {
return this._core.onBinary;
}
public get onCursorMove(): IEvent<void> {
return this._core.onCursorMove;
}
public get onData(): IEvent<string> {
return this._core.onData;
}
public get onLineFeed(): IEvent<void> {
return this._core.onLineFeed;
}
public get onRender(): IEvent<{ start: number, end: number }> {
return this._core.onRender;
}
public get onResize(): IEvent<{ cols: number, rows: number }> {
return this._core.onResize;
}
public get onScroll(): IEvent<number> {
return this._core.onScroll;
}
public get onTitleChange(): IEvent<string> {
return this._core.onTitleChange;
}
public get onWriteParsed(): IEvent<void> {
return this._core.onWriteParsed;
}
public get parser(): IParser {
this._parser ??= new ParserApi(this._core);
@@ -91,8 +111,12 @@ export class Terminal extends Disposable implements ITerminalApi {
this._checkProposedApi();
return new UnicodeApi(this._core);
}
public get rows(): number { return this._core.rows; }
public get cols(): number { return this._core.cols; }
public get rows(): number {
return this._core.rows;
}
public get cols(): number {
return this._core.cols;
}
public get buffer(): IBufferNamespaceApi {
this._buffer ??= this._register(new BufferNamespaceApi(this._core));
return this._buffer;
@@ -24,19 +24,25 @@ function toUtf32(s: string): Uint32Array {
class FastDcsHandler implements IDcsHandler {
public hook(params: IParams): void {}
public put(data: Uint32Array, start: number, end: number): void {}
public unhook(success: boolean): boolean { return true; }
public unhook(success: boolean): boolean {
return true;
}
}
class FastOscHandler implements IOscHandler {
public start(): void {}
public put(data: Uint32Array, start: number, end: number): void {}
public end(success: boolean): boolean { return true; }
public end(success: boolean): boolean {
return true;
}
}
class FastApcHandler implements IApcHandler {
public start(): void {}
public put(data: Uint32Array, start: number, end: number): void {}
public end(success: boolean): boolean { return true; }
public end(success: boolean): boolean {
return true;
}
}
+12 -4
View File
@@ -27,7 +27,9 @@ perfContext('Emitter.fire()', () => {
let sum = 0;
before(() => {
emitter = new Emitter<number>();
emitter.event(e => { sum += e; });
emitter.event(e => {
sum += e;
});
});
new RuntimeCase('', () => {
for (let i = 0; i < ITERATIONS; i++) {
@@ -42,8 +44,12 @@ perfContext('Emitter.fire()', () => {
let sum = 0;
before(() => {
emitter = new Emitter<number>();
emitter.event(e => { sum += e; });
emitter.event(e => { sum += e * 2; });
emitter.event(e => {
sum += e;
});
emitter.event(e => {
sum += e * 2;
});
});
new RuntimeCase('', () => {
for (let i = 0; i < ITERATIONS; i++) {
@@ -59,7 +65,9 @@ perfContext('Emitter.fire()', () => {
before(() => {
emitter = new Emitter<number>();
for (let j = 0; j < 5; j++) {
emitter.event(e => { sum += e; });
emitter.event(e => {
sum += e;
});
}
});
new RuntimeCase('', () => {
+243 -81
View File
@@ -202,76 +202,156 @@ export class TerminalProxy implements ITerminalProxyCustomMethods, PlaywrightApi
// #region Events
private _onBell = new EventEmitter<void>();
public get onBell(): IEvent<void> { return this._onBell.event; }
public get onBell(): IEvent<void> {
return this._onBell.event;
}
private _onBinary = new EventEmitter<string>();
public get onBinary(): IEvent<string> { return this._onBinary.event; }
public get onBinary(): IEvent<string> {
return this._onBinary.event;
}
private _onCursorMove = new EventEmitter<void>();
public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; }
public get onCursorMove(): IEvent<void> {
return this._onCursorMove.event;
}
private _onData = new EventEmitter<string>();
public get onData(): IEvent<string> { return this._onData.event; }
public get onData(): IEvent<string> {
return this._onData.event;
}
private _onKey = new EventEmitter<{ key: string, domEvent: KeyboardEvent }>();
public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> { return this._onKey.event; }
public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> {
return this._onKey.event;
}
private _onLineFeed = new EventEmitter<void>();
public get onLineFeed(): IEvent<void> { return this._onLineFeed.event; }
public get onLineFeed(): IEvent<void> {
return this._onLineFeed.event;
}
private _onRender = new EventEmitter<{ start: number, end: number }>();
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }
public get onRender(): IEvent<{ start: number, end: number }> {
return this._onRender.event;
}
private _onResize = new EventEmitter<{ cols: number, rows: number }>();
public get onResize(): IEvent<{ cols: number, rows: number }> { return this._onResize.event; }
public get onResize(): IEvent<{ cols: number, rows: number }> {
return this._onResize.event;
}
private _onScroll = new EventEmitter<number>();
public get onScroll(): IEvent<number> { return this._onScroll.event; }
public get onScroll(): IEvent<number> {
return this._onScroll.event;
}
private _onDimensionsChange = new EventEmitter<IRenderDimensions>();
public get onDimensionsChange(): IEvent<IRenderDimensions> { return this._onDimensionsChange.event; }
public get onDimensionsChange(): IEvent<IRenderDimensions> {
return this._onDimensionsChange.event;
}
private _onSelectionChange = new EventEmitter<void>();
public get onSelectionChange(): IEvent<void> { return this._onSelectionChange.event; }
public get onSelectionChange(): IEvent<void> {
return this._onSelectionChange.event;
}
private _onTitleChange = new EventEmitter<string>();
public get onTitleChange(): IEvent<string> { return this._onTitleChange.event; }
public get onTitleChange(): IEvent<string> {
return this._onTitleChange.event;
}
private _onWriteParsed = new EventEmitter<void>();
public get onWriteParsed(): IEvent<void> { return this._onWriteParsed.event; }
public get onWriteParsed(): IEvent<void> {
return this._onWriteParsed.event;
}
// #endregion
// #region Simple properties
public get cols(): Promise<number> { return this.evaluate(([term]) => term.cols); }
public get rows(): Promise<number> { return this.evaluate(([term]) => term.rows); }
public get modes(): Promise<IModes> { return this.evaluate(([term]) => term.modes); }
public get dimensions(): Promise<IRenderDimensions | undefined> { return this.evaluate(([term]) => term.dimensions); }
public get cols(): Promise<number> {
return this.evaluate(([term]) => term.cols);
}
public get rows(): Promise<number> {
return this.evaluate(([term]) => term.rows);
}
public get modes(): Promise<IModes> {
return this.evaluate(([term]) => term.modes);
}
public get dimensions(): Promise<IRenderDimensions | undefined> {
return this.evaluate(([term]) => term.dimensions);
}
// #endregion
// #region Complex properties
public get buffer(): TerminalBufferNamespaceProxy { return new TerminalBufferNamespaceProxy(this._page, this); }
public get buffer(): TerminalBufferNamespaceProxy {
return new TerminalBufferNamespaceProxy(this._page, this);
}
/**
* Exposes somewhat unsafe access to internals for testing things difficult to do with the regular
* API
*/
public get core(): TerminalCoreProxy { return new TerminalCoreProxy(this._page, this); }
public get core(): TerminalCoreProxy {
return new TerminalCoreProxy(this._page, this);
}
// #endregion
// #region Proxied methods
public async dispose(): Promise<void> { return this.evaluate(([term]) => term.dispose()); }
public async reset(): Promise<void> { return this.evaluate(([term]) => term.reset()); }
public async clear(): Promise<void> { return this.evaluate(([term]) => term.clear()); }
public async focus(): Promise<void> { return this.evaluate(([term]) => term.focus()); }
public async blur(): Promise<void> { return this.evaluate(([term]) => term.blur()); }
public async hasSelection(): Promise<boolean> { return this.evaluate(([term]) => term.hasSelection()); }
public async getSelection(): Promise<string> { return this.evaluate(([term]) => term.getSelection()); }
public async getSelectionPosition(): Promise<IBufferRange | undefined> { return this.evaluate(([term]) => term.getSelectionPosition()); }
public async selectAll(): Promise<void> { return this.evaluate(([term]) => term.selectAll()); }
public async selectLines(start: number, end: number): Promise<void> { return this._page.evaluate(([term, start, end]) => term.selectLines(start, end), [await this.getHandle(), start, end] as const); }
public async clearSelection(): Promise<void> { return this.evaluate(([term]) => term.clearSelection()); }
public async select(column: number, row: number, length: number): Promise<void> { return this._page.evaluate(([term, column, row, length]) => term.select(column, row, length), [await this.getHandle(), column, row, length] as const); }
public async paste(data: string): Promise<void> { return this._page.evaluate(([term, data]) => term.paste(data), [await this.getHandle(), data] as const); }
public async refresh(start: number, end: number): Promise<void> { return this._page.evaluate(([term, start, end]) => term.refresh(start, end), [await this.getHandle(), start, end] as const); }
public async getOption<T extends keyof ITerminalOptions>(key: T): Promise<ITerminalOptions[T]> { return this._page.evaluate(([term, key]) => term.options[key as T], [await this.getHandle(), key] as const); }
public async setOption<T extends keyof ITerminalOptions>(key: T, value: ITerminalOptions[T]): Promise<any> { return this._page.evaluate(([term, key, value]) => term.options[key as T] = (value as ITerminalOptions[T]), [await this.getHandle(), key, value] as const); }
public async dispose(): Promise<void> {
return this.evaluate(([term]) => term.dispose());
}
public async reset(): Promise<void> {
return this.evaluate(([term]) => term.reset());
}
public async clear(): Promise<void> {
return this.evaluate(([term]) => term.clear());
}
public async focus(): Promise<void> {
return this.evaluate(([term]) => term.focus());
}
public async blur(): Promise<void> {
return this.evaluate(([term]) => term.blur());
}
public async hasSelection(): Promise<boolean> {
return this.evaluate(([term]) => term.hasSelection());
}
public async getSelection(): Promise<string> {
return this.evaluate(([term]) => term.getSelection());
}
public async getSelectionPosition(): Promise<IBufferRange | undefined> {
return this.evaluate(([term]) => term.getSelectionPosition());
}
public async selectAll(): Promise<void> {
return this.evaluate(([term]) => term.selectAll());
}
public async selectLines(start: number, end: number): Promise<void> {
return this._page.evaluate(([term, start, end]) => term.selectLines(start, end), [await this.getHandle(), start, end] as const);
}
public async clearSelection(): Promise<void> {
return this.evaluate(([term]) => term.clearSelection());
}
public async select(column: number, row: number, length: number): Promise<void> {
return this._page.evaluate(([term, column, row, length]) => term.select(column, row, length), [await this.getHandle(), column, row, length] as const);
}
public async paste(data: string): Promise<void> {
return this._page.evaluate(([term, data]) => term.paste(data), [await this.getHandle(), data] as const);
}
public async refresh(start: number, end: number): Promise<void> {
return this._page.evaluate(([term, start, end]) => term.refresh(start, end), [await this.getHandle(), start, end] as const);
}
public async getOption<T extends keyof ITerminalOptions>(key: T): Promise<ITerminalOptions[T]> {
return this._page.evaluate(([term, key]) => term.options[key as T], [await this.getHandle(), key] as const);
}
public async setOption<T extends keyof ITerminalOptions>(key: T, value: ITerminalOptions[T]): Promise<any> {
return this._page.evaluate(([term, key, value]) => term.options[key as T] = (value as ITerminalOptions[T]), [await this.getHandle(), key, value] as const);
}
public async setOptions(value: Partial<ITerminalOptions>): Promise<any> {
return this._page.evaluate(([term, value]) => {
term.options = value;
}, [await this.getHandle(), value] as const);
}
public async scrollToTop(): Promise<void> { return this.evaluate(([term]) => term.scrollToTop()); }
public async scrollToBottom(): Promise<void> { return this.evaluate(([term]) => term.scrollToBottom()); }
public async scrollPages(pageCount: number): Promise<void> { return this._page.evaluate(([term, pageCount]) => term.scrollPages(pageCount), [await this.getHandle(), pageCount] as const); }
public async scrollToLine(line: number): Promise<void> { return this._page.evaluate(([term, line]) => term.scrollToLine(line), [await this.getHandle(), line] as const); }
public async scrollLines(amount: number): Promise<void> { return this._page.evaluate(([term, amount]) => term.scrollLines(amount), [await this.getHandle(), amount] as const); }
public async scrollToTop(): Promise<void> {
return this.evaluate(([term]) => term.scrollToTop());
}
public async scrollToBottom(): Promise<void> {
return this.evaluate(([term]) => term.scrollToBottom());
}
public async scrollPages(pageCount: number): Promise<void> {
return this._page.evaluate(([term, pageCount]) => term.scrollPages(pageCount), [await this.getHandle(), pageCount] as const);
}
public async scrollToLine(line: number): Promise<void> {
return this._page.evaluate(([term, line]) => term.scrollToLine(line), [await this.getHandle(), line] as const);
}
public async scrollLines(amount: number): Promise<void> {
return this._page.evaluate(([term, amount]) => term.scrollLines(amount), [await this.getHandle(), amount] as const);
}
public async write(data: string | Uint8Array): Promise<void> {
return this._page.evaluate(([term, data]) => {
return new Promise(r => term.write(typeof data === 'string' ? data : new Uint8Array(data), r));
@@ -282,11 +362,21 @@ export class TerminalProxy implements ITerminalProxyCustomMethods, PlaywrightApi
return new Promise(r => term.writeln(typeof data === 'string' ? data : new Uint8Array(data), r));
}, [await this.getHandle(), typeof data === 'string' ? data : Array.from(data)] as const);
}
public async input(data: string, wasUserInput: boolean = true): Promise<void> { return this.evaluate(([term]) => term.input(data, wasUserInput)); }
public async resize(cols: number, rows: number): Promise<void> { return this._page.evaluate(([term, cols, rows]) => term.resize(cols, rows), [await this.getHandle(), cols, rows] as const); }
public async registerMarker(y?: number | undefined): Promise<IMarker> { return this._page.evaluate(([term, y]) => term.registerMarker(y), [await this.getHandle(), y] as const); }
public async registerDecoration(decorationOptions: IDecorationOptions): Promise<IDecoration | undefined> { return this._page.evaluate(([term, decorationOptions]) => term.registerDecoration(decorationOptions), [await this.getHandle(), decorationOptions] as const); }
public async clearTextureAtlas(): Promise<void> { return this.evaluate(([term]) => term.clearTextureAtlas()); }
public async input(data: string, wasUserInput: boolean = true): Promise<void> {
return this.evaluate(([term]) => term.input(data, wasUserInput));
}
public async resize(cols: number, rows: number): Promise<void> {
return this._page.evaluate(([term, cols, rows]) => term.resize(cols, rows), [await this.getHandle(), cols, rows] as const);
}
public async registerMarker(y?: number | undefined): Promise<IMarker> {
return this._page.evaluate(([term, y]) => term.registerMarker(y), [await this.getHandle(), y] as const);
}
public async registerDecoration(decorationOptions: IDecorationOptions): Promise<IDecoration | undefined> {
return this._page.evaluate(([term, decorationOptions]) => term.registerDecoration(decorationOptions), [await this.getHandle(), decorationOptions] as const);
}
public async clearTextureAtlas(): Promise<void> {
return this.evaluate(([term]) => term.clearTextureAtlas());
}
// #endregion
public async evaluate<T>(pageFunction: PageFunction<Terminal[], T>): Promise<T> {
@@ -314,9 +404,15 @@ class TerminalBufferNamespaceProxy implements PlaywrightApiProxy<IBufferNamespac
}
public get active(): TerminalBufferProxy { return new TerminalBufferProxy(this._page, this._proxy, this._proxy.evaluateHandle(([term]) => term.buffer.active)); }
public get normal(): TerminalBufferProxy { return new TerminalBufferProxy(this._page, this._proxy, this._proxy.evaluateHandle(([term]) => term.buffer.normal)); }
public get alternate(): TerminalBufferProxy { return new TerminalBufferProxy(this._page, this._proxy, this._proxy.evaluateHandle(([term]) => term.buffer.alternate)); }
public get active(): TerminalBufferProxy {
return new TerminalBufferProxy(this._page, this._proxy, this._proxy.evaluateHandle(([term]) => term.buffer.active));
}
public get normal(): TerminalBufferProxy {
return new TerminalBufferProxy(this._page, this._proxy, this._proxy.evaluateHandle(([term]) => term.buffer.normal));
}
public get alternate(): TerminalBufferProxy {
return new TerminalBufferProxy(this._page, this._proxy, this._proxy.evaluateHandle(([term]) => term.buffer.alternate));
}
}
// TODO: Adopt PlaywrightApiProxy
@@ -328,12 +424,24 @@ class TerminalBufferProxy /* implements EnsureAsyncProperties<IBuffer>*/ {
) {
}
public get type(): Promise<'normal' | 'alternate'> { return this.evaluate(([buffer]) => buffer.type); }
public get cursorY(): Promise<number> { return this.evaluate(([buffer]) => buffer.cursorY); }
public get cursorX(): Promise<number> { return this.evaluate(([buffer]) => buffer.cursorX); }
public get viewportY(): Promise<number> { return this.evaluate(([buffer]) => buffer.viewportY); }
public get baseY(): Promise<number> { return this.evaluate(([buffer]) => buffer.baseY); }
public get length(): Promise<number> { return this.evaluate(([buffer]) => buffer.length); }
public get type(): Promise<'normal' | 'alternate'> {
return this.evaluate(([buffer]) => buffer.type);
}
public get cursorY(): Promise<number> {
return this.evaluate(([buffer]) => buffer.cursorY);
}
public get cursorX(): Promise<number> {
return this.evaluate(([buffer]) => buffer.cursorX);
}
public get viewportY(): Promise<number> {
return this.evaluate(([buffer]) => buffer.viewportY);
}
public get baseY(): Promise<number> {
return this.evaluate(([buffer]) => buffer.baseY);
}
public get length(): Promise<number> {
return this.evaluate(([buffer]) => buffer.length);
}
public async getLine(y: number): Promise<TerminalBufferLine | undefined> {
const lineHandle = await this._page.evaluateHandle(([buffer, y]) => buffer.getLine(y), [await this._handle, y] as const);
const value = await lineHandle.jsonValue();
@@ -356,8 +464,12 @@ class TerminalBufferLine {
) {
}
public get length(): Promise<number> { return this.evaluate(([bufferLine]) => bufferLine.length); }
public get isWrapped(): Promise<boolean> { return this.evaluate(([bufferLine]) => bufferLine.isWrapped); }
public get length(): Promise<number> {
return this.evaluate(([bufferLine]) => bufferLine.length);
}
public get isWrapped(): Promise<boolean> {
return this.evaluate(([bufferLine]) => bufferLine.isWrapped);
}
public translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): Promise<string> {
return this._page.evaluate(([bufferLine, trimRight, startColumn, endColumn]) => {
@@ -387,33 +499,79 @@ class TerminalBufferCell {
) {
}
public getWidth(): Promise<number> { return this.evaluate(([cell]) => cell.getWidth()); }
public getChars(): Promise<string> { return this.evaluate(([cell]) => cell.getChars()); }
public getCode(): Promise<number> { return this.evaluate(([cell]) => cell.getCode()); }
public getWidth(): Promise<number> {
return this.evaluate(([cell]) => cell.getWidth());
}
public getChars(): Promise<string> {
return this.evaluate(([cell]) => cell.getChars());
}
public getCode(): Promise<number> {
return this.evaluate(([cell]) => cell.getCode());
}
public getFgColorMode(): Promise<number> { return this.evaluate(([cell]) => cell.getFgColorMode()); }
public getBgColorMode(): Promise<number> { return this.evaluate(([cell]) => cell.getBgColorMode()); }
public getFgColor(): Promise<number> { return this.evaluate(([cell]) => cell.getFgColor()); }
public getBgColor(): Promise<number> { return this.evaluate(([cell]) => cell.getBgColor()); }
public getFgColorMode(): Promise<number> {
return this.evaluate(([cell]) => cell.getFgColorMode());
}
public getBgColorMode(): Promise<number> {
return this.evaluate(([cell]) => cell.getBgColorMode());
}
public getFgColor(): Promise<number> {
return this.evaluate(([cell]) => cell.getFgColor());
}
public getBgColor(): Promise<number> {
return this.evaluate(([cell]) => cell.getBgColor());
}
public isBold(): Promise<number> { return this.evaluate(([cell]) => cell.isBold()); }
public isItalic(): Promise<number> { return this.evaluate(([cell]) => cell.isItalic()); }
public isDim(): Promise<number> { return this.evaluate(([cell]) => cell.isDim()); }
public isUnderline(): Promise<number> { return this.evaluate(([cell]) => cell.isUnderline()); }
public isBlink(): Promise<number> { return this.evaluate(([cell]) => cell.isBlink()); }
public isInverse(): Promise<number> { return this.evaluate(([cell]) => cell.isInverse()); }
public isInvisible(): Promise<number> { return this.evaluate(([cell]) => cell.isInvisible()); }
public isStrikethrough(): Promise<number> { return this.evaluate(([cell]) => cell.isStrikethrough()); }
public isOverline(): Promise<number> { return this.evaluate(([cell]) => cell.isOverline()); }
public isBold(): Promise<number> {
return this.evaluate(([cell]) => cell.isBold());
}
public isItalic(): Promise<number> {
return this.evaluate(([cell]) => cell.isItalic());
}
public isDim(): Promise<number> {
return this.evaluate(([cell]) => cell.isDim());
}
public isUnderline(): Promise<number> {
return this.evaluate(([cell]) => cell.isUnderline());
}
public isBlink(): Promise<number> {
return this.evaluate(([cell]) => cell.isBlink());
}
public isInverse(): Promise<number> {
return this.evaluate(([cell]) => cell.isInverse());
}
public isInvisible(): Promise<number> {
return this.evaluate(([cell]) => cell.isInvisible());
}
public isStrikethrough(): Promise<number> {
return this.evaluate(([cell]) => cell.isStrikethrough());
}
public isOverline(): Promise<number> {
return this.evaluate(([cell]) => cell.isOverline());
}
public isFgRGB(): Promise<boolean> { return this.evaluate(([cell]) => cell.isFgRGB()); }
public isBgRGB(): Promise<boolean> { return this.evaluate(([cell]) => cell.isBgRGB()); }
public isFgPalette(): Promise<boolean> { return this.evaluate(([cell]) => cell.isFgPalette()); }
public isBgPalette(): Promise<boolean> { return this.evaluate(([cell]) => cell.isBgPalette()); }
public isFgDefault(): Promise<boolean> { return this.evaluate(([cell]) => cell.isFgDefault()); }
public isBgDefault(): Promise<boolean> { return this.evaluate(([cell]) => cell.isBgDefault()); }
public isFgRGB(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isFgRGB());
}
public isBgRGB(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isBgRGB());
}
public isFgPalette(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isFgPalette());
}
public isBgPalette(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isBgPalette());
}
public isFgDefault(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isFgDefault());
}
public isBgDefault(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isBgDefault());
}
public isAttributeDefault(): Promise<boolean> { return this.evaluate(([cell]) => cell.isAttributeDefault()); }
public isAttributeDefault(): Promise<boolean> {
return this.evaluate(([cell]) => cell.isAttributeDefault());
}
public async evaluate<T>(pageFunction: PageFunction<IBufferCell[], T>): Promise<T> {
return this._page.evaluate(pageFunction, [this._handle]);
@@ -427,8 +585,12 @@ class TerminalCoreProxy {
) {
}
public get isDisposed(): Promise<boolean> { return this.evaluate(([core]) => (core as any)._isDisposed); }
public get renderDimensions(): Promise<IRenderDimensionsInternal> { return this.evaluate(([core]) => ((core as any)._renderService as IRenderService).dimensions); }
public get isDisposed(): Promise<boolean> {
return this.evaluate(([core]) => (core as any)._isDisposed);
}
public get renderDimensions(): Promise<IRenderDimensionsInternal> {
return this.evaluate(([core]) => ((core as any)._renderService as IRenderService).dimensions);
}
public async triggerBinaryEvent(data: string): Promise<void> {
return this._page.evaluate(([core, data]) => core.coreService.triggerBinaryEvent(data), [await this._getCoreHandle(), data] as const);