From 0aeeebdd646b7ddd9b990565669778cf46b42dfa Mon Sep 17 00:00:00 2001 From: Simon Lamon <32477463+silamon@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:05:42 +0000 Subject: [PATCH 01/56] Devcontainer update --- .devcontainer/devcontainer.json | 8 +++++--- .nvmrc | 2 +- .vscode/launch.json | 2 +- package.json | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c09a29bf..9c83cc4c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,13 +1,15 @@ { "name": "xterm.js", - "image": "mcr.microsoft.com/devcontainers/typescript-node:0-18-buster", + "image": "mcr.microsoft.com/devcontainers/typescript-node:18-bookworm", "features": { - "ghcr.io/devcontainers/features/node:1": {} // yarn + "ghcr.io/devcontainers/features/node:1": { + "version": 18 + } // yarn }, "forwardPorts": [ 3000 ], - "postCreateCommand": "yarn install", + "postCreateCommand": "yarn install && yarn setup", "customizations": { "vscode": { "extensions": [ diff --git a/.nvmrc b/.nvmrc index b6a7d89c..3c032078 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16 +18 diff --git a/.vscode/launch.json b/.vscode/launch.json index 5dbd01ce..eaa5e12e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -61,7 +61,7 @@ "runtimeExecutable": "npm", "runtimeArgs": ["start"], "stopOnEntry": true, - "runtimeVersion": "16", + "runtimeVersion": "18", "serverReadyAction": { "action": "openExternally", "pattern": "App listening to (http://.*?:[0-9]+)" diff --git a/package.json b/package.json index d0510e5d..28e9952b 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "cross-env": "^7.0.3", "deep-equal": "^2.0.5", "eslint": "^8.45.0", - "eslint-plugin-jsdoc": "^39.3.6", + "eslint-plugin-jsdoc": "^46.8.2", "express": "^4.17.1", "express-ws": "^5.0.2", "glob": "^7.2.0", From 5c1d9b28cd411ee1c1787ddc971b7bdc9c418b80 Mon Sep 17 00:00:00 2001 From: Simon Lamon <32477463+silamon@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:10:36 +0000 Subject: [PATCH 02/56] Update yarn lock --- yarn.lock | 69 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/yarn.lock b/yarn.lock index a0cb39da..5f25390b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -265,14 +265,14 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@es-joy/jsdoccomment@~0.36.1": - version "0.36.1" - resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz#c37db40da36e4b848da5fd427a74bae3b004a30f" - integrity sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg== +"@es-joy/jsdoccomment@~0.40.1": + version "0.40.1" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz#13acd77fb372ed1c83b7355edd865a3b370c9ec4" + integrity sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg== dependencies: - comment-parser "1.3.1" - esquery "^1.4.0" - jsdoc-type-pratt-parser "~3.1.0" + comment-parser "1.4.0" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -1029,6 +1029,11 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== +are-docs-informative@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" + integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -1149,6 +1154,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1355,10 +1365,10 @@ commander@^7.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -comment-parser@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" - integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== +comment-parser@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.0.tgz#0f8c560f59698193854f12884c20c0e39a26d32c" + integrity sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw== commondir@^1.0.1: version "1.0.1" @@ -1666,17 +1676,19 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-plugin-jsdoc@^39.3.6: - version "39.9.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.9.1.tgz#e9ce1723411fd7ea0933b3ef0dd02156ae3068e2" - integrity sha512-Rq2QY6BZP2meNIs48aZ3GlIlJgBqFCmR55+UBvaDkA3ZNQ0SvQXOs2QKkubakEijV8UbIVbVZKsOVN8G3MuqZw== +eslint-plugin-jsdoc@^46.8.2: + version "46.8.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz#3e6b1c93e91e38fe01874d45da121b56393c54a5" + integrity sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ== dependencies: - "@es-joy/jsdoccomment" "~0.36.1" - comment-parser "1.3.1" + "@es-joy/jsdoccomment" "~0.40.1" + are-docs-informative "^0.0.2" + comment-parser "1.4.0" debug "^4.3.4" escape-string-regexp "^4.0.0" - esquery "^1.4.0" - semver "^7.3.8" + esquery "^1.5.0" + is-builtin-module "^3.2.1" + semver "^7.5.4" spdx-expression-parse "^3.0.1" eslint-scope@5.1.1: @@ -1757,7 +1769,7 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0, esquery@^1.4.2: +esquery@^1.4.2, esquery@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -2341,6 +2353,13 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -2599,10 +2618,10 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -jsdoc-type-pratt-parser@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz#a4a56bdc6e82e5865ffd9febc5b1a227ff28e67e" - integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw== +jsdoc-type-pratt-parser@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" + integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== jsdom@^18.0.1: version "18.1.1" @@ -3348,7 +3367,7 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.4, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^7.3.4, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== From b1d9b4751deffd1669b3cbf7b9384619ccd13dca Mon Sep 17 00:00:00 2001 From: tisilent Date: Mon, 1 Jan 2024 22:25:54 +0800 Subject: [PATCH 03/56] Check after updating the SelectionRenderModel --- src/browser/renderer/dom/DomRenderer.ts | 8 +++----- test/playwright/SharedRendererTests.ts | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 1549b130..439f8457 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -324,6 +324,9 @@ export class DomRenderer extends Disposable implements IRenderer { } this._selectionRenderModel.update(this._terminal, start, end, columnSelectMode); + if (!this._selectionRenderModel.hasSelection) { + return; + } // Translate from buffer position to viewport position const viewportStartRow = this._selectionRenderModel.viewportStartRow; @@ -331,11 +334,6 @@ export class DomRenderer extends Disposable implements IRenderer { const viewportCappedStartRow = this._selectionRenderModel.viewportCappedStartRow; const viewportCappedEndRow = this._selectionRenderModel.viewportCappedEndRow; - // No need to draw the selection - if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) { - return; - } - // Create the selections const documentFragment = this._document.createDocumentFragment(); diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index 657fba44..5871e8e4 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -1128,6 +1128,20 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [0, 0, 0, 255]); // inverse foreground of '■' should be default await pollFor(ctx.value.page, () => getCellColor(ctx.value, 2, 1), [0, 0, 255, 255]); // inverse background of ' ' should be decoration bg override }); + test('#4911 The selection should not be displayed if it is not within the scope of the viewport.', async () => { + const theme: ITheme = { + selectionBackground: '#FF0000' + }; + await ctx.value.page.evaluate(`window.term.options.theme = ${JSON.stringify(theme)};`); + for (let index = 0; index < 160; index++) { + await ctx.value.proxy.writeln(``); + } + await ctx.value.proxy.scrollToBottom(); + const rows = await ctx.value.proxy.buffer.active.length; + await ctx.value.proxy.selectLines(rows - 1, rows - 1); + await ctx.value.proxy.scrollLines(-2); + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [0, 0, 0, 255]); + }); }); test.describe('regression tests', () => { From 750f3179dec28a3a8620b6856ce2d898b70ece5e Mon Sep 17 00:00:00 2001 From: tisilent Date: Mon, 1 Jan 2024 22:48:39 +0800 Subject: [PATCH 04/56] move test --- test/playwright/SharedRendererTests.ts | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index 5871e8e4..322e03f4 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -1128,20 +1128,6 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [0, 0, 0, 255]); // inverse foreground of '■' should be default await pollFor(ctx.value.page, () => getCellColor(ctx.value, 2, 1), [0, 0, 255, 255]); // inverse background of ' ' should be decoration bg override }); - test('#4911 The selection should not be displayed if it is not within the scope of the viewport.', async () => { - const theme: ITheme = { - selectionBackground: '#FF0000' - }; - await ctx.value.page.evaluate(`window.term.options.theme = ${JSON.stringify(theme)};`); - for (let index = 0; index < 160; index++) { - await ctx.value.proxy.writeln(``); - } - await ctx.value.proxy.scrollToBottom(); - const rows = await ctx.value.proxy.buffer.active.length; - await ctx.value.proxy.selectLines(rows - 1, rows - 1); - await ctx.value.proxy.scrollLines(-2); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [0, 0, 0, 255]); - }); }); test.describe('regression tests', () => { @@ -1246,6 +1232,20 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows), [0, 0, 0, 255]); await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, rows, CellColorPosition.FIRST), [0, 0, 255, 255]); }); + test('#4917 The selection should not be displayed if it is not within the scope of the viewport.', async () => { + const theme: ITheme = { + selectionBackground: '#FF0000' + }; + await ctx.value.page.evaluate(`window.term.options.theme = ${JSON.stringify(theme)};`); + for (let index = 0; index < 160; index++) { + await ctx.value.proxy.writeln(``); + } + await ctx.value.proxy.scrollToBottom(); + const rows = await ctx.value.proxy.buffer.active.length; + await ctx.value.proxy.selectLines(rows - 1, rows - 1); + await ctx.value.proxy.scrollLines(-2); + await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [0, 0, 0, 255]); + }); }); } From b0667aacca4cc1d0c14d57bb6f51333bd03fecea Mon Sep 17 00:00:00 2001 From: Simon Siefke Date: Thu, 4 Jan 2024 22:05:23 +0100 Subject: [PATCH 05/56] fix: memory leak in CoreBrowserService --- src/browser/services/CoreBrowserService.ts | 28 ++++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts index 575b62b6..9999ceec 100644 --- a/src/browser/services/CoreBrowserService.ts +++ b/src/browser/services/CoreBrowserService.ts @@ -3,17 +3,17 @@ * @license MIT */ -import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle'; -import { ICoreBrowserService } from './Services'; -import { EventEmitter, forwardEvent } from 'common/EventEmitter'; -import { addDisposableDomListener } from 'browser/Lifecycle'; +import { Disposable, MutableDisposable, toDisposable } from "common/Lifecycle"; +import { ICoreBrowserService } from "./Services"; +import { EventEmitter, forwardEvent } from "common/EventEmitter"; +import { addDisposableDomListener } from "browser/Lifecycle"; export class CoreBrowserService extends Disposable implements ICoreBrowserService { public serviceBrand: undefined; private _isFocused = false; private _cachedIsFocused: boolean | undefined = undefined; - private _screenDprMonitor = new ScreenDprMonitor(this._window); + private _screenDprMonitor = this.register(new ScreenDprMonitor(this._window)); private readonly _onDprChange = this.register(new EventEmitter()); public readonly onDprChange = this._onDprChange.event; @@ -28,11 +28,11 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic super(); // Monitor device pixel ratio - this.register(this.onWindowChange(w => this._screenDprMonitor.setWindow(w))); + this.register(this.onWindowChange((w) => this._screenDprMonitor.setWindow(w))); this.register(forwardEvent(this._screenDprMonitor.onDprChange, this._onDprChange)); - this._textarea.addEventListener('focus', () => this._isFocused = true); - this._textarea.addEventListener('blur', () => this._isFocused = false); + this._textarea.addEventListener("focus", () => (this._isFocused = true)); + this._textarea.addEventListener("blur", () => (this._isFocused = false)); } public get window(): Window & typeof globalThis { @@ -53,13 +53,12 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic public get isFocused(): boolean { if (this._cachedIsFocused === undefined) { this._cachedIsFocused = this._isFocused && this._textarea.ownerDocument.hasFocus(); - queueMicrotask(() => this._cachedIsFocused = undefined); + queueMicrotask(() => (this._cachedIsFocused = undefined)); } return this._cachedIsFocused; } } - /** * The screen device pixel ratio monitor allows listening for when the * window.devicePixelRatio value changes. This is done not with polling but with @@ -94,7 +93,6 @@ class ScreenDprMonitor extends Disposable { this.register(toDisposable(() => this.clearListener())); } - public setWindow(parentWindow: Window): void { this._parentWindow = parentWindow; this._setWindowResizeListener(); @@ -102,7 +100,9 @@ class ScreenDprMonitor extends Disposable { } private _setWindowResizeListener(): void { - this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, 'resize', () => this._setDprAndFireIfDiffers()); + this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, "resize", () => + this._setDprAndFireIfDiffers() + ); } private _setDprAndFireIfDiffers(): void { @@ -122,7 +122,9 @@ class ScreenDprMonitor extends Disposable { // Add listeners for new DPR this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio; - this._resolutionMediaMatchList = this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`); + this._resolutionMediaMatchList = this._parentWindow.matchMedia( + `screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)` + ); this._resolutionMediaMatchList.addListener(this._outerListener); } From 9e98b631da085b099af25634bca7100d35162806 Mon Sep 17 00:00:00 2001 From: Simon Siefke Date: Thu, 4 Jan 2024 22:29:12 +0100 Subject: [PATCH 06/56] use disposable for text area listeners --- src/browser/services/CoreBrowserService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts index 9999ceec..8a400ffd 100644 --- a/src/browser/services/CoreBrowserService.ts +++ b/src/browser/services/CoreBrowserService.ts @@ -31,8 +31,8 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic this.register(this.onWindowChange((w) => this._screenDprMonitor.setWindow(w))); this.register(forwardEvent(this._screenDprMonitor.onDprChange, this._onDprChange)); - this._textarea.addEventListener("focus", () => (this._isFocused = true)); - this._textarea.addEventListener("blur", () => (this._isFocused = false)); + this.register(addDisposableDomListener(this._textarea, 'focus', () => (this._isFocused = true))) + this.register(addDisposableDomListener(this._textarea, 'blur', () => (this._isFocused = false))) } public get window(): Window & typeof globalThis { From f4869896977168bd608e7f878509bcde48559012 Mon Sep 17 00:00:00 2001 From: Simon Siefke Date: Thu, 4 Jan 2024 22:32:59 +0100 Subject: [PATCH 07/56] fix formatting --- src/browser/services/CoreBrowserService.ts | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts index 8a400ffd..6b2c13c3 100644 --- a/src/browser/services/CoreBrowserService.ts +++ b/src/browser/services/CoreBrowserService.ts @@ -3,10 +3,10 @@ * @license MIT */ -import { Disposable, MutableDisposable, toDisposable } from "common/Lifecycle"; -import { ICoreBrowserService } from "./Services"; -import { EventEmitter, forwardEvent } from "common/EventEmitter"; -import { addDisposableDomListener } from "browser/Lifecycle"; +import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle'; +import { ICoreBrowserService } from './Services'; +import { EventEmitter, forwardEvent } from 'common/EventEmitter'; +import { addDisposableDomListener } from 'browser/Lifecycle'; export class CoreBrowserService extends Disposable implements ICoreBrowserService { public serviceBrand: undefined; @@ -28,11 +28,15 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic super(); // Monitor device pixel ratio - this.register(this.onWindowChange((w) => this._screenDprMonitor.setWindow(w))); + this.register(this.onWindowChange(w => this._screenDprMonitor.setWindow(w))); this.register(forwardEvent(this._screenDprMonitor.onDprChange, this._onDprChange)); - this.register(addDisposableDomListener(this._textarea, 'focus', () => (this._isFocused = true))) - this.register(addDisposableDomListener(this._textarea, 'blur', () => (this._isFocused = false))) + this.register( + addDisposableDomListener(this._textarea, 'focus', () => (this._isFocused = true)) + ); + this.register( + addDisposableDomListener(this._textarea, 'blur', () => (this._isFocused = false)) + ); } public get window(): Window & typeof globalThis { @@ -53,12 +57,13 @@ export class CoreBrowserService extends Disposable implements ICoreBrowserServic public get isFocused(): boolean { if (this._cachedIsFocused === undefined) { this._cachedIsFocused = this._isFocused && this._textarea.ownerDocument.hasFocus(); - queueMicrotask(() => (this._cachedIsFocused = undefined)); + queueMicrotask(() => this._cachedIsFocused = undefined); } return this._cachedIsFocused; } } + /** * The screen device pixel ratio monitor allows listening for when the * window.devicePixelRatio value changes. This is done not with polling but with @@ -93,6 +98,7 @@ class ScreenDprMonitor extends Disposable { this.register(toDisposable(() => this.clearListener())); } + public setWindow(parentWindow: Window): void { this._parentWindow = parentWindow; this._setWindowResizeListener(); @@ -100,7 +106,7 @@ class ScreenDprMonitor extends Disposable { } private _setWindowResizeListener(): void { - this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, "resize", () => + this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, 'resize', () => this._setDprAndFireIfDiffers() ); } @@ -122,9 +128,7 @@ class ScreenDprMonitor extends Disposable { // Add listeners for new DPR this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio; - this._resolutionMediaMatchList = this._parentWindow.matchMedia( - `screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)` - ); + this._resolutionMediaMatchList = this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`); this._resolutionMediaMatchList.addListener(this._outerListener); } From 819254e5403cc4a1adb8b5be39eb0c0af2d22460 Mon Sep 17 00:00:00 2001 From: Simon Siefke Date: Thu, 4 Jan 2024 22:33:39 +0100 Subject: [PATCH 08/56] fix formatting --- src/browser/services/CoreBrowserService.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts index 6b2c13c3..a6c066b2 100644 --- a/src/browser/services/CoreBrowserService.ts +++ b/src/browser/services/CoreBrowserService.ts @@ -106,9 +106,7 @@ class ScreenDprMonitor extends Disposable { } private _setWindowResizeListener(): void { - this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, 'resize', () => - this._setDprAndFireIfDiffers() - ); + this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, 'resize', () => this._setDprAndFireIfDiffers()); } private _setDprAndFireIfDiffers(): void { From 815758529d6d4ad34164b942e03de349a13d8a16 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:21:30 -0600 Subject: [PATCH 09/56] Update global object fix --- addons/addon-attach/webpack.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/addon-attach/webpack.config.js b/addons/addon-attach/webpack.config.js index 599bb142..a882928b 100644 --- a/addons/addon-attach/webpack.config.js +++ b/addons/addon-attach/webpack.config.js @@ -26,6 +26,8 @@ module.exports = { path: path.resolve('./lib'), library: addonName, libraryTarget: 'umd' + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From 7f7de14e6f3e17b0ab7ecf77a1c1a0242e0b5d42 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:23:33 -0600 Subject: [PATCH 10/56] Add comma --- addons/addon-attach/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/addon-attach/webpack.config.js b/addons/addon-attach/webpack.config.js index a882928b..3599a977 100644 --- a/addons/addon-attach/webpack.config.js +++ b/addons/addon-attach/webpack.config.js @@ -25,7 +25,7 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', // Force usage of globalThis instead of global / self. (This is cross-env compatible) globalObject: 'globalThis', }, From 1a67241f67f68831e487c75cfe76ae65326362d9 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:23:57 -0600 Subject: [PATCH 11/56] Update global object fix --- addons/addon-canvas/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-canvas/webpack.config.js b/addons/addon-canvas/webpack.config.js index 9daa08f9..e0c7fde2 100644 --- a/addons/addon-canvas/webpack.config.js +++ b/addons/addon-canvas/webpack.config.js @@ -33,7 +33,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From f84fff5f873b44438115183d8058b66bf2bdc867 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:24:15 -0600 Subject: [PATCH 12/56] Update global object fix --- addons/addon-fit/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-fit/webpack.config.js b/addons/addon-fit/webpack.config.js index e220668c..aebb523a 100644 --- a/addons/addon-fit/webpack.config.js +++ b/addons/addon-fit/webpack.config.js @@ -25,7 +25,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From 8d6fff7000158cc3f118b921f4814b0eda1b17f9 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:27:44 -0600 Subject: [PATCH 13/56] Update webpack.config.js global object fix --- addons/addon-image/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-image/webpack.config.js b/addons/addon-image/webpack.config.js index b4283b66..239ebd24 100644 --- a/addons/addon-image/webpack.config.js +++ b/addons/addon-image/webpack.config.js @@ -33,7 +33,9 @@ const addon = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From 46baff84593bbc3c2854f4743a45e5057e9ccfa8 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:28:05 -0600 Subject: [PATCH 14/56] Update webpack.config.js global object fix --- addons/addon-ligatures/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-ligatures/webpack.config.js b/addons/addon-ligatures/webpack.config.js index 6ec7f42d..f9e9f347 100644 --- a/addons/addon-ligatures/webpack.config.js +++ b/addons/addon-ligatures/webpack.config.js @@ -25,7 +25,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production', externals: { From 072cd029e424891f34c109a17b7c8c127763f8ef Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:28:21 -0600 Subject: [PATCH 15/56] Update webpack.config.js global object fix --- addons/addon-search/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-search/webpack.config.js b/addons/addon-search/webpack.config.js index a770f93f..78580548 100644 --- a/addons/addon-search/webpack.config.js +++ b/addons/addon-search/webpack.config.js @@ -32,7 +32,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From d8f96ab9c744032f6f6deb91dc5fe4c8ce9e5a32 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:29:20 -0600 Subject: [PATCH 16/56] Update webpack.config.js global object fix `this` might be okay, I'm not actually sure, but xterm.js uses `globalThis` and so I think consistency is better maybe? --- addons/addon-serialize/webpack.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/addon-serialize/webpack.config.js b/addons/addon-serialize/webpack.config.js index bd08ca37..837a73a3 100644 --- a/addons/addon-serialize/webpack.config.js +++ b/addons/addon-serialize/webpack.config.js @@ -34,7 +34,8 @@ module.exports = { path: path.resolve('./lib'), library: addonName, libraryTarget: 'umd', - globalObject: 'this' + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From 330d7b3100c79bc5f890ca0c28bfef67d55db33c Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:29:33 -0600 Subject: [PATCH 17/56] Update webpack.config.js global object fix --- addons/addon-unicode-graphemes/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-unicode-graphemes/webpack.config.js b/addons/addon-unicode-graphemes/webpack.config.js index 6a80bdea..1ebaecaa 100644 --- a/addons/addon-unicode-graphemes/webpack.config.js +++ b/addons/addon-unicode-graphemes/webpack.config.js @@ -32,7 +32,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From 693ec1b2bcaae2f05496f4a696ec39997230cdeb Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:29:48 -0600 Subject: [PATCH 18/56] Update webpack.config.js global object fix --- addons/addon-unicode11/webpack.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/addon-unicode11/webpack.config.js b/addons/addon-unicode11/webpack.config.js index 1913481d..746d2581 100644 --- a/addons/addon-unicode11/webpack.config.js +++ b/addons/addon-unicode11/webpack.config.js @@ -33,7 +33,8 @@ module.exports = { path: path.resolve('./lib'), library: addonName, libraryTarget: 'umd', - globalObject: 'this' + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From 8696cf8789575cfabb1b9b364b6b3c1a085e848d Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:29:59 -0600 Subject: [PATCH 19/56] Update webpack.config.js global object fix --- addons/addon-web-links/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-web-links/webpack.config.js b/addons/addon-web-links/webpack.config.js index 4484dbf6..e8dcecef 100644 --- a/addons/addon-web-links/webpack.config.js +++ b/addons/addon-web-links/webpack.config.js @@ -25,7 +25,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From c0044dc4a5f07d04d1da1b0346bdef09869fabd5 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:30:10 -0600 Subject: [PATCH 20/56] Update webpack.config.js global object fix --- addons/addon-webgl/webpack.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/addon-webgl/webpack.config.js b/addons/addon-webgl/webpack.config.js index f31ffd51..7365acff 100644 --- a/addons/addon-webgl/webpack.config.js +++ b/addons/addon-webgl/webpack.config.js @@ -33,7 +33,9 @@ module.exports = { filename: mainFile, path: path.resolve('./lib'), library: addonName, - libraryTarget: 'umd' + libraryTarget: 'umd', + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, mode: 'production' }; From d5827ec77d044af9f8cc3e8719710fb93bd1abb4 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:54:27 -0600 Subject: [PATCH 21/56] Update webpack.config.headless.js --- webpack.config.headless.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/webpack.config.headless.js b/webpack.config.headless.js index 9e9099cd..12e7484d 100644 --- a/webpack.config.headless.js +++ b/webpack.config.headless.js @@ -39,8 +39,10 @@ const config = { path: path.resolve('./headless/lib-headless'), library: { type: 'commonjs' - } + }, + // Force usage of globalThis instead of global / self. (This is cross-env compatible) + globalObject: 'globalThis', }, - mode: 'production' + mode: 'production', }; module.exports = config; From 67e8e60a6990621ba32b3ee12f89395a070dd495 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:55:18 -0600 Subject: [PATCH 22/56] Update webpack.config.headless.js --- webpack.config.headless.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.config.headless.js b/webpack.config.headless.js index 12e7484d..5c8deb16 100644 --- a/webpack.config.headless.js +++ b/webpack.config.headless.js @@ -43,6 +43,6 @@ const config = { // Force usage of globalThis instead of global / self. (This is cross-env compatible) globalObject: 'globalThis', }, - mode: 'production', + mode: 'production' }; module.exports = config; From d83f442cffc30ecfe4874c0ce27f817451df8262 Mon Sep 17 00:00:00 2001 From: octoclonius <25781800+octoclonius@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:57:38 -0600 Subject: [PATCH 23/56] Update webpack.config.headless.js --- webpack.config.headless.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.config.headless.js b/webpack.config.headless.js index 5c8deb16..12e7484d 100644 --- a/webpack.config.headless.js +++ b/webpack.config.headless.js @@ -43,6 +43,6 @@ const config = { // Force usage of globalThis instead of global / self. (This is cross-env compatible) globalObject: 'globalThis', }, - mode: 'production' + mode: 'production', }; module.exports = config; From 9107ee905a66c9a3e22b6ae6f54e8ea87c8616af Mon Sep 17 00:00:00 2001 From: Homa Wong Date: Fri, 16 Feb 2024 18:08:58 -0800 Subject: [PATCH 24/56] Update xterm.d.ts Fix doc typo --- typings/xterm.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index d957d655..9ba11bb3 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -48,7 +48,7 @@ declare module '@xterm/xterm' { /** * When enabled the cursor will be set to the beginning of the next line * with every new line. This is equivalent to sending '\r\n' for each '\n'. - * Normally the termios settings of the underlying PTY deals with the + * Normally the terminal settings of the underlying PTY deals with the * translation of '\n' to '\r\n' and this setting should not be used. If you * deal with data from a non-PTY related source, this settings might be * useful. From 88bfc4ad9ccba4e4457f84fdb42f832bc04f15c9 Mon Sep 17 00:00:00 2001 From: Homa Wong Date: Mon, 19 Feb 2024 17:18:52 -0800 Subject: [PATCH 25/56] add termios link --- typings/xterm.d.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 9ba11bb3..d2fa9f99 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -47,11 +47,13 @@ declare module '@xterm/xterm' { /** * When enabled the cursor will be set to the beginning of the next line - * with every new line. This is equivalent to sending '\r\n' for each '\n'. - * Normally the terminal settings of the underlying PTY deals with the - * translation of '\n' to '\r\n' and this setting should not be used. If you + * with every new line. This is equivalent to sending `\r\n` for each `\n`. + * Normally the settings of the underlying PTY (`termios`) deal with the + * translation of `\n` to `\r\n` and this setting should not be used. If you * deal with data from a non-PTY related source, this settings might be * useful. + * + * @see https://pubs.opengroup.org/onlinepubs/007904975/basedefs/termios.h.html */ convertEol?: boolean; From fe22671a6edfefb38727e1c2d9346baea1e7ad9a Mon Sep 17 00:00:00 2001 From: tisilent Date: Wed, 6 Mar 2024 17:03:25 +0800 Subject: [PATCH 26/56] Clear timer when dispose --- src/browser/Viewport.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index a8e1a498..cea2ca8f 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -49,6 +49,8 @@ export class Viewport extends Disposable implements IViewport { target: -1 }; + private _ensureTimeout: number; + private readonly _onRequestScrollLines = this.register(new EventEmitter<{ amount: number, suppressScrollEvent: boolean }>()); public readonly onRequestScrollLines = this._onRequestScrollLines.event; @@ -81,7 +83,7 @@ export class Viewport extends Disposable implements IViewport { this.register(this._optionsService.onSpecificOptionChange('scrollback', () => this.syncScrollArea())); // Perform this async to ensure the ICharSizeService is ready. - setTimeout(() => this.syncScrollArea()); + this._ensureTimeout = window.setTimeout(() => this.syncScrollArea()); } private _handleThemeChange(colors: ReadonlyColorSet): void { @@ -398,4 +400,8 @@ export class Viewport extends Disposable implements IViewport { this._viewportElement.scrollTop += deltaY; return this._bubbleScroll(ev, deltaY); } + + public dispose(): void { + clearTimeout(this._ensureTimeout); + } } From 553b9f261a2f231d4e16f27d6e745592432c0b94 Mon Sep 17 00:00:00 2001 From: Knox Lively Date: Wed, 6 Mar 2024 23:56:04 -0700 Subject: [PATCH 27/56] adding Wave Terminal to the README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b055ea7b..5f4a786a 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,7 @@ Xterm.js is used in several world-class applications to provide great terminal e - [**Cloudtutor.io**](https://cloudtutor.io): innovative online learning platform that offers users access to an interactive lab. - [**Helix Editor Playground**](https://github.com/tomgroenwoldt/helix-editor-playground): Online playground for the terminal based helix editor. - [**Coder**](https://github.com/coder/coder): Self-Hosted Remote Development Environments +- [**Wave Terminal**](https://waveterm.dev): An open-source, ai-native, terminal built for seamless workflows. - [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. Note: Please add any new contributions to the end of the list only. From 47409f39f684c417717d885b2cba56dd918d591a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:05:45 -0700 Subject: [PATCH 28/56] Set up shared context on browser even if process exists Fixes #4995 --- src/common/Color.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/common/Color.ts b/src/common/Color.ts index 5ec2d87d..b7b3ff47 100644 --- a/src/common/Color.ts +++ b/src/common/Color.ts @@ -3,7 +3,6 @@ * @license MIT */ -import { isNode } from 'common/Platform'; import { IColor, IColorRGB } from 'common/Types'; let $r = 0; @@ -117,9 +116,10 @@ export namespace color { * '#rrggbbaa'). */ export namespace css { + // Attempt to set get the shared canvas context let $ctx: CanvasRenderingContext2D | undefined; let $litmusColor: CanvasGradient | undefined; - if (!isNode) { + try { // This is guaranteed to run in the first window, so document should be correct const canvas = document.createElement('canvas'); canvas.width = 1; @@ -133,6 +133,9 @@ export namespace css { $litmusColor = $ctx.createLinearGradient(0, 0, 1, 1); } } + catch { + // noop + } /** * Converts a css string to an IColor, this should handle all valid CSS color strings and will From 37efeeb044c55ab5debe60f9ae92cdd280285a06 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:08:54 -0700 Subject: [PATCH 29/56] Make process node check stricter Fixes #4995 --- src/common/Platform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Platform.ts b/src/common/Platform.ts index 1007fc0a..4102f20c 100644 --- a/src/common/Platform.ts +++ b/src/common/Platform.ts @@ -14,7 +14,7 @@ interface INavigator { declare const navigator: INavigator; declare const process: unknown; -export const isNode = (typeof process !== 'undefined') ? true : false; +export const isNode = (typeof process !== 'undefined' && 'title' in (process as any)) ? true : false; const userAgent = (isNode) ? 'node' : navigator.userAgent; const platform = (isNode) ? 'node' : navigator.platform; From 4071f41f525016ff9f02e11b281f39a47258b909 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:16:31 -0700 Subject: [PATCH 30/56] Don't rescale unless it exceeds 25% of following cell Fixes #5005 --- addons/addon-canvas/src/BaseRenderLayer.ts | 11 ++--------- addons/addon-webgl/src/GlyphRenderer.ts | 11 ++--------- src/browser/renderer/shared/RendererUtils.ts | 5 +++-- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/addons/addon-canvas/src/BaseRenderLayer.ts b/addons/addon-canvas/src/BaseRenderLayer.ts index 0868ba8e..cd3cfa1f 100644 --- a/addons/addon-canvas/src/BaseRenderLayer.ts +++ b/addons/addon-canvas/src/BaseRenderLayer.ts @@ -8,7 +8,7 @@ import { CellColorResolver } from 'browser/renderer/shared/CellColorResolver'; import { acquireTextureAtlas } from 'browser/renderer/shared/CharAtlasCache'; import { TEXT_BASELINE } from 'browser/renderer/shared/Constants'; import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs'; -import { isEmoji, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; +import { allowRescaling, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel'; import { IRasterizedGlyph, IRenderDimensions, ISelectionRenderModel, ITextureAtlas } from 'browser/renderer/shared/Types'; import { ICoreBrowserService, IThemeService } from 'browser/services/Services'; @@ -407,14 +407,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer // following cell (ie. the width is not 2). let renderWidth = glyph.size.x; if (this._optionsService.rawOptions.rescaleOverlappingGlyphs) { - if ( - // Is single cell width - width === 1 && - // Glyph exceeds cell bounds, + 1 to avoid hurting readability - glyph.size.x > this._deviceCellWidth + 1 && - // Never rescale emoji - code && !isEmoji(code) - ) { + if (allowRescaling(code, width, glyph.size.x, this._deviceCellWidth)) { renderWidth = this._deviceCellWidth - 1; // - 1 to improve readability } } diff --git a/addons/addon-webgl/src/GlyphRenderer.ts b/addons/addon-webgl/src/GlyphRenderer.ts index 7ac89084..35b56eef 100644 --- a/addons/addon-webgl/src/GlyphRenderer.ts +++ b/addons/addon-webgl/src/GlyphRenderer.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { isEmoji, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; +import { allowRescaling, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; import { TextureAtlas } from 'browser/renderer/shared/TextureAtlas'; import { IRasterizedGlyph, IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types'; import { NULL_CELL_CODE } from 'common/buffer/Constants'; @@ -281,14 +281,7 @@ export class GlyphRenderer extends Disposable { // Reduce scale horizontally for wide glyphs printed in cells that would overlap with the // following cell (ie. the width is not 2). if (this._optionsService.rawOptions.rescaleOverlappingGlyphs) { - if ( - // Is single cell width - width === 1 && - // Glyph exceeds cell bounds, + 1 to avoid hurting readability - $glyph.size.x > this._dimensions.device.cell.width + 1 && - // Never rescale emoji - code && !isEmoji(code) - ) { + if (allowRescaling(code, width, $glyph.size.x, this._dimensions.device.cell.width)) { array[$i + 2] = (this._dimensions.device.cell.width - 1) / this._dimensions.device.canvas.width; // - 1 to improve readability } } diff --git a/src/browser/renderer/shared/RendererUtils.ts b/src/browser/renderer/shared/RendererUtils.ts index f99c23a1..792d5b1d 100644 --- a/src/browser/renderer/shared/RendererUtils.ts +++ b/src/browser/renderer/shared/RendererUtils.ts @@ -48,8 +48,9 @@ export function allowRescaling(codepoint: number | undefined, width: number, gly return ( // Is single cell width width === 1 && - // Glyph exceeds cell bounds, + 1 to avoid hurting readability - glyphSizeX > deviceCellWidth + 1 && + // Glyph exceeds cell bounds, add 25% to avoid hurting readability by rescaling glyphs that + // barely overlap + glyphSizeX > deviceCellWidth * 1.25 && // Never rescale emoji codepoint !== undefined && !isEmoji(codepoint) && // Never rescale powerline or nerd fonts From 3e5d0015afa09633aabb9a5e2634f4d866c4f8f6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:30:25 -0700 Subject: [PATCH 31/56] Fix search not destroying cache on linefeed Fixes #4994 --- addons/addon-search/src/SearchAddon.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/addon-search/src/SearchAddon.ts b/addons/addon-search/src/SearchAddon.ts index 3fae7373..17850f60 100644 --- a/addons/addon-search/src/SearchAddon.ts +++ b/addons/addon-search/src/SearchAddon.ts @@ -78,6 +78,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA */ private _linesCache: LineCacheEntry[] | undefined; private _linesCacheTimeoutId = 0; + private _lineFeedListener: IDisposable | undefined; private _cursorMoveListener: IDisposable | undefined; private _resizeListener: IDisposable | undefined; @@ -427,6 +428,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA const terminal = this._terminal!; if (!this._linesCache) { this._linesCache = new Array(terminal.buffer.active.length); + this._lineFeedListener = terminal.onLineFeed(() => this._destroyLinesCache()); this._cursorMoveListener = terminal.onCursorMove(() => this._destroyLinesCache()); this._resizeListener = terminal.onResize(() => this._destroyLinesCache()); } @@ -445,6 +447,10 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA this._resizeListener.dispose(); this._resizeListener = undefined; } + if (this._lineFeedListener) { + this._lineFeedListener.dispose(); + this._lineFeedListener = undefined; + } if (this._linesCacheTimeoutId) { window.clearTimeout(this._linesCacheTimeoutId); this._linesCacheTimeoutId = 0; From 14fbdd3e9cc00aed02fbd24963a1d601e0db83c8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:32:49 -0700 Subject: [PATCH 32/56] Adopt MutableDisposable in SearchAddon --- addons/addon-search/src/SearchAddon.ts | 27 ++++++++------------------ 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/addons/addon-search/src/SearchAddon.ts b/addons/addon-search/src/SearchAddon.ts index 17850f60..d42f4d27 100644 --- a/addons/addon-search/src/SearchAddon.ts +++ b/addons/addon-search/src/SearchAddon.ts @@ -6,7 +6,7 @@ import type { Terminal, IDisposable, ITerminalAddon, IDecoration } from '@xterm/xterm'; import type { SearchAddon as ISearchApi } from '@xterm/addon-search'; import { EventEmitter } from 'common/EventEmitter'; -import { Disposable, toDisposable, disposeArray, MutableDisposable } from 'common/Lifecycle'; +import { Disposable, toDisposable, disposeArray, MutableDisposable, getDisposeArrayDisposable } from 'common/Lifecycle'; export interface ISearchOptions { regex?: boolean; @@ -78,9 +78,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA */ private _linesCache: LineCacheEntry[] | undefined; private _linesCacheTimeoutId = 0; - private _lineFeedListener: IDisposable | undefined; - private _cursorMoveListener: IDisposable | undefined; - private _resizeListener: IDisposable | undefined; + private _linesCacheDisposables = new MutableDisposable(); private readonly _onDidChangeResults = this.register(new EventEmitter<{ resultIndex: number, resultCount: number }>()); public readonly onDidChangeResults = this._onDidChangeResults.event; @@ -428,9 +426,11 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA const terminal = this._terminal!; if (!this._linesCache) { this._linesCache = new Array(terminal.buffer.active.length); - this._lineFeedListener = terminal.onLineFeed(() => this._destroyLinesCache()); - this._cursorMoveListener = terminal.onCursorMove(() => this._destroyLinesCache()); - this._resizeListener = terminal.onResize(() => this._destroyLinesCache()); + this._linesCacheDisposables.value = getDisposeArrayDisposable([ + terminal.onLineFeed(() => this._destroyLinesCache()), + terminal.onCursorMove(() => this._destroyLinesCache()), + terminal.onResize(() => this._destroyLinesCache()) + ]); } window.clearTimeout(this._linesCacheTimeoutId); @@ -439,18 +439,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA private _destroyLinesCache(): void { this._linesCache = undefined; - if (this._cursorMoveListener) { - this._cursorMoveListener.dispose(); - this._cursorMoveListener = undefined; - } - if (this._resizeListener) { - this._resizeListener.dispose(); - this._resizeListener = undefined; - } - if (this._lineFeedListener) { - this._lineFeedListener.dispose(); - this._lineFeedListener = undefined; - } + this._linesCacheDisposables.clear(); if (this._linesCacheTimeoutId) { window.clearTimeout(this._linesCacheTimeoutId); this._linesCacheTimeoutId = 0; From c78af2b448b9fa34359750a639f07a8049cf1af9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:49:36 -0700 Subject: [PATCH 33/56] Fix dom cursor blink animation Fixes #4987 Doesn't seem to regress #4773 which caused this issue --- src/browser/renderer/dom/DomRenderer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 1549b130..3e8f2111 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -209,8 +209,8 @@ export class DomRenderer extends Disposable implements IRenderer { ` animation: blink_block` + `_` + this._terminalClass + ` 1s step-end infinite;` + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + - ` background-color: ${colors.cursor.css} !important;` + - ` color: ${colors.cursorAccent.css} !important;` + + ` background-color: ${colors.cursor.css};` + + ` color: ${colors.cursorAccent.css};` + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_OUTLINE_CLASS} {` + ` outline: 1px solid ${colors.cursor.css};` + From 18147b2134b1c73a3aae57f012bd46a690309b13 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:55:20 -0700 Subject: [PATCH 34/56] Fix bar blink animation --- src/browser/renderer/dom/DomRenderer.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 3e8f2111..68004ff5 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -184,11 +184,17 @@ export class DomRenderer extends Disposable implements IRenderer { `}`; // Blink animation styles += - `@keyframes blink_box_shadow` + `_` + this._terminalClass + ` {` + + `@keyframes blink_underline` + `_` + this._terminalClass + ` {` + ` 50% {` + ` border-bottom-style: hidden;` + ` }` + `}`; + styles += + `@keyframes blink_bar` + `_` + this._terminalClass + ` {` + + ` 50% {` + + ` box-shadow: none;` + + ` }` + + `}`; styles += `@keyframes blink_block` + `_` + this._terminalClass + ` {` + ` 0% {` + @@ -202,8 +208,11 @@ export class DomRenderer extends Disposable implements IRenderer { `}`; // Cursor styles += - `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}:not(.${RowCss.CURSOR_STYLE_BLOCK_CLASS}) {` + - ` animation: blink_box_shadow` + `_` + this._terminalClass + ` 1s step-end infinite;` + + `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` + + ` animation: blink_underline` + `_` + this._terminalClass + ` 1s step-end infinite;` + + `}` + + `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` + + ` animation: blink_bar` + `_` + this._terminalClass + ` 1s step-end infinite;` + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + ` animation: blink_block` + `_` + this._terminalClass + ` 1s step-end infinite;` + From 7b76ca7e49276d4388f750106576302982fcb23e Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:57:23 -0700 Subject: [PATCH 35/56] Make dom rendere animation classes more readable --- src/browser/renderer/dom/DomRenderer.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 68004ff5..e6db73e8 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -183,20 +183,23 @@ export class DomRenderer extends Disposable implements IRenderer { ` font-style: italic;` + `}`; // Blink animation + const blinkAnimationUnderlineId = `blink_underline_${this._terminalClass}`; + const blinkAnimationBarId = `blink_bar_${this._terminalClass}`; + const blinkAnimationBlockId = `blink_block_${this._terminalClass}`; styles += - `@keyframes blink_underline` + `_` + this._terminalClass + ` {` + + `@keyframes ${blinkAnimationUnderlineId} {` + ` 50% {` + ` border-bottom-style: hidden;` + ` }` + `}`; styles += - `@keyframes blink_bar` + `_` + this._terminalClass + ` {` + + `@keyframes ${blinkAnimationBarId} {` + ` 50% {` + ` box-shadow: none;` + ` }` + `}`; styles += - `@keyframes blink_block` + `_` + this._terminalClass + ` {` + + `@keyframes ${blinkAnimationBlockId} {` + ` 0% {` + ` background-color: ${colors.cursor.css};` + ` color: ${colors.cursorAccent.css};` + @@ -209,13 +212,13 @@ export class DomRenderer extends Disposable implements IRenderer { // Cursor styles += `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` + - ` animation: blink_underline` + `_` + this._terminalClass + ` 1s step-end infinite;` + + ` animation: ${blinkAnimationUnderlineId} 1s step-end infinite;` + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` + - ` animation: blink_bar` + `_` + this._terminalClass + ` 1s step-end infinite;` + + ` animation: ${blinkAnimationBarId} 1s step-end infinite;` + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + - ` animation: blink_block` + `_` + this._terminalClass + ` 1s step-end infinite;` + + ` animation: ${blinkAnimationBlockId} 1s step-end infinite;` + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + ` background-color: ${colors.cursor.css};` + From a4f1299f42beaa1c7298dee68600ba15de51bdc5 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 16 Mar 2024 11:05:01 -0700 Subject: [PATCH 36/56] Special case cursor block blink to not use important Fixes #4987 --- src/browser/renderer/dom/DomRenderer.ts | 7 +++++++ test/playwright/SharedRendererTests.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index e6db73e8..c89cee62 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -220,10 +220,17 @@ export class DomRenderer extends Disposable implements IRenderer { `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + ` animation: ${blinkAnimationBlockId} 1s step-end infinite;` + `}` + + // !important helps fix an issue where the cursor will not render on top of the selection, + // however it's very hard to fix this issue and retain the blink animation without the use of + // !important. So this edge case fails when cursor blink is on. `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` + ` background-color: ${colors.cursor.css};` + ` color: ${colors.cursorAccent.css};` + `}` + + `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS}:not(.${RowCss.CURSOR_BLINK_CLASS}) {` + + ` background-color: ${colors.cursor.css} !important;` + + ` color: ${colors.cursorAccent.css} !important;` + + `}` + `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_OUTLINE_CLASS} {` + ` outline: 1px solid ${colors.cursor.css};` + ` outline-offset: -1px;` + diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index 29dc51c3..c4b66536 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -6,7 +6,7 @@ import { IImage32, decodePng } from '@lunapaint/png-codec'; import { LocatorScreenshotOptions, test } from '@playwright/test'; import { ITheme } from '@xterm/xterm'; -import { ITestContext, MaybeAsync, openTerminal, pollFor, pollForApproximate, timeout } from './TestUtils'; +import { ITestContext, MaybeAsync, openTerminal, pollFor, pollForApproximate } from './TestUtils'; export interface ISharedRendererTestContext { value: ITestContext; From f8ae7edaa0d6f188101df9b3a9d26a835e2c223f Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 19 Mar 2024 08:56:13 -0700 Subject: [PATCH 37/56] Only scale when over 50% of following cell See microsoft/vscode#208102 --- src/browser/renderer/shared/RendererUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/renderer/shared/RendererUtils.ts b/src/browser/renderer/shared/RendererUtils.ts index 792d5b1d..13c3bdd0 100644 --- a/src/browser/renderer/shared/RendererUtils.ts +++ b/src/browser/renderer/shared/RendererUtils.ts @@ -48,9 +48,9 @@ export function allowRescaling(codepoint: number | undefined, width: number, gly return ( // Is single cell width width === 1 && - // Glyph exceeds cell bounds, add 25% to avoid hurting readability by rescaling glyphs that + // Glyph exceeds cell bounds, add 50% to avoid hurting readability by rescaling glyphs that // barely overlap - glyphSizeX > deviceCellWidth * 1.25 && + glyphSizeX > Math.ceil(deviceCellWidth * 1.5) && // Never rescale emoji codepoint !== undefined && !isEmoji(codepoint) && // Never rescale powerline or nerd fonts From 4c90009a0e7678dcb751d4632f5354dded9c3ed1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:02:46 -0700 Subject: [PATCH 38/56] Don't rescale ascii See microsoft/vscode#208102 --- src/browser/renderer/shared/RendererUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/browser/renderer/shared/RendererUtils.ts b/src/browser/renderer/shared/RendererUtils.ts index 13c3bdd0..01064364 100644 --- a/src/browser/renderer/shared/RendererUtils.ts +++ b/src/browser/renderer/shared/RendererUtils.ts @@ -51,8 +51,10 @@ export function allowRescaling(codepoint: number | undefined, width: number, gly // Glyph exceeds cell bounds, add 50% to avoid hurting readability by rescaling glyphs that // barely overlap glyphSizeX > Math.ceil(deviceCellWidth * 1.5) && + // Never rescale ascii + codepoint !== undefined && codepoint > 0xFF && // Never rescale emoji - codepoint !== undefined && !isEmoji(codepoint) && + !isEmoji(codepoint) && // Never rescale powerline or nerd fonts !isPowerlineGlyph(codepoint) && !isNerdFontGlyph(codepoint) ); From 78297e52aaf12f67f1d1abf885869adc176fceb3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Apr 2024 06:50:30 -0700 Subject: [PATCH 39/56] v5.5 --- addons/addon-attach/package.json | 2 +- addons/addon-canvas/package.json | 2 +- addons/addon-fit/package.json | 2 +- addons/addon-image/package.json | 2 +- addons/addon-ligatures/package.json | 2 +- addons/addon-search/package.json | 2 +- addons/addon-serialize/package.json | 2 +- addons/addon-unicode-graphemes/package.json | 2 +- addons/addon-unicode11/package.json | 2 +- addons/addon-web-links/package.json | 2 +- addons/addon-webgl/package.json | 2 +- package.json | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/addons/addon-attach/package.json b/addons/addon-attach/package.json index c2f42ce5..71b1188d 100644 --- a/addons/addon-attach/package.json +++ b/addons/addon-attach/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-attach", - "version": "0.10.0", + "version": "0.11.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-canvas/package.json b/addons/addon-canvas/package.json index 8fdec96b..2ca5d163 100644 --- a/addons/addon-canvas/package.json +++ b/addons/addon-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-canvas", - "version": "0.6.0", + "version": "0.7.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-fit/package.json b/addons/addon-fit/package.json index be81b196..cacf31dd 100644 --- a/addons/addon-fit/package.json +++ b/addons/addon-fit/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-fit", - "version": "0.9.0", + "version": "0.10.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-image/package.json b/addons/addon-image/package.json index 2e28955d..ac4dc018 100644 --- a/addons/addon-image/package.json +++ b/addons/addon-image/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-image", - "version": "0.7.0", + "version": "0.8.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-ligatures/package.json b/addons/addon-ligatures/package.json index 60166577..80608ee3 100644 --- a/addons/addon-ligatures/package.json +++ b/addons/addon-ligatures/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-ligatures", - "version": "0.8.0", + "version": "0.9.0", "description": "Add support for programming ligatures to xterm.js", "author": { "name": "The xterm.js authors", diff --git a/addons/addon-search/package.json b/addons/addon-search/package.json index 35a4015e..9292a0c4 100644 --- a/addons/addon-search/package.json +++ b/addons/addon-search/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-search", - "version": "0.14.0", + "version": "0.15.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-serialize/package.json b/addons/addon-serialize/package.json index 9c50288d..30dadbb6 100644 --- a/addons/addon-serialize/package.json +++ b/addons/addon-serialize/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-serialize", - "version": "0.12.0", + "version": "0.13.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-unicode-graphemes/package.json b/addons/addon-unicode-graphemes/package.json index 610e14b4..3d846286 100644 --- a/addons/addon-unicode-graphemes/package.json +++ b/addons/addon-unicode-graphemes/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-unicode-graphemes", - "version": "0.2.0", + "version": "0.3.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-unicode11/package.json b/addons/addon-unicode11/package.json index e511c65a..9f2c21b8 100644 --- a/addons/addon-unicode11/package.json +++ b/addons/addon-unicode11/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-unicode11", - "version": "0.7.0", + "version": "0.8.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-web-links/package.json b/addons/addon-web-links/package.json index 6a65f289..da888716 100644 --- a/addons/addon-web-links/package.json +++ b/addons/addon-web-links/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-web-links", - "version": "0.10.0", + "version": "0.11.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/addons/addon-webgl/package.json b/addons/addon-webgl/package.json index f504bb7e..da37eb26 100644 --- a/addons/addon-webgl/package.json +++ b/addons/addon-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@xterm/addon-webgl", - "version": "0.17.0", + "version": "0.18.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" diff --git a/package.json b/package.json index dd425db6..c79b1196 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@xterm/xterm", "description": "Full xterm terminal, in your browser", - "version": "5.4.0", + "version": "5.5.0", "main": "lib/xterm.js", "style": "css/xterm.css", "types": "typings/xterm.d.ts", From 52e8a75e9f3b0f12cdba71d8c3cfe3a5f4958885 Mon Sep 17 00:00:00 2001 From: ksqsf Date: Mon, 8 Apr 2024 13:37:55 +0800 Subject: [PATCH 40/56] Fix duplicate input for some IMEs fixes #5023 --- src/browser/input/CompositionHelper.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/browser/input/CompositionHelper.ts b/src/browser/input/CompositionHelper.ts index 7542969a..9891709f 100644 --- a/src/browser/input/CompositionHelper.ts +++ b/src/browser/input/CompositionHelper.ts @@ -159,8 +159,9 @@ export class CompositionHelper { // otherwise input characters can be duplicated. (Issue #3191) currentCompositionPosition.start += this._dataAlreadySent.length; if (this._isComposing) { - // Use the end position to get the string if a new composition has started. - input = this._textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); + // Use the start position of the new composition to get the string + // if a new composition has started. + input = this._textarea.value.substring(currentCompositionPosition.start, this._compositionPosition.start); } else { // Don't use the end position here in order to pick up any characters after the // composition has finished, for example when typing a non-composition character From e845abc784dba466f504d9da629ce15e4ec1875d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 12 Apr 2024 16:47:59 -0700 Subject: [PATCH 41/56] Finish OSC hyperlinks when the second param is only whitespace Fixes #4916 --- src/common/InputHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index a4b8c64b..9b300993 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -2979,7 +2979,7 @@ export class InputHandler extends Disposable implements IInputHandler { if (args[1]) { return this._createHyperlink(args[0], args[1]); } - if (args[0]) { + if (args[0].trim()) { return false; } return this._finishHyperlink(); From 8458bb4c4f4b8b3cf1d4a7207e0d47b13d17260c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:27:48 -0700 Subject: [PATCH 42/56] Expose onWriteParsed on API Inconsistency with headless API --- src/headless/public/Terminal.ts | 1 + typings/xterm-headless.d.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/headless/public/Terminal.ts b/src/headless/public/Terminal.ts index 0d73f9d3..1b39c184 100644 --- a/src/headless/public/Terminal.ts +++ b/src/headless/public/Terminal.ts @@ -80,6 +80,7 @@ export class Terminal extends Disposable implements ITerminalApi { public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; } public get onScroll(): IEvent { return this._core.onScroll; } public get onTitleChange(): IEvent { return this._core.onTitleChange; } + public get onWriteParsed(): IEvent { return this._core.onWriteParsed; } public get parser(): IParser { this._checkProposedApi(); diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 5e84f266..2d3329ed 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -714,6 +714,17 @@ declare module '@xterm/headless' { */ onLineFeed: IEvent; + /** + * Adds an event listener for when data has been parsed by the terminal, + * after {@link write} is called. This event is useful to listen for any + * changes in the buffer. + * + * This fires at most once per frame, after data parsing completes. Note + * that this can fire when there are still writes pending if there is a lot + * of data. + */ + onWriteParsed: IEvent; + /** * Adds an event listener for when the terminal is resized. The event value * contains the new size. From 16db22711946e7843b360ba583eb05e4a73694f6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 08:11:59 -0700 Subject: [PATCH 43/56] Prevent smooth scroll from running more than once per frame Fixes #5036 --- src/browser/Viewport.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index a8e1a498..1b2f7b5b 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -36,6 +36,8 @@ export class Viewport extends Disposable implements IViewport { private _activeBuffer: IBuffer; private _renderDimensions: IRenderDimensions; + private _smoothScrollAnimationFrame: number = 0; + // Stores a partial line amount when scrolling, this is used to keep track of how much of a line // is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a // quick fix and could have a more robust solution in place that reset the value when needed. @@ -211,7 +213,12 @@ export class Viewport extends Disposable implements IViewport { // Continue or finish smooth scroll if (percent < 1) { - this._coreBrowserService.window.requestAnimationFrame(() => this._smoothScroll()); + if (!this._smoothScrollAnimationFrame) { + this._smoothScrollAnimationFrame = this._coreBrowserService.window.requestAnimationFrame(() => { + this._smoothScrollAnimationFrame = 0; + this._smoothScroll(); + }); + } } else { this._clearSmoothScrollState(); } From 5c8a9084e3e52c528ac14ce5035e4c7d9d060dd1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 08:41:22 -0700 Subject: [PATCH 44/56] Add mass decoration test button Part of #4911 --- demo/client.ts | 30 +++++++++++++++++++++++++++++- demo/index.html | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/demo/client.ts b/demo/client.ts index 7e0830a5..a3e58051 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -44,7 +44,7 @@ if ('WebAssembly' in window) { // Pulling in the module's types relies on the above, it's looks a // little weird here as we're importing "this" module -import { Terminal as TerminalType, ITerminalOptions } from '@xterm/xterm'; +import { Terminal as TerminalType, ITerminalOptions, type IDisposable } from '@xterm/xterm'; export interface IWindowWithTerminal extends Window { term: TerminalType; @@ -255,6 +255,7 @@ if (document.location.pathname === '/test') { document.getElementById('add-grapheme-clusters').addEventListener('click', addGraphemeClusters); document.getElementById('add-decoration').addEventListener('click', addDecoration); document.getElementById('add-overview-ruler').addEventListener('click', addOverviewRuler); + document.getElementById('decoration-stress-test').addEventListener('click', decorationStressTest); document.getElementById('weblinks-test').addEventListener('click', testWeblinks); document.getElementById('bce').addEventListener('click', coloredErase); addVtButtons(); @@ -1170,6 +1171,33 @@ function addOverviewRuler(): void { term.registerDecoration({ marker: term.registerMarker(10), overviewRulerOptions: { color: '#ffffff80', position: 'full' } }); } +let decorationStressTestDecorations: IDisposable[] | undefined; +function decorationStressTest(): void { + if (decorationStressTestDecorations) { + for (const d of decorationStressTestDecorations) { + d.dispose(); + } + decorationStressTestDecorations = undefined; + } else { + const t = term as Terminal; + const buffer = t.buffer.active; + const cursorY = buffer.baseY + buffer.cursorY; + decorationStressTestDecorations = []; + for (const x of [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]) { + for (let y = 0; y < t.buffer.active.length; y++) { + const cursorOffsetY = y - cursorY; + decorationStressTestDecorations.push(t.registerDecoration({ + marker: t.registerMarker(cursorOffsetY), + x, + width: 4, + backgroundColor: '#FF0000', + overviewRulerOptions: { color: '#FF0000' } + })); + } + } + } +} + (console as any).image = (source: ImageData | HTMLCanvasElement, scale: number = 1) => { function getBox(width: number, height: number): any { return { diff --git a/demo/index.html b/demo/index.html index caff2ca2..238c9886 100644 --- a/demo/index.html +++ b/demo/index.html @@ -102,6 +102,7 @@
Decorations
+
Weblinks Addon
From dc541d549543f4bff48993074a7222d923d1aa72 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:32:30 -0700 Subject: [PATCH 45/56] Optimize SortedList.delete by batching to idle task --- src/common/SortedList.ts | 43 ++++++++++++++++++++++-- src/common/services/DecorationService.ts | 3 +- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index c3250091..0fb71e4e 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -3,6 +3,8 @@ * @license MIT */ +import { IdleTaskQueue } from 'common/TaskQueue'; + // Work variables to avoid garbage collection. let i = 0; @@ -12,7 +14,10 @@ let i = 0; * includes the by key iterator. */ export class SortedList { - private readonly _array: T[] = []; + private _array: T[] = []; + private readonly _deletedIndices: Set = new Set(); + private readonly _cleanupDeletedTask = new IdleTaskQueue(); + private _isCleaningUp = false; constructor( private readonly _getKey: (value: T) => number @@ -21,9 +26,13 @@ export class SortedList { public clear(): void { this._array.length = 0; + this._deletedIndices.clear(); + this._cleanupDeletedTask.clear(); + this._isCleaningUp = false; } public insert(value: T): void { + this._flushCleanupDeleted(); if (this._array.length === 0) { this._array.push(value); return; @@ -49,14 +58,42 @@ export class SortedList { } do { if (this._array[i] === value) { - this._array.splice(i, 1); + if (this._deletedIndices.size === 0) { + this._cleanupDeletedTask.enqueue(() => this._cleanupDeleted()); + } + this._deletedIndices.add(i); return true; } } while (++i < this._array.length && this._getKey(this._array[i]) === key); return false; } + private _cleanupDeleted(): void { + this._isCleaningUp = true; + const sortedDeletedIndices = Array.from(this._deletedIndices).sort((a, b) => a - b); + let sortedDeletedIndicesIndex = 0; + const newArray = new Array(this._array.length - sortedDeletedIndices.length); + let newArrayIndex = 0; + for (let i = 0; i < this._array.length; i++) { + if (sortedDeletedIndices[sortedDeletedIndicesIndex] === i) { + sortedDeletedIndicesIndex++; + } else { + newArray[newArrayIndex++] = this._array[i]; + } + } + this._array = newArray; + this._deletedIndices.clear(); + this._isCleaningUp = false; + } + + private _flushCleanupDeleted(): void { + if (!this._isCleaningUp) { + this._cleanupDeletedTask.flush(); + } + } + public *getKeyIterator(key: number): IterableIterator { + this._flushCleanupDeleted(); if (this._array.length === 0) { return; } @@ -73,6 +110,7 @@ export class SortedList { } public forEachByKey(key: number, callback: (value: T) => void): void { + this._flushCleanupDeleted(); if (this._array.length === 0) { return; } @@ -89,6 +127,7 @@ export class SortedList { } public values(): IterableIterator { + this._flushCleanupDeleted(); // Duplicate the array to avoid issues when _array changes while iterating return [...this._array].values(); } diff --git a/src/common/services/DecorationService.ts b/src/common/services/DecorationService.ts index da759152..c9be78af 100644 --- a/src/common/services/DecorationService.ts +++ b/src/common/services/DecorationService.ts @@ -45,7 +45,8 @@ export class DecorationService extends Disposable implements IDecorationService const decoration = new Decoration(options); if (decoration) { const markerDispose = decoration.marker.onDispose(() => decoration.dispose()); - decoration.onDispose(() => { + const listener = decoration.onDispose(() => { + listener.dispose(); if (decoration) { if (this._decorations.delete(decoration)) { this._onDecorationRemoved.fire(decoration); From 3af11c2b1f8c79cf61b040231e851f6d523c4e19 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:47:40 -0700 Subject: [PATCH 46/56] Optimize SortedList.insert by batching to idle task --- src/common/SortedList.ts | 58 +++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index 0fb71e4e..0aba3668 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -15,8 +15,14 @@ let i = 0; */ export class SortedList { private _array: T[] = []; + + private readonly _addedValues: Set = new Set(); + private readonly _cleanupAddedTask = new IdleTaskQueue(); + private _isCleaningUpAdded = false; + private readonly _deletedIndices: Set = new Set(); - private readonly _cleanupDeletedTask = new IdleTaskQueue(); + + private readonly _cleanupTask = new IdleTaskQueue(); private _isCleaningUp = false; constructor( @@ -27,21 +33,52 @@ export class SortedList { public clear(): void { this._array.length = 0; this._deletedIndices.clear(); - this._cleanupDeletedTask.clear(); + this._cleanupTask.clear(); this._isCleaningUp = false; } public insert(value: T): void { this._flushCleanupDeleted(); - if (this._array.length === 0) { - this._array.push(value); - return; + if (this._addedValues.size === 0) { + this._cleanupAddedTask.enqueue(() => this._cleanupAdded()); + } + this._addedValues.add(value); + // if (this._array.length === 0) { + // this._array.push(value); + // return; + // } + // i = this._search(this._getKey(value)); + // this._array.splice(i, 0, value); + } + + private _cleanupAdded(): void { + const sortedAddedValues = Array.from(this._addedValues).sort((a, b) => this._getKey(a) - this._getKey(b)); + let sortedAddedValuesIndex = 0; + let arrayIndex = 0; + + const newArray = new Array(this._array.length + this._addedValues.size); + + for (let newArrayIndex = 0; newArrayIndex < newArray.length; newArrayIndex++) { + if (arrayIndex >= this._array.length || this._getKey(sortedAddedValues[sortedAddedValuesIndex]) === this._getKey(this._array[arrayIndex])) { + newArray[newArrayIndex] = sortedAddedValues[sortedAddedValuesIndex]; + sortedAddedValuesIndex++; + } else { + newArray[newArrayIndex] = this._array[arrayIndex++]; + } + } + + this._array = newArray; + this._addedValues.clear(); + } + + private _flushCleanupAdded(): void { + if (!this._isCleaningUpAdded) { + this._cleanupAddedTask.flush(); } - i = this._search(this._getKey(value)); - this._array.splice(i, 0, value); } public delete(value: T): boolean { + this._flushCleanupAdded(); if (this._array.length === 0) { return false; } @@ -59,7 +96,7 @@ export class SortedList { do { if (this._array[i] === value) { if (this._deletedIndices.size === 0) { - this._cleanupDeletedTask.enqueue(() => this._cleanupDeleted()); + this._cleanupTask.enqueue(() => this._cleanupDeleted()); } this._deletedIndices.add(i); return true; @@ -88,11 +125,12 @@ export class SortedList { private _flushCleanupDeleted(): void { if (!this._isCleaningUp) { - this._cleanupDeletedTask.flush(); + this._cleanupTask.flush(); } } public *getKeyIterator(key: number): IterableIterator { + this._flushCleanupAdded(); this._flushCleanupDeleted(); if (this._array.length === 0) { return; @@ -110,6 +148,7 @@ export class SortedList { } public forEachByKey(key: number, callback: (value: T) => void): void { + this._flushCleanupAdded(); this._flushCleanupDeleted(); if (this._array.length === 0) { return; @@ -127,6 +166,7 @@ export class SortedList { } public values(): IterableIterator { + this._flushCleanupAdded(); this._flushCleanupDeleted(); // Duplicate the array to avoid issues when _array changes while iterating return [...this._array].values(); From 69c4966804d6fc33ebe27bf3f38901a6e5875aff Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:48:55 -0700 Subject: [PATCH 47/56] Consistent naming --- src/common/SortedList.ts | 61 ++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index 0aba3668..42dc7ef3 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -16,14 +16,13 @@ let i = 0; export class SortedList { private _array: T[] = []; - private readonly _addedValues: Set = new Set(); - private readonly _cleanupAddedTask = new IdleTaskQueue(); - private _isCleaningUpAdded = false; + private readonly _insertedValues: Set = new Set(); + private readonly _flushInsertedTask = new IdleTaskQueue(); + private _isFlushingInserted = false; private readonly _deletedIndices: Set = new Set(); - - private readonly _cleanupTask = new IdleTaskQueue(); - private _isCleaningUp = false; + private readonly _flushDeletedTask = new IdleTaskQueue(); + private _isflushingDeleted = false; constructor( private readonly _getKey: (value: T) => number @@ -33,30 +32,24 @@ export class SortedList { public clear(): void { this._array.length = 0; this._deletedIndices.clear(); - this._cleanupTask.clear(); - this._isCleaningUp = false; + this._flushDeletedTask.clear(); + this._isflushingDeleted = false; } public insert(value: T): void { this._flushCleanupDeleted(); - if (this._addedValues.size === 0) { - this._cleanupAddedTask.enqueue(() => this._cleanupAdded()); + if (this._insertedValues.size === 0) { + this._flushInsertedTask.enqueue(() => this._flushInserted()); } - this._addedValues.add(value); - // if (this._array.length === 0) { - // this._array.push(value); - // return; - // } - // i = this._search(this._getKey(value)); - // this._array.splice(i, 0, value); + this._insertedValues.add(value); } - private _cleanupAdded(): void { - const sortedAddedValues = Array.from(this._addedValues).sort((a, b) => this._getKey(a) - this._getKey(b)); + private _flushInserted(): void { + const sortedAddedValues = Array.from(this._insertedValues).sort((a, b) => this._getKey(a) - this._getKey(b)); let sortedAddedValuesIndex = 0; let arrayIndex = 0; - const newArray = new Array(this._array.length + this._addedValues.size); + const newArray = new Array(this._array.length + this._insertedValues.size); for (let newArrayIndex = 0; newArrayIndex < newArray.length; newArrayIndex++) { if (arrayIndex >= this._array.length || this._getKey(sortedAddedValues[sortedAddedValuesIndex]) === this._getKey(this._array[arrayIndex])) { @@ -68,17 +61,17 @@ export class SortedList { } this._array = newArray; - this._addedValues.clear(); + this._insertedValues.clear(); } - private _flushCleanupAdded(): void { - if (!this._isCleaningUpAdded) { - this._cleanupAddedTask.flush(); + private _flushCleanupInserted(): void { + if (!this._isFlushingInserted) { + this._flushInsertedTask.flush(); } } public delete(value: T): boolean { - this._flushCleanupAdded(); + this._flushCleanupInserted(); if (this._array.length === 0) { return false; } @@ -96,7 +89,7 @@ export class SortedList { do { if (this._array[i] === value) { if (this._deletedIndices.size === 0) { - this._cleanupTask.enqueue(() => this._cleanupDeleted()); + this._flushDeletedTask.enqueue(() => this._flushDeleted()); } this._deletedIndices.add(i); return true; @@ -105,8 +98,8 @@ export class SortedList { return false; } - private _cleanupDeleted(): void { - this._isCleaningUp = true; + private _flushDeleted(): void { + this._isflushingDeleted = true; const sortedDeletedIndices = Array.from(this._deletedIndices).sort((a, b) => a - b); let sortedDeletedIndicesIndex = 0; const newArray = new Array(this._array.length - sortedDeletedIndices.length); @@ -120,17 +113,17 @@ export class SortedList { } this._array = newArray; this._deletedIndices.clear(); - this._isCleaningUp = false; + this._isflushingDeleted = false; } private _flushCleanupDeleted(): void { - if (!this._isCleaningUp) { - this._cleanupTask.flush(); + if (!this._isflushingDeleted) { + this._flushDeletedTask.flush(); } } public *getKeyIterator(key: number): IterableIterator { - this._flushCleanupAdded(); + this._flushCleanupInserted(); this._flushCleanupDeleted(); if (this._array.length === 0) { return; @@ -148,7 +141,7 @@ export class SortedList { } public forEachByKey(key: number, callback: (value: T) => void): void { - this._flushCleanupAdded(); + this._flushCleanupInserted(); this._flushCleanupDeleted(); if (this._array.length === 0) { return; @@ -166,7 +159,7 @@ export class SortedList { } public values(): IterableIterator { - this._flushCleanupAdded(); + this._flushCleanupInserted(); this._flushCleanupDeleted(); // Duplicate the array to avoid issues when _array changes while iterating return [...this._array].values(); From 45fd3c900f2cfe448a129ba5b7525bacb24c9b9f Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:52:43 -0700 Subject: [PATCH 48/56] Only flush when needed --- src/common/SortedList.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index 42dc7ef3..8a2ad9cc 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -22,7 +22,7 @@ export class SortedList { private readonly _deletedIndices: Set = new Set(); private readonly _flushDeletedTask = new IdleTaskQueue(); - private _isflushingDeleted = false; + private _isFlushingDeleted = false; constructor( private readonly _getKey: (value: T) => number @@ -33,7 +33,7 @@ export class SortedList { this._array.length = 0; this._deletedIndices.clear(); this._flushDeletedTask.clear(); - this._isflushingDeleted = false; + this._isFlushingDeleted = false; } public insert(value: T): void { @@ -65,7 +65,7 @@ export class SortedList { } private _flushCleanupInserted(): void { - if (!this._isFlushingInserted) { + if (!this._isFlushingInserted && this._insertedValues.size > 0) { this._flushInsertedTask.flush(); } } @@ -99,7 +99,7 @@ export class SortedList { } private _flushDeleted(): void { - this._isflushingDeleted = true; + this._isFlushingDeleted = true; const sortedDeletedIndices = Array.from(this._deletedIndices).sort((a, b) => a - b); let sortedDeletedIndicesIndex = 0; const newArray = new Array(this._array.length - sortedDeletedIndices.length); @@ -113,11 +113,11 @@ export class SortedList { } this._array = newArray; this._deletedIndices.clear(); - this._isflushingDeleted = false; + this._isFlushingDeleted = false; } private _flushCleanupDeleted(): void { - if (!this._isflushingDeleted) { + if (!this._isFlushingDeleted && this._deletedIndices.size > 0) { this._flushDeletedTask.flush(); } } From 71dddbc8b93f141413c32c20443639681b5ad914 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:57:39 -0700 Subject: [PATCH 49/56] Move from set to array --- src/common/SortedList.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index 8a2ad9cc..eb88f368 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -16,11 +16,11 @@ let i = 0; export class SortedList { private _array: T[] = []; - private readonly _insertedValues: Set = new Set(); + private readonly _insertedValues: T[] = []; private readonly _flushInsertedTask = new IdleTaskQueue(); private _isFlushingInserted = false; - private readonly _deletedIndices: Set = new Set(); + private readonly _deletedIndices: number[] = []; private readonly _flushDeletedTask = new IdleTaskQueue(); private _isFlushingDeleted = false; @@ -31,17 +31,20 @@ export class SortedList { public clear(): void { this._array.length = 0; - this._deletedIndices.clear(); + this._insertedValues.length = 0; + this._flushInsertedTask.clear(); + this._isFlushingInserted = false; + this._deletedIndices.length = 0; this._flushDeletedTask.clear(); this._isFlushingDeleted = false; } public insert(value: T): void { this._flushCleanupDeleted(); - if (this._insertedValues.size === 0) { + if (this._insertedValues.length === 0) { this._flushInsertedTask.enqueue(() => this._flushInserted()); } - this._insertedValues.add(value); + this._insertedValues.push(value); } private _flushInserted(): void { @@ -49,7 +52,7 @@ export class SortedList { let sortedAddedValuesIndex = 0; let arrayIndex = 0; - const newArray = new Array(this._array.length + this._insertedValues.size); + const newArray = new Array(this._array.length + this._insertedValues.length); for (let newArrayIndex = 0; newArrayIndex < newArray.length; newArrayIndex++) { if (arrayIndex >= this._array.length || this._getKey(sortedAddedValues[sortedAddedValuesIndex]) === this._getKey(this._array[arrayIndex])) { @@ -61,11 +64,11 @@ export class SortedList { } this._array = newArray; - this._insertedValues.clear(); + this._insertedValues.length = 0; } private _flushCleanupInserted(): void { - if (!this._isFlushingInserted && this._insertedValues.size > 0) { + if (!this._isFlushingInserted && this._insertedValues.length > 0) { this._flushInsertedTask.flush(); } } @@ -88,10 +91,10 @@ export class SortedList { } do { if (this._array[i] === value) { - if (this._deletedIndices.size === 0) { + if (this._deletedIndices.length === 0) { this._flushDeletedTask.enqueue(() => this._flushDeleted()); } - this._deletedIndices.add(i); + this._deletedIndices.push(i); return true; } } while (++i < this._array.length && this._getKey(this._array[i]) === key); @@ -112,12 +115,12 @@ export class SortedList { } } this._array = newArray; - this._deletedIndices.clear(); + this._deletedIndices.length = 0; this._isFlushingDeleted = false; } private _flushCleanupDeleted(): void { - if (!this._isFlushingDeleted && this._deletedIndices.size > 0) { + if (!this._isFlushingDeleted && this._deletedIndices.length > 0) { this._flushDeletedTask.flush(); } } From ef1152a8fb0c5e7bdf5bda2bb433b7fe148c93b7 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:59:17 -0700 Subject: [PATCH 50/56] Doc --- src/common/SortedList.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index eb88f368..67e1047e 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -9,9 +9,10 @@ import { IdleTaskQueue } from 'common/TaskQueue'; let i = 0; /** - * A generic list that is maintained in sorted order and allows values with duplicate keys. This - * list is based on binary search and as such locating a key will take O(log n) amortized, this - * includes the by key iterator. + * A generic list that is maintained in sorted order and allows values with duplicate keys. Deferred + * batch insertion and deletion is used to significantly reduce the time it takes to insert and + * delete a large amount of items in succession. This list is based on binary search and as such + * locating a key will take O(log n) amortized, this includes the by key iterator. */ export class SortedList { private _array: T[] = []; From 73fe7015b7776b80c78927ae28809a73f5b8ffcc Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 11:00:41 -0700 Subject: [PATCH 51/56] Use sort on object --- src/common/SortedList.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index 67e1047e..1fb4f962 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -49,7 +49,7 @@ export class SortedList { } private _flushInserted(): void { - const sortedAddedValues = Array.from(this._insertedValues).sort((a, b) => this._getKey(a) - this._getKey(b)); + const sortedAddedValues = this._insertedValues.sort((a, b) => this._getKey(a) - this._getKey(b)); let sortedAddedValuesIndex = 0; let arrayIndex = 0; @@ -104,7 +104,7 @@ export class SortedList { private _flushDeleted(): void { this._isFlushingDeleted = true; - const sortedDeletedIndices = Array.from(this._deletedIndices).sort((a, b) => a - b); + const sortedDeletedIndices = this._deletedIndices.sort((a, b) => a - b); let sortedDeletedIndicesIndex = 0; const newArray = new Array(this._array.length - sortedDeletedIndices.length); let newArrayIndex = 0; From a4a7ce843ce1555c9ab6159ddba39100536db222 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 11:08:28 -0700 Subject: [PATCH 52/56] Reduce gc pressure in api verify integers --- src/browser/public/Terminal.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index a6349225..56edbc50 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -20,6 +20,8 @@ import { IBufferNamespace as IBufferNamespaceApi, IDecoration, IDecorationOption */ const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows']; +let $value = 0; + export class Terminal extends Disposable implements ITerminalApi { private _core: ITerminal; private _addonManager: AddonManager; @@ -249,16 +251,16 @@ export class Terminal extends Disposable implements ITerminalApi { } private _verifyIntegers(...values: number[]): void { - for (const value of values) { - if (value === Infinity || isNaN(value) || value % 1 !== 0) { + for ($value of values) { + if ($value === Infinity || isNaN($value) || $value % 1 !== 0) { throw new Error('This API only accepts integers'); } } } private _verifyPositiveIntegers(...values: number[]): void { - for (const value of values) { - if (value && (value === Infinity || isNaN(value) || value % 1 !== 0 || value < 0)) { + for ($value of values) { + if ($value && ($value === Infinity || isNaN($value) || $value % 1 !== 0 || $value < 0)) { throw new Error('This API only accepts positive integers'); } } From 6b4bf428de661f7269b777de68454dd08175050d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 20 Apr 2024 11:15:14 -0700 Subject: [PATCH 53/56] Fix tests --- src/common/SortedList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index 1fb4f962..82b6dfa6 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -56,7 +56,7 @@ export class SortedList { const newArray = new Array(this._array.length + this._insertedValues.length); for (let newArrayIndex = 0; newArrayIndex < newArray.length; newArrayIndex++) { - if (arrayIndex >= this._array.length || this._getKey(sortedAddedValues[sortedAddedValuesIndex]) === this._getKey(this._array[arrayIndex])) { + if (arrayIndex >= this._array.length || this._getKey(sortedAddedValues[sortedAddedValuesIndex]) <= this._getKey(this._array[arrayIndex])) { newArray[newArrayIndex] = sortedAddedValues[sortedAddedValuesIndex]; sortedAddedValuesIndex++; } else { From 75491f41526512c4786b1cb3feea0bcf4ca124e1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 21 Apr 2024 07:42:17 -0700 Subject: [PATCH 54/56] Remove trailing whitespace --- typings/xterm.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 8c92fec8..b6470275 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -52,7 +52,7 @@ declare module '@xterm/xterm' { * translation of `\n` to `\r\n` and this setting should not be used. If you * deal with data from a non-PTY related source, this settings might be * useful. - * + * * @see https://pubs.opengroup.org/onlinepubs/007904975/basedefs/termios.h.html */ convertEol?: boolean; From f1e0737c5ef6222a6f41f65efa7fa68c2251b2b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Apr 2024 14:47:44 +0000 Subject: [PATCH 55/56] Bump express from 4.18.2 to 4.19.2 Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2) --- updated-dependencies: - dependency-name: express dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- yarn.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/yarn.lock b/yarn.lock index b2788793..e566fff2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1099,13 +1099,13 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== dependencies: bytes "3.1.2" - content-type "~1.0.4" + content-type "~1.0.5" debug "2.6.9" depd "2.0.0" destroy "1.2.0" @@ -1113,7 +1113,7 @@ body-parser@1.20.1: iconv-lite "0.4.24" on-finished "2.4.1" qs "6.11.0" - raw-body "2.5.1" + raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -1402,7 +1402,7 @@ content-disposition@0.5.4: dependencies: safe-buffer "5.2.1" -content-type@~1.0.4: +content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== @@ -1417,10 +1417,10 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== cross-env@^7.0.3: version "7.0.3" @@ -1832,16 +1832,16 @@ express-ws@^5.0.2: ws "^7.4.6" express@^4.17.1: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.1" + body-parser "1.20.2" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" @@ -3242,10 +3242,10 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" http-errors "2.0.0" From b0c55d1bbf56b1836a2d79509decfaaed92acfb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Apr 2024 14:47:44 +0000 Subject: [PATCH 56/56] Bump follow-redirects from 1.15.3 to 1.15.6 in /addons/addon-ligatures Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.6. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.6) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- addons/addon-ligatures/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/addon-ligatures/yarn.lock b/addons/addon-ligatures/yarn.lock index 966fc113..ac58cbe2 100644 --- a/addons/addon-ligatures/yarn.lock +++ b/addons/addon-ligatures/yarn.lock @@ -86,9 +86,9 @@ fd-slicer@~1.1.0: pend "~1.2.0" follow-redirects@^1.15.0: - version "1.15.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" - integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== font-finder@^1.0.3: version "1.0.4"