From d177accceea386364016bcb3cc3d7539f582f876 Mon Sep 17 00:00:00 2001 From: Jason Lin Date: Fri, 2 Dec 2022 18:17:57 +1100 Subject: [PATCH 01/30] Fix a11y issues #4269 --- src/browser/AccessibilityManager.ts | 5 ++++- src/browser/Terminal.ts | 14 +++++++++----- src/common/Platform.ts | 2 ++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index 3998e779..49e4c66b 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -246,7 +246,10 @@ export class AccessibilityManager extends Disposable { private _handleKey(keyChar: string): void { this._clearLiveRegion(); - this._charsToConsume.push(keyChar); + // Only add the char if there is no control character. + if (!/\p{Control}/u.test(keyChar)) { + this._charsToConsume.push(keyChar); + } } private _refreshRows(start?: number, end?: number): void { diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 3c88b948..caeec050 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -445,7 +445,11 @@ export class Terminal extends CoreTerminal implements ITerminal { this.textarea = document.createElement('textarea'); this.textarea.classList.add('xterm-helper-textarea'); this.textarea.setAttribute('aria-label', Strings.promptLabel); - this.textarea.setAttribute('aria-multiline', 'false'); + if (!Browser.isChromeOS) { + // ChromeVox on ChromeOS does not like this. See + // https://issuetracker.google.com/issues/260170397 + this.textarea.setAttribute('aria-multiline', 'false'); + } this.textarea.setAttribute('autocorrect', 'off'); this.textarea.setAttribute('autocapitalize', 'off'); this.textarea.setAttribute('spellcheck', 'false'); @@ -1057,10 +1061,10 @@ export class Terminal extends CoreTerminal implements ITerminal { this.coreService.triggerDataEvent(result.key, true); // Cancel events when not in screen reader mode so events don't get bubbled up and handled by - // other listeners. When screen reader mode is enabled, this could cause issues if the event - // is handled at a higher level, this is a compromise in order to echo keys to the screen - // reader. - if (!this.optionsService.rawOptions.screenReaderMode) { + // other listeners. When screen reader mode is enabled, we don't cancel them (unless ctrl or alt + // is also depressed) so that the cursor textarea can be updated, which triggers the screen + // reader to read it. + if (!this.optionsService.rawOptions.screenReaderMode || event.altKey || event.ctrlKey) { return this.cancel(event, true); } diff --git a/src/common/Platform.ts b/src/common/Platform.ts index 034665cd..41d8552e 100644 --- a/src/common/Platform.ts +++ b/src/common/Platform.ts @@ -39,3 +39,5 @@ export const isIpad = platform === 'iPad'; export const isIphone = platform === 'iPhone'; export const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].includes(platform); export const isLinux = platform.indexOf('Linux') >= 0; +// Note that when this is true, isLinux will also be true. +export const isChromeOS = /\bCrOS\b/.test(userAgent); From 73d20c1d3bc43107236ecd0bcac97550a43875e5 Mon Sep 17 00:00:00 2001 From: Jason Lin Date: Tue, 6 Dec 2022 14:20:29 +1100 Subject: [PATCH 02/30] Add option scrollOnKeypress Note that we also change the existing behavior a bit: CoreService.triggerDataEvent() will not scroll to the bottom unless `wasUserInput` is also true. This actually seems to be the intended behavior according to the doc just above ICoreService.triggerDataEvent(). --- src/browser/Terminal.ts | 2 +- src/common/services/CoreService.ts | 2 +- src/common/services/OptionsService.ts | 1 + src/common/services/Services.ts | 3 ++- typings/xterm.d.ts | 6 ++++++ 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 3c88b948..2de0200e 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -995,7 +995,7 @@ export class Terminal extends CoreTerminal implements ITerminal { const shouldIgnoreComposition = this.browser.isMac && this.options.macOptionIsMeta && event.altKey; if (!shouldIgnoreComposition && !this._compositionHelper!.keydown(event)) { - if (this.buffer.ybase !== this.buffer.ydisp) { + if (this.options.scrollOnKeypress && this.buffer.ybase !== this.buffer.ydisp) { this._bufferService.scrollToBottom(); } return false; diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index 9282197b..101a142a 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -68,7 +68,7 @@ export class CoreService extends Disposable implements ICoreService { // Input is being sent to the terminal, the terminal should focus the prompt. const buffer = this._bufferService.buffer; - if (buffer.ybase !== buffer.ydisp) { + if (wasUserInput && this._optionsService.rawOptions.scrollOnKeypress && buffer.ybase !== buffer.ydisp) { this._scrollToBottom!(); } diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 976cdf8d..d1e47051 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -28,6 +28,7 @@ export const DEFAULT_OPTIONS: Readonly> = { linkHandler: null, logLevel: 'info', scrollback: 1000, + scrollOnKeypress: true, scrollSensitivity: 1, screenReaderMode: false, smoothScrollDuration: 0, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index cc388063..5f4e692b 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -87,7 +87,7 @@ export interface ICoreService { * @param data The data that is being emitted. * @param wasFromUser Whether the data originated from the user (as opposed to * resulting from parsing incoming data). When true this will also: - * - Scroll to the bottom of the buffer.s + * - Scroll to the bottom of the buffer if option scrollOnKeypress is true. * - Fire the `onUserInput` event (so selection can be cleared). */ triggerDataEvent(data: string, wasUserInput?: boolean): void; @@ -243,6 +243,7 @@ export interface ITerminalOptions { rows?: number; screenReaderMode?: boolean; scrollback?: number; + scrollOnKeypress?: boolean; scrollSensitivity?: number; smoothScrollDuration?: number; tabStopWidth?: number; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 926cc6b4..2eedaac8 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -193,6 +193,12 @@ declare module 'xterm' { */ scrollback?: number; + /** + * Whether to scroll to the bottom whenever a key is pressed. The default is + * true. + */ + scrollOnKeypress?: boolean; + /** * The scrolling speed multiplier used for adjusting normal scrolling speed. */ From e46a9e12d0107085ec3f0db73aaf938a8d2389b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Tue, 6 Dec 2022 13:40:25 +0100 Subject: [PATCH 03/30] fix demo in epiphany --- .../xterm-addon-canvas/src/BaseRenderLayer.ts | 3 +++ demo/client.ts | 26 +++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts index d2a7a4ed..fb146884 100644 --- a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts @@ -373,6 +373,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer } else { glyph = this._charAtlas.getRasterizedGlyph(cell.getCode() || WHITESPACE_CELL_CODE, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext); } + if (!glyph.size.x || !glyph.size.y) { + return; + } this._ctx.save(); this._clipRow(y); // Draw the image, use the bitmap if it's available diff --git a/demo/client.ts b/demo/client.ts index 38c4748a..280b5e56 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -273,22 +273,22 @@ function createTerminal(): void { socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/'; addons.fit.instance!.fit(); - typedTerm.loadAddon(addons.webgl.instance); - setTimeout(() => { - if (addons.webgl.instance !== undefined) { - setTextureAtlas(addons.webgl.instance.textureAtlas); - addons.webgl.instance.onChangeTextureAtlas(e => setTextureAtlas(e)); - addons.webgl.instance.onAddTextureAtlasCanvas(e => appendTextureAtlas(e)); - addons.webgl.instance.onRemoveTextureAtlasCanvas(e => removeTextureAtlas(e)); - } - }, 0); - try { // try-catch to allow the demo to load if webgl is not supported + // try to start with webgl renderer (might throw on older safari/webkit) + try { + typedTerm.loadAddon(addons.webgl.instance); + term.open(terminalContainer); + setTextureAtlas(addons.webgl.instance.textureAtlas); + addons.webgl.instance.onChangeTextureAtlas(e => setTextureAtlas(e)); + addons.webgl.instance.onAddTextureAtlasCanvas(e => appendTextureAtlas(e)); + addons.webgl.instance.onRemoveTextureAtlasCanvas(e => removeTextureAtlas(e)); + } catch (e) { + console.log(e); + addons.webgl.instance.dispose(); + addons.webgl.instance = undefined; term.open(terminalContainer); } - catch { - addons.webgl.instance = undefined; - } + term.focus(); addDomListener(paddingElement, 'change', setPadding); From 9e84895141a40a958ec14241a159bbf1e9f2f6a4 Mon Sep 17 00:00:00 2001 From: Jason Lin Date: Wed, 7 Dec 2022 10:12:43 +1100 Subject: [PATCH 04/30] polish --- src/browser/Terminal.ts | 2 +- src/common/services/CoreService.ts | 2 +- src/common/services/OptionsService.ts | 2 +- src/common/services/Services.ts | 6 +++--- typings/xterm.d.ts | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 2de0200e..606f3a53 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -995,7 +995,7 @@ export class Terminal extends CoreTerminal implements ITerminal { const shouldIgnoreComposition = this.browser.isMac && this.options.macOptionIsMeta && event.altKey; if (!shouldIgnoreComposition && !this._compositionHelper!.keydown(event)) { - if (this.options.scrollOnKeypress && this.buffer.ybase !== this.buffer.ydisp) { + if (this.options.scrollOnUserInput && this.buffer.ybase !== this.buffer.ydisp) { this._bufferService.scrollToBottom(); } return false; diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index 101a142a..321678a1 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -68,7 +68,7 @@ export class CoreService extends Disposable implements ICoreService { // Input is being sent to the terminal, the terminal should focus the prompt. const buffer = this._bufferService.buffer; - if (wasUserInput && this._optionsService.rawOptions.scrollOnKeypress && buffer.ybase !== buffer.ydisp) { + if (wasUserInput && this._optionsService.rawOptions.scrollOnUserInput && buffer.ybase !== buffer.ydisp) { this._scrollToBottom!(); } diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index d1e47051..9709f2a7 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -28,7 +28,7 @@ export const DEFAULT_OPTIONS: Readonly> = { linkHandler: null, logLevel: 'info', scrollback: 1000, - scrollOnKeypress: true, + scrollOnUserInput: true, scrollSensitivity: 1, screenReaderMode: false, smoothScrollDuration: 0, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 5f4e692b..a5e1c5bc 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -85,9 +85,9 @@ export interface ICoreService { /** * Triggers the onData event in the public API. * @param data The data that is being emitted. - * @param wasFromUser Whether the data originated from the user (as opposed to + * @param wasUserInput Whether the data originated from the user (as opposed to * resulting from parsing incoming data). When true this will also: - * - Scroll to the bottom of the buffer if option scrollOnKeypress is true. + * - Scroll to the bottom of the buffer if option scrollOnUserInput is true. * - Fire the `onUserInput` event (so selection can be cleared). */ triggerDataEvent(data: string, wasUserInput?: boolean): void; @@ -243,7 +243,7 @@ export interface ITerminalOptions { rows?: number; screenReaderMode?: boolean; scrollback?: number; - scrollOnKeypress?: boolean; + scrollOnUserInput?: boolean; scrollSensitivity?: number; smoothScrollDuration?: number; tabStopWidth?: number; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 2eedaac8..d5e207fa 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -194,10 +194,10 @@ declare module 'xterm' { scrollback?: number; /** - * Whether to scroll to the bottom whenever a key is pressed. The default is - * true. + * Whether to scroll to the bottom whenever there is some user input. The + * default is true. */ - scrollOnKeypress?: boolean; + scrollOnUserInput?: boolean; /** * The scrolling speed multiplier used for adjusting normal scrolling speed. From 0b56b56c069ab257a9ce55a642d5369dbc04f3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Wed, 7 Dec 2022 22:55:45 +0100 Subject: [PATCH 05/30] skipping renderer on NUL and SP --- addons/xterm-addon-canvas/src/TextRenderLayer.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/xterm-addon-canvas/src/TextRenderLayer.ts b/addons/xterm-addon-canvas/src/TextRenderLayer.ts index 66fc5106..b429e8c2 100644 --- a/addons/xterm-addon-canvas/src/TextRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/TextRenderLayer.ts @@ -95,6 +95,12 @@ export class TextRenderLayer extends BaseRenderLayer { continue; } + // exit early for NULL and SP + const code = cell.getCode(); + if (code === 0 || code === 32) { + continue; + } + // Process any joined character ranges as needed. Because of how the // ranges are produced, we know that they are valid for the characters // and attributes of our input. From d2298d84a0b2846d146dcf232d791bd1632d20ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Wed, 7 Dec 2022 23:56:43 +0100 Subject: [PATCH 06/30] move safari check to WebglAddon ctor --- addons/xterm-addon-webgl/src/WebglAddon.ts | 8 ++--- demo/client.ts | 34 +++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index 6dbbeca9..97e2ce0c 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -9,7 +9,6 @@ import { EventEmitter, forwardEvent } from 'common/EventEmitter'; import { Disposable, toDisposable } from 'common/Lifecycle'; import { getSafariVersion, isSafari } from 'common/Platform'; import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; -import { ICoreTerminal } from 'common/Types'; import { ITerminalAddon, Terminal } from 'xterm'; import { WebglRenderer } from './WebglRenderer'; @@ -29,14 +28,13 @@ export class WebglAddon extends Disposable implements ITerminalAddon { constructor( private _preserveDrawingBuffer?: boolean ) { + if (isSafari && getSafariVersion() < 16) { + throw new Error('Webgl2 is only supported on Safari 16 and above'); + } super(); } public activate(terminal: Terminal): void { - if (isSafari && getSafariVersion() < 16) { - throw new Error('Webgl2 is only supported on Safari 16 and above'); - } - const core = (terminal as any)._core as ITerminal; if (!terminal.element) { this.register(core.onWillOpen(() => this.activate(terminal))); diff --git a/demo/client.ts b/demo/client.ts index 280b5e56..7c04bb2a 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -250,7 +250,11 @@ function createTerminal(): void { addons.serialize.instance = new SerializeAddon(); addons.fit.instance = new FitAddon(); addons.unicode11.instance = new Unicode11Addon(); - addons.webgl.instance = new WebglAddon(); + try { // try to start with webgl renderer (might throw on older safari/webkit) + addons.webgl.instance = new WebglAddon(); + } catch (e) { + console.warn(e); + } addons['web-links'].instance = new WebLinksAddon(); typedTerm.loadAddon(addons.fit.instance); typedTerm.loadAddon(addons.search.instance); @@ -274,18 +278,22 @@ function createTerminal(): void { addons.fit.instance!.fit(); - // try to start with webgl renderer (might throw on older safari/webkit) - try { - typedTerm.loadAddon(addons.webgl.instance); - term.open(terminalContainer); - setTextureAtlas(addons.webgl.instance.textureAtlas); - addons.webgl.instance.onChangeTextureAtlas(e => setTextureAtlas(e)); - addons.webgl.instance.onAddTextureAtlasCanvas(e => appendTextureAtlas(e)); - addons.webgl.instance.onRemoveTextureAtlasCanvas(e => removeTextureAtlas(e)); - } catch (e) { - console.log(e); - addons.webgl.instance.dispose(); - addons.webgl.instance = undefined; + if (addons.webgl.instance) { + try { + typedTerm.loadAddon(addons.webgl.instance); + term.open(terminalContainer); + setTextureAtlas(addons.webgl.instance.textureAtlas); + addons.webgl.instance.onChangeTextureAtlas(e => setTextureAtlas(e)); + addons.webgl.instance.onAddTextureAtlasCanvas(e => appendTextureAtlas(e)); + addons.webgl.instance.onRemoveTextureAtlasCanvas(e => removeTextureAtlas(e)); + } catch (e) { + console.warn('error during loading webgl addon:', e); + addons.webgl.instance.dispose(); + addons.webgl.instance = undefined; + } + } + if (!typedTerm.element) { + // webgl loading failed for some reason, attach with DOM renderer term.open(terminalContainer); } From 440da4a5ffd07a221c82fd849535f6721138ccb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Fri, 9 Dec 2022 16:37:56 +0100 Subject: [PATCH 07/30] reeval previous active link, fixes #4295 --- src/browser/Linkifier2.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/browser/Linkifier2.ts b/src/browser/Linkifier2.ts index 236efb22..78680f6f 100644 --- a/src/browser/Linkifier2.ts +++ b/src/browser/Linkifier2.ts @@ -315,7 +315,15 @@ export class Linkifier2 extends Disposable implements ILinkifier2 { // When start is 0 a scroll most likely occurred, make sure links above the fold also get // cleared. const start = e.start === 0 ? 0 : e.start + 1 + this._bufferService.buffer.ydisp; + const oldEvent = this._currentLink ? this._lastMouseEvent : undefined; this._clearCurrentLink(start, e.end + 1 + this._bufferService.buffer.ydisp); + if (oldEvent && this._element) { + // re-eval previously active link after changes + const position = this._positionFromMouseEvent(oldEvent, this._element, this._mouseService!); + if (position) { + this._askForLink(position, false); + } + } })); } } From 6d527c42b092b811828a89246d9e3413ed943199 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 10 Dec 2022 17:06:32 +0000 Subject: [PATCH 08/30] Bump express from 4.17.1 to 4.17.3 Bumps [express](https://github.com/expressjs/express) from 4.17.1 to 4.17.3. - [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.17.1...4.17.3) --- updated-dependencies: - dependency-name: express dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- yarn.lock | 241 ++++++++++++++++++++++++------------------------------ 1 file changed, 109 insertions(+), 132 deletions(-) diff --git a/yarn.lock b/yarn.lock index 75940196..017fcd91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -822,13 +822,13 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== -accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" + mime-types "~2.1.34" + negotiator "0.6.3" acorn-globals@^6.0.0: version "6.0.0" @@ -1007,21 +1007,21 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== +body-parser@1.19.2: + version "1.19.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" + integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw== dependencies: - bytes "3.1.0" + bytes "3.1.2" content-type "~1.0.4" debug "2.6.9" depd "~1.1.2" - http-errors "1.7.2" + http-errors "1.8.1" iconv-lite "0.4.24" on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" + qs "6.9.7" + raw-body "2.4.3" + type-is "~1.6.18" brace-expansion@^1.1.7: version "1.1.11" @@ -1071,10 +1071,10 @@ 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== -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== caching-transform@^4.0.0: version "4.0.0" @@ -1309,12 +1309,12 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: - safe-buffer "5.1.2" + safe-buffer "5.2.1" content-type@~1.0.4: version "1.0.4" @@ -1333,10 +1333,10 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== cross-env@^7.0.3: version "7.0.3" @@ -1387,27 +1387,13 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" - integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== - dependencies: - ms "2.1.2" - -debug@4.3.4, debug@^4.3.4: +debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" -debug@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1834,16 +1820,16 @@ express-ws@^5.0.2: ws "^7.4.6" express@^4.17.1: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + version "4.17.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" + integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg== dependencies: - accepts "~1.3.7" + accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" + body-parser "1.19.2" + content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.4.0" + cookie "0.4.2" cookie-signature "1.0.6" debug "2.6.9" depd "~1.1.2" @@ -1857,13 +1843,13 @@ express@^4.17.1: on-finished "~2.3.0" parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" + proxy-addr "~2.0.7" + qs "6.9.7" range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" statuses "~1.5.0" type-is "~1.6.18" utils-merge "1.0.1" @@ -2004,10 +1990,10 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fraction.js@^4.1.1: version "4.2.0" @@ -2207,27 +2193,16 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== dependencies: depd "~1.1.2" inherits "2.0.4" - setprototypeof "1.1.1" + setprototypeof "1.2.0" statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" + toidentifier "1.0.1" http-proxy-agent@^5.0.0: version "5.0.0" @@ -2314,11 +2289,6 @@ inherits@2, inherits@2.0.4: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" @@ -2826,6 +2796,11 @@ mime-db@1.50.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-types@^2.1.12: version "2.1.33" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" @@ -2847,6 +2822,13 @@ mime-types@~2.1.24: dependencies: mime-db "1.44.0" +mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -2908,11 +2890,6 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -2943,10 +2920,10 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== neo-async@^2.6.2: version "2.6.2" @@ -3255,12 +3232,12 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: - forwarded "~0.1.2" + forwarded "0.2.0" ipaddr.js "1.9.1" psl@^1.1.33: @@ -3273,10 +3250,10 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@6.9.7: + version "6.9.7" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" + integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== queue-microtask@^1.2.2: version "1.2.3" @@ -3295,13 +3272,13 @@ 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.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== +raw-body@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" + integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g== dependencies: - bytes "3.1.0" - http-errors "1.7.2" + bytes "3.1.2" + http-errors "1.8.1" iconv-lite "0.4.24" unpipe "1.0.0" @@ -3405,16 +3382,16 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@5.1.2, safe-buffer@~5.1.1: +safe-buffer@5.2.1, safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -3474,10 +3451,10 @@ semver@^7.3.7: dependencies: lru-cache "^6.0.0" -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== +send@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== dependencies: debug "2.6.9" depd "~1.1.2" @@ -3486,9 +3463,9 @@ send@0.17.1: escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" - http-errors "~1.7.2" + http-errors "1.8.1" mime "1.6.0" - ms "2.1.1" + ms "2.1.3" on-finished "~2.3.0" range-parser "~1.2.1" statuses "~1.5.0" @@ -3507,25 +3484,25 @@ serialize-javascript@^5.0.1: dependencies: randombytes "^2.1.0" -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== +serve-static@1.14.2: + version "1.14.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.17.1" + send "0.17.2" set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== shallow-clone@^3.0.0: version "3.0.1" @@ -3797,10 +3774,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== tough-cookie@^4.0.0: version "4.0.0" @@ -3869,7 +3846,7 @@ type-fest@^0.8.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.17, type-is@~1.6.18: +type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== From d6b8a21219fe3f94818b4e072dcfb73a7a068b02 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:35:11 -0800 Subject: [PATCH 09/30] Avoid passing circular callback into CoreService ctor --- src/common/CoreTerminal.ts | 3 ++- src/common/InputHandler.test.ts | 4 ++-- src/common/TestUtils.test.ts | 1 + src/common/services/CoreService.test.ts | 1 - src/common/services/CoreService.ts | 11 +++-------- src/common/services/Services.ts | 1 + 6 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index c5182554..33637421 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -109,7 +109,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { this._instantiationService.setService(IBufferService, this._bufferService); this._logService = this.register(this._instantiationService.createInstance(LogService)); this._instantiationService.setService(ILogService, this._logService); - this.coreService = this.register(this._instantiationService.createInstance(CoreService, () => this.scrollToBottom())); + this.coreService = this.register(this._instantiationService.createInstance(CoreService)); this._instantiationService.setService(ICoreService, this.coreService); this.coreMouseService = this.register(this._instantiationService.createInstance(CoreMouseService)); this._instantiationService.setService(ICoreMouseService, this.coreMouseService); @@ -129,6 +129,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { this.register(forwardEvent(this._bufferService.onResize, this._onResize)); this.register(forwardEvent(this.coreService.onData, this._onData)); this.register(forwardEvent(this.coreService.onBinary, this._onBinary)); + this.register(this.coreService.onRequestScrollToBottom(() => this.scrollToBottom())); this.register(this.coreService.onUserInput(() => this._writeBuffer.handleUserInput())); this.register(this.optionsService.onSpecificOptionChange('windowsMode', e => this._handleWindowsModeOptionChange(e))); this.register(this._bufferService.onScroll(event => { diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index 110e4f51..858019ff 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -65,7 +65,7 @@ describe('InputHandler', () => { optionsService = new MockOptionsService(); bufferService = new BufferService(optionsService); bufferService.resize(80, 30); - coreService = new CoreService(() => { }, bufferService, new MockLogService(), optionsService); + coreService = new CoreService(bufferService, new MockLogService(), optionsService); inputHandler = new TestInputHandler(bufferService, new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService()); }); @@ -2300,7 +2300,7 @@ describe('InputHandler - async handlers', () => { optionsService = new MockOptionsService(); bufferService = new BufferService(optionsService); bufferService.resize(80, 30); - coreService = new CoreService(() => { }, bufferService, new MockLogService(), optionsService); + coreService = new CoreService(bufferService, new MockLogService(), optionsService); coreService.onData(data => { console.log(data); }); inputHandler = new TestInputHandler(bufferService, new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService()); diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 3aa0f694..cae90ec8 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -95,6 +95,7 @@ export class MockCoreService implements ICoreService { public onData: IEvent = new EventEmitter().event; public onUserInput: IEvent = new EventEmitter().event; public onBinary: IEvent = new EventEmitter().event; + public onRequestScrollToBottom: IEvent = new EventEmitter().event; public reset(): void { } public triggerDataEvent(data: string, wasUserInput?: boolean): void { } public triggerBinaryEvent(data: string): void { } diff --git a/src/common/services/CoreService.test.ts b/src/common/services/CoreService.test.ts index 00be4953..44018494 100644 --- a/src/common/services/CoreService.test.ts +++ b/src/common/services/CoreService.test.ts @@ -13,7 +13,6 @@ describe('CoreService', () => { beforeEach(() => { coreService = new CoreService( - () => {}, new MockBufferService(80, 30), new MockLogService(), new MockOptionsService()); diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index 9282197b..2c5d5706 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -31,26 +31,21 @@ export class CoreService extends Disposable implements ICoreService { public modes: IModes; public decPrivateModes: IDecPrivateModes; - // Circular dependency, this must be unset or memory will leak after Terminal.dispose - private _scrollToBottom: (() => void) | undefined; - private readonly _onData = this.register(new EventEmitter()); public readonly onData = this._onData.event; private readonly _onUserInput = this.register(new EventEmitter()); public readonly onUserInput = this._onUserInput.event; private readonly _onBinary = this.register(new EventEmitter()); public readonly onBinary = this._onBinary.event; + private readonly _onRequestScrollToBottom = this.register(new EventEmitter()); + public readonly onRequestScrollToBottom = this._onRequestScrollToBottom.event; constructor( - // TODO: Move this into a service - scrollToBottom: () => void, @IBufferService private readonly _bufferService: IBufferService, @ILogService private readonly _logService: ILogService, @IOptionsService private readonly _optionsService: IOptionsService ) { super(); - this._scrollToBottom = scrollToBottom; - this.register({ dispose: () => this._scrollToBottom = undefined }); this.modes = clone(DEFAULT_MODES); this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES); } @@ -69,7 +64,7 @@ export class CoreService extends Disposable implements ICoreService { // Input is being sent to the terminal, the terminal should focus the prompt. const buffer = this._bufferService.buffer; if (buffer.ybase !== buffer.ydisp) { - this._scrollToBottom!(); + this._onRequestScrollToBottom.fire(); } // Fire onUserInput so listeners can react as well (eg. clear selection) diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index cc388063..3648b338 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -79,6 +79,7 @@ export interface ICoreService { readonly onData: IEvent; readonly onUserInput: IEvent; readonly onBinary: IEvent; + readonly onRequestScrollToBottom: IEvent; reset(): void; From 69379ba59bf5c8b369675e65116c73ece6f0ec85 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 11:33:03 -0800 Subject: [PATCH 10/30] Simplify options API Fixes #4259 --- typings/xterm.d.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 926cc6b4..4c2291f9 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -704,29 +704,24 @@ declare module 'xterm' { * Gets or sets the terminal options. This supports setting multiple options. * * @example Get a single option - * ```typescript + * ```ts * console.log(terminal.options.fontSize); * ``` - */ - get options(): Required; - - /** - * Gets or sets the terminal options. This supports setting multiple options. * * @example Set a single option - * ```typescript + * ```ts * terminal.options.fontSize = 12; * ``` * * @example Set multiple options - * ```typescript + * ```ts * terminal.options = { * fontSize: 12, * fontFamily: 'Arial', * }; * ``` */ - set options(options: ITerminalOptions); + options: ITerminalOptions; /** * Natural language strings that can be localized. From 2bd38695470c70744432df5098eb6bd22214ec85 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 11:33:23 -0800 Subject: [PATCH 11/30] Use a monospace font in example --- 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 4c2291f9..ba179b96 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -717,7 +717,7 @@ declare module 'xterm' { * ```ts * terminal.options = { * fontSize: 12, - * fontFamily: 'Arial', + * fontFamily: 'Courier New' * }; * ``` */ From c118f0418728ad3ffa5514fd9019c21a602efc91 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 11:36:32 -0800 Subject: [PATCH 12/30] Sync xterm-headless.d.ts --- typings/xterm-headless.d.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index af55ffac..2ceb6a94 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -537,11 +537,6 @@ declare module 'xterm-headless' { * ```typescript * console.log(terminal.options.fontSize); * ``` - */ - get options(): Required; - - /** - * Gets or sets the terminal options. This supports setting multiple options. * * @example Set a single option * ```typescript @@ -552,11 +547,11 @@ declare module 'xterm-headless' { * ```typescript * terminal.options = { * fontSize: 12, - * fontFamily: 'Arial', + * fontFamily: 'Courier New', * }; * ``` */ - set options(options: ITerminalOptions); + options: ITerminalOptions; /** * Natural language strings that can be localized. From 02d3ef599a3d7f38eb4cd273ffe60a7a2dccdc8a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 11:42:14 -0800 Subject: [PATCH 13/30] Fix internal usages that needed Required --- .../xterm-addon-canvas/src/BaseRenderLayer.ts | 2 +- addons/xterm-addon-webgl/src/WebglRenderer.ts | 17 ++++++------- .../src/renderLayer/BaseRenderLayer.ts | 4 +++- .../src/renderLayer/CursorRenderLayer.ts | 8 +++---- .../src/renderLayer/LinkRenderLayer.ts | 4 +++- src/browser/renderer/shared/CharAtlasCache.ts | 7 +++--- src/browser/renderer/shared/CharAtlasUtils.ts | 24 +++++++++---------- 7 files changed, 35 insertions(+), 31 deletions(-) diff --git a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts index d2a7a4ed..6c9ebd3c 100644 --- a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts @@ -122,7 +122,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer return; } this._charAtlasDisposable?.dispose(); - this._charAtlas = acquireTextureAtlas(this._terminal, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr); + this._charAtlas = acquireTextureAtlas(this._terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr); this._charAtlasDisposable = forwardEvent(this._charAtlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas); this._charAtlas.warmUp(); for (let i = 0; i < this._charAtlas.pages.length; i++) { diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 97e8dd7d..db379214 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -67,7 +67,7 @@ export class WebglRenderer extends Disposable implements IRenderer { private readonly _coreBrowserService: ICoreBrowserService, coreService: ICoreService, private readonly _decorationService: IDecorationService, - optionsService: IOptionsService, + private readonly _optionsService: IOptionsService, private readonly _themeService: IThemeService, preserveDrawingBuffer?: boolean ) { @@ -80,13 +80,13 @@ export class WebglRenderer extends Disposable implements IRenderer { this._core = (this._terminal as any)._core; this._renderLayers = [ - new LinkRenderLayer(this._core.screenElement!, 2, this._terminal, this._core.linkifier2, this._coreBrowserService, this._themeService), - new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._onRequestRedraw, this._coreBrowserService, coreService, this._themeService, optionsService) + new LinkRenderLayer(this._core.screenElement!, 2, this._terminal, this._core.linkifier2, this._coreBrowserService, _optionsService, this._themeService), + new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._onRequestRedraw, this._coreBrowserService, coreService, _optionsService, this._themeService) ]; this.dimensions = createRenderDimensions(); this._devicePixelRatio = this._coreBrowserService.dpr; this._updateDimensions(); - this.register(optionsService.onOptionChange(() => this._handleOptionsChanged())); + this.register(_optionsService.onOptionChange(() => this._handleOptionsChanged())); this._canvas = document.createElement('canvas'); @@ -259,6 +259,7 @@ export class WebglRenderer extends Disposable implements IRenderer { const atlas = acquireTextureAtlas( this._terminal, + this._optionsService.rawOptions, this._themeService.colors, this.dimensions.device.cell.width, this.dimensions.device.cell.height, @@ -469,18 +470,18 @@ export class WebglRenderer extends Disposable implements IRenderer { // Calculate the device cell height, if lineHeight is _not_ 1, the resulting value will be // floored since lineHeight can never be lower then 1, this guarentees the device cell height // will always be larger than device char height. - this.dimensions.device.cell.height = Math.floor(this.dimensions.device.char.height * this._terminal.options.lineHeight); + this.dimensions.device.cell.height = Math.floor(this.dimensions.device.char.height * this._optionsService.rawOptions.lineHeight); // Calculate the y offset within a cell that glyph should draw at in order for it to be centered // correctly within the cell. - this.dimensions.device.char.top = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.device.cell.height - this.dimensions.device.char.height) / 2); + this.dimensions.device.char.top = this._optionsService.rawOptions.lineHeight === 1 ? 0 : Math.round((this.dimensions.device.cell.height - this.dimensions.device.char.height) / 2); // Calculate the device cell width, taking the letterSpacing into account. - this.dimensions.device.cell.width = this.dimensions.device.char.width + Math.round(this._terminal.options.letterSpacing); + this.dimensions.device.cell.width = this.dimensions.device.char.width + Math.round(this._optionsService.rawOptions.letterSpacing); // Calculate the x offset with a cell that text should draw from in order for it to be centered // correctly within the cell. - this.dimensions.device.char.left = Math.floor(this._terminal.options.letterSpacing / 2); + this.dimensions.device.char.left = Math.floor(this._optionsService.rawOptions.letterSpacing / 2); // Recalculate the canvas dimensions, the device dimensions define the actual number of pixel in // the canvas diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index e30ef25b..1a45eb5e 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -13,6 +13,7 @@ import { IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types' import { CellData } from 'common/buffer/CellData'; import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; import { Disposable, toDisposable } from 'common/Lifecycle'; +import { IOptionsService } from 'common/services/Services'; export abstract class BaseRenderLayer extends Disposable implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -33,6 +34,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer zIndex: number, private _alpha: boolean, protected readonly _coreBrowserService: ICoreBrowserService, + protected readonly _optionsService: IOptionsService, protected readonly _themeService: IThemeService ) { super(); @@ -93,7 +95,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) { return; } - this._charAtlas = acquireTextureAtlas(terminal, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr); + this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr); this._charAtlas.warmUp(); } diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index cb288f24..49c80588 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -39,10 +39,10 @@ export class CursorRenderLayer extends BaseRenderLayer { private _onRequestRefreshRowsEvent: IEventEmitter, coreBrowserService: ICoreBrowserService, private readonly _coreService: ICoreService, - themeService: IThemeService, - optionsService: IOptionsService + optionsService: IOptionsService, + themeService: IThemeService ) { - super(terminal, container, 'cursor', zIndex, true, coreBrowserService, themeService); + super(terminal, container, 'cursor', zIndex, true, coreBrowserService, optionsService, themeService); this._state = { x: 0, y: 0, @@ -213,7 +213,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _renderBarCursor(terminal: Terminal, x: number, y: number, cell: ICellData): void { this._ctx.save(); this._ctx.fillStyle = this._themeService.colors.cursor.css; - this._fillLeftLineAtCell(x, y, terminal.options.cursorWidth); + this._fillLeftLineAtCell(x, y, this._optionsService.rawOptions.cursorWidth); this._ctx.restore(); } diff --git a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts index 77b02420..aefc9f6e 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts @@ -8,6 +8,7 @@ import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants'; import { IRenderDimensions } from 'browser/renderer/shared/Types'; import { ICoreBrowserService, IThemeService } from 'browser/services/Services'; import { ILinkifier2, ILinkifierEvent } from 'browser/Types'; +import { IOptionsService } from 'common/services/Services'; import { Terminal } from 'xterm'; import { BaseRenderLayer } from './BaseRenderLayer'; @@ -20,9 +21,10 @@ export class LinkRenderLayer extends BaseRenderLayer { terminal: Terminal, linkifier2: ILinkifier2, coreBrowserService: ICoreBrowserService, + optionsService: IOptionsService, themeService: IThemeService ) { - super(terminal, container, 'link', zIndex, true, coreBrowserService, themeService); + super(terminal, container, 'link', zIndex, true, coreBrowserService, optionsService, themeService); this.register(linkifier2.onShowLinkUnderline(e => this._handleShowLinkUnderline(e))); this.register(linkifier2.onHideLinkUnderline(e => this._handleHideLinkUnderline(e))); diff --git a/src/browser/renderer/shared/CharAtlasCache.ts b/src/browser/renderer/shared/CharAtlasCache.ts index 48368a16..67343912 100644 --- a/src/browser/renderer/shared/CharAtlasCache.ts +++ b/src/browser/renderer/shared/CharAtlasCache.ts @@ -4,7 +4,7 @@ */ import { TextureAtlas } from 'browser/renderer/shared/TextureAtlas'; -import { Terminal } from 'xterm'; +import { ITerminalOptions, Terminal } from 'xterm'; import { ITerminal, ReadonlyColorSet } from 'browser/Types'; import { ICharAtlasConfig, ITextureAtlas } from 'browser/renderer/shared/Types'; import { generateConfig, configEquals } from 'browser/renderer/shared/CharAtlasUtils'; @@ -22,11 +22,10 @@ const charAtlasCache: ITextureAtlasCacheEntry[] = []; /** * Acquires a char atlas, either generating a new one or returning an existing * one that is in use by another terminal. - * @param terminal The terminal. - * @param colors The colors to use. */ export function acquireTextureAtlas( terminal: Terminal, + options: Required, colors: ReadonlyColorSet, deviceCellWidth: number, deviceCellHeight: number, @@ -34,7 +33,7 @@ export function acquireTextureAtlas( deviceCharHeight: number, devicePixelRatio: number ): ITextureAtlas { - const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, terminal, colors, devicePixelRatio); + const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio); // Check to see if the terminal already owns this config for (let i = 0; i < charAtlasCache.length; i++) { diff --git a/src/browser/renderer/shared/CharAtlasUtils.ts b/src/browser/renderer/shared/CharAtlasUtils.ts index e69b476a..89b21dbc 100644 --- a/src/browser/renderer/shared/CharAtlasUtils.ts +++ b/src/browser/renderer/shared/CharAtlasUtils.ts @@ -5,11 +5,11 @@ import { ICharAtlasConfig } from './Types'; import { Attributes } from 'common/buffer/Constants'; -import { Terminal } from 'xterm'; +import { ITerminalOptions } from 'xterm'; import { IColorSet, ReadonlyColorSet } from 'browser/Types'; import { NULL_COLOR } from 'common/Color'; -export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, terminal: Terminal, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig { +export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig { // null out some fields that don't matter const clonedColors: IColorSet = { foreground: colors.foreground, @@ -27,21 +27,21 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number contrastCache: colors.contrastCache }; return { - customGlyphs: terminal.options.customGlyphs, + customGlyphs: options.customGlyphs, devicePixelRatio, - letterSpacing: terminal.options.letterSpacing, - lineHeight: terminal.options.lineHeight, + letterSpacing: options.letterSpacing, + lineHeight: options.lineHeight, deviceCellWidth: deviceCellWidth, deviceCellHeight: deviceCellHeight, deviceCharWidth: deviceCharWidth, deviceCharHeight: deviceCharHeight, - fontFamily: terminal.options.fontFamily, - fontSize: terminal.options.fontSize, - fontWeight: terminal.options.fontWeight, - fontWeightBold: terminal.options.fontWeightBold, - allowTransparency: terminal.options.allowTransparency, - drawBoldTextInBrightColors: terminal.options.drawBoldTextInBrightColors, - minimumContrastRatio: terminal.options.minimumContrastRatio, + fontFamily: options.fontFamily, + fontSize: options.fontSize, + fontWeight: options.fontWeight, + fontWeightBold: options.fontWeightBold, + allowTransparency: options.allowTransparency, + drawBoldTextInBrightColors: options.drawBoldTextInBrightColors, + minimumContrastRatio: options.minimumContrastRatio, colors: clonedColors }; } From 7b28dc4d59c5c2ba16bef33ce933972c596e07f0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 11:47:09 -0800 Subject: [PATCH 14/30] Fix line height and letter spacing on canvas renderer Fixes #4221 --- addons/xterm-addon-canvas/src/BaseRenderLayer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts index d2a7a4ed..72b1bca8 100644 --- a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts @@ -389,8 +389,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer glyph.texturePosition.y, glyph.size.x, glyph.size.y, - x * this._deviceCellWidth - glyph.offset.x, - y * this._deviceCellHeight - glyph.offset.y, + x * this._deviceCellWidth + this._deviceCharLeft - glyph.offset.x, + y * this._deviceCellHeight + this._deviceCharTop - glyph.offset.y, glyph.size.x, glyph.size.y ); From 74ea0c23ca15974ff2c0aafc1d2d8dc4998b463a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 11 Dec 2022 13:11:16 -0800 Subject: [PATCH 15/30] Add combo entries to sgr test for testing multiple sgr --- demo/client.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/demo/client.ts b/demo/client.ts index 7c04bb2a..092e5636 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -969,6 +969,20 @@ function sgrTest(): void { for (const e of entries) { term.writeln(`\x1b[0m\x1b[${e.ps}m ${e.ps.toString().padEnd(2, ' ')} ${e.name.padEnd(maxNameLength, ' ')} - ${testString}\x1b[0m`); } + const entriesByPs: Map = new Map(); + for (const e of entries) { + entriesByPs.set(e.ps, e.name); + } + const comboEntries: { ps: number[] }[] = [ + { ps: [1, 2, 3, 4, 5, 6, 7, 9] }, + { ps: [2, 41] } + ]; + term.write('\n\n\r'); + term.writeln(`Combinations`); + for (const e of comboEntries) { + const name = e.ps.map(e => entriesByPs.get(e)).join(', '); + term.writeln(`\x1b[0m\x1b[${e.ps.join(';')}m ${name}\n\r${testString}\x1b[0m`); + } } function addAnsiHyperlink(): void { From 15e3b1ac128a452b48b476e21a86475ba33c3891 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 14 Dec 2022 08:10:52 -0800 Subject: [PATCH 16/30] Improve explanation of danger with the linkHandler API Fixes #4309 --- src/browser/OscLinkProvider.ts | 2 +- typings/xterm.d.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/browser/OscLinkProvider.ts b/src/browser/OscLinkProvider.ts index 3ca93b09..c621ddf2 100644 --- a/src/browser/OscLinkProvider.ts +++ b/src/browser/OscLinkProvider.ts @@ -94,7 +94,7 @@ export class OscLinkProvider implements ILinkProvider { } function defaultActivate(e: MouseEvent, uri: string): void { - const answer = confirm(`Do you want to navigate to ${uri}?`); + const answer = confirm(`Do you want to navigate to ${uri}?\n\nWARNING: This link could potentially be dangerous`); if (answer) { const newWindow = window.open(); if (newWindow) { diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 322cb150..6168ff4b 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -129,9 +129,14 @@ declare module 'xterm' { /** * The handler for OSC 8 hyperlinks. Links will use the `confirm` browser - * API if no link handler is set. Consider the security of users when using - * this, there should be some tooltip or prompt when hovering or activating - * the link. + * API with a strongly worded warning if no link handler is set. + * + * When setting this, consider the security of users opening these links, + * at a minimum there should be a tooltip or a prompt when hovering or + * activating the link respectively. An example of what might be possible is + * a terminal app writing link in the form `javascript:...` that runs some + * javascript, a safe approach to prevent that is to validate the link + * starts with http(s)://. */ linkHandler?: ILinkHandler | null; From fd8a0690c9cfe297e96bf679f363b7092ae33e63 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 14 Dec 2022 09:28:25 -0800 Subject: [PATCH 17/30] Add VT arrow buttons Part of #2064 --- demo/client.ts | 31 +++++++++++++++++++++++++++++++ demo/index.html | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/demo/client.ts b/demo/client.ts index 092e5636..759b0658 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -228,6 +228,7 @@ if (document.location.pathname === '/test') { document.getElementById('sgr-test').addEventListener('click', sgrTest); document.getElementById('add-decoration').addEventListener('click', addDecoration); document.getElementById('add-overview-ruler').addEventListener('click', addOverviewRuler); + addVtButtons(); } function createTerminal(): void { @@ -1091,3 +1092,33 @@ function addOverviewRuler(): void { ); console.groupEnd(); }; + +function addVtButtons(): void { + function csi(e: string): string { + return `\x1b[${e}`; + } + + const vtCUU = (): void => term.write(csi('A')); + const vtCUD = (): void => term.write(csi('B')); + const vtCUF = (): void => term.write(csi('C')); + const vtCUB = (): void => term.write(csi('D')); + + function createButton(name: string, writeCsi: string): HTMLElement { + const element = document.createElement('button'); + element.textContent = name; + element.addEventListener('click', () => term.write(csi(writeCsi))); + return element; + } + const vtFragment = document.createDocumentFragment(); + const buttonSpecs: { [key: string]: string } = { + A: 'CUU ↑', + B: 'CUD ↓', + C: 'CUF →', + D: 'CUB ←' + }; + for (const s of Object.keys(buttonSpecs)) { + vtFragment.appendChild(createButton(buttonSpecs[s], s)); + } + + document.querySelector('#vt-container').appendChild(vtFragment); +} diff --git a/demo/index.html b/demo/index.html index 0a7c8bb3..5662f361 100644 --- a/demo/index.html +++ b/demo/index.html @@ -23,6 +23,7 @@ +

Options

@@ -89,6 +90,10 @@
+
+

VT

+
+
From 852255ea03b9d838476ccff50c51c5b9bf303942 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 14 Dec 2022 12:10:48 -0800 Subject: [PATCH 18/30] Point new issue questions at GH discussions --- .github/ISSUE_TEMPLATE/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index dccd0c5d..59beeeb9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Question - url: https://stackoverflow.com/questions/tagged/xtermjs - about: Please ask and answer questions here. + - name: Support / Q&A + url: https://github.com/xtermjs/xterm.js/discussions/categories/q-a + about: Use GitHub Discussions for community support and general Q&A From c9c07aeabd7eab948a49fcbe068c55122f4c1b59 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:15:05 -0800 Subject: [PATCH 19/30] Support slash and triangle custom glyphs This also fixes an issue with padding making glyphs regress Fixes #4258 --- src/browser/renderer/shared/CustomGlyphs.ts | 32 +++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/browser/renderer/shared/CustomGlyphs.ts b/src/browser/renderer/shared/CustomGlyphs.ts index fd56376b..6b632444 100644 --- a/src/browser/renderer/shared/CustomGlyphs.ts +++ b/src/browser/renderer/shared/CustomGlyphs.ts @@ -362,15 +362,31 @@ export const powerlineDefinitions: { [index: string]: IVectorShape } = { '\u{E0B2}': { d: 'M1,0 L0,.5 L1,1', type: VectorType.FILL, leftPadding: 2 }, // Left triangle line '\u{E0B3}': { d: 'M2,-.5 L0,.5 L2,1.5', type: VectorType.STROKE, leftPadding: 1, rightPadding: 1 }, - // Right semi-circle solid, + // Right semi-circle solid '\u{E0B4}': { d: 'M0,0 L0,1 C0.552,1,1,0.776,1,.5 C1,0.224,0.552,0,0,0', type: VectorType.FILL, rightPadding: 1 }, - // Right semi-circle line, + // Right semi-circle line '\u{E0B5}': { d: 'M0,1 C0.552,1,1,0.776,1,.5 C1,0.224,0.552,0,0,0', type: VectorType.STROKE, rightPadding: 1 }, - // Left semi-circle solid, + // Left semi-circle solid '\u{E0B6}': { d: 'M1,0 L1,1 C0.448,1,0,0.776,0,.5 C0,0.224,0.448,0,1,0', type: VectorType.FILL, leftPadding: 1 }, - // Left semi-circle line, - '\u{E0B7}': { d: 'M1,1 C0.448,1,0,0.776,0,.5 C0,0.224,0.448,0,1,0', type: VectorType.STROKE, leftPadding: 1 } + // Left semi-circle line + '\u{E0B7}': { d: 'M1,1 C0.448,1,0,0.776,0,.5 C0,0.224,0.448,0,1,0', type: VectorType.STROKE, leftPadding: 1 }, + // Lower left triangle + '\u{E0B8}': { d: 'M-.5,-.5 L1.5,1.5 L-.5,1.5', type: VectorType.FILL }, + // Backslash separator + '\u{E0B9}': { d: 'M-.5,-.5 L1.5,1.5', type: VectorType.STROKE, leftPadding: 1, rightPadding: 1 }, + // Lower right triangle + '\u{E0BA}': { d: 'M1.5,-.5 L-.5,1.5 L1.5,1.5', type: VectorType.FILL }, + // Upper left triangle + '\u{E0BC}': { d: 'M1.5,-.5 L-.5,1.5 L-.5,-.5', type: VectorType.FILL }, + // Forward slash separator + '\u{E0BD}': { d: 'M1.5,-.5 L-.5,1.5', type: VectorType.STROKE, leftPadding: 1, rightPadding: 1 }, + // Upper right triangle + '\u{E0BE}': { d: 'M-.5,-.5 L1.5,1.5 L1.5,-.5', type: VectorType.FILL } }; +// Backslash separator redundant +powerlineDefinitions['\u{E0BB}'] = powerlineDefinitions['\u{E0B9}']; +// Forward slash separator redundant +powerlineDefinitions['\u{E0BF}'] = powerlineDefinitions['\u{E0BD}']; /** * Try drawing a custom block element or box drawing character, returning whether it was @@ -584,6 +600,11 @@ function drawPowerlineChar( fontSize: number, devicePixelRatio: number ): void { + // Clip the cell to make sure drawing doesn't occur beyond bounds + const clipRegion = new Path2D(); + clipRegion.rect(xOffset, yOffset, deviceCellWidth, deviceCellHeight); + ctx.clip(clipRegion); + ctx.beginPath(); // Scale the stroke with DPR and font size const cssLineWidth = fontSize / 12; @@ -606,6 +627,7 @@ function drawPowerlineChar( xOffset, yOffset, false, + devicePixelRatio, (charDefinition.leftPadding ?? 0) * (cssLineWidth / 2), (charDefinition.rightPadding ?? 0) * (cssLineWidth / 2) )); From fc4196813129c007970c095d9837b6d19a3d651c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 15 Dec 2022 07:50:45 -0800 Subject: [PATCH 20/30] Allow scroll bar interaction in demo in screenReaderMode Fixes #2757 --- css/xterm.css | 1 - src/browser/AccessibilityManager.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/css/xterm.css b/css/xterm.css index e9fd8153..9471e1eb 100644 --- a/css/xterm.css +++ b/css/xterm.css @@ -146,7 +146,6 @@ left: 0; top: 0; bottom: 0; - right: 0; z-index: 10; color: transparent; } diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index 3998e779..8ebcf823 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -277,6 +277,7 @@ export class AccessibilityManager extends Disposable { if (!this._renderService.dimensions.css.cell.height) { return; } + this._accessibilityTreeRoot.style.width = `${this._renderService.dimensions.css.canvas.width}px`; if (this._rowElements.length !== this._terminal.rows) { this._handleResize(this._terminal.rows); } From aba59e9386cdad27b15a76619912cdeeb741aaca Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 15 Dec 2022 16:41:31 -0800 Subject: [PATCH 21/30] Explain object option edge case Fixes #4124 --- typings/xterm.d.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 6168ff4b..b652491a 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -712,17 +712,30 @@ declare module 'xterm' { readonly modes: IModes; /** - * Gets or sets the terminal options. This supports setting multiple options. + * Gets or sets the terminal options. This supports setting multiple + * options. * * @example Get a single option * ```ts * console.log(terminal.options.fontSize); * ``` * - * @example Set a single option + * @example Set a single option: * ```ts * terminal.options.fontSize = 12; * ``` + * Note that for options that are object, a new object must be used in order + * to take effect as a reference comparison will be done: + * ```ts + * const newValue = terminal.options.theme; + * newValue.background = '#000000'; + * + * // This won't work + * terminal.options.theme = newValue; + * + * // This will work + * terminal.options.theme = { ...newValue }; + * ``` * * @example Set multiple options * ```ts From 8636d0f82014b2107281de9d2e7d2827f58e3921 Mon Sep 17 00:00:00 2001 From: RyotaK <49341894+Ry0taK@users.noreply.github.com> Date: Sat, 17 Dec 2022 01:31:11 +0900 Subject: [PATCH 22/30] Add allowNonHttpProtocols to typings --- typings/xterm.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index b652491a..836299de 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1179,6 +1179,13 @@ declare module 'xterm' { * @param range The buffer range of the link. */ leave?(event: MouseEvent, text: string, range: IBufferRange): void; + + /** + * Whether to allow the use of non HTTP URLs in OscLinkProvider. When false, any usage of non + * HTTP URLs will be ignored. Enabling this option without proper protection in activate function + * may allow XSS. + */ + allowNonHttpProtocols?: boolean; } /** From cb8d93a1ef137a0a7a8d193e431091ec216b91ea Mon Sep 17 00:00:00 2001 From: RyotaK <49341894+Ry0taK@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:50:57 +0000 Subject: [PATCH 23/30] Implement protocol validation --- src/browser/OscLinkProvider.ts | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/browser/OscLinkProvider.ts b/src/browser/OscLinkProvider.ts index c621ddf2..1b6ee483 100644 --- a/src/browser/OscLinkProvider.ts +++ b/src/browser/OscLinkProvider.ts @@ -66,14 +66,25 @@ export class OscLinkProvider implements ILinkProvider { y } }; - // OSC links always use underline and pointer decorations - result.push({ - text, - range, - activate: (e, text) => (linkHandler ? linkHandler.activate(e, text, range) : defaultActivate(e, text)), - hover: (e, text) => linkHandler?.hover?.(e, text, range), - leave: (e, text) => linkHandler?.leave?.(e, text, range) - }); + + let ignoreLink = false; + if (!linkHandler?.allowNonHttpProtocols) { + const parsed = new URL(text); + if (!['http:', 'https:'].includes(parsed.protocol)) { + ignoreLink = true; + } + } + + if (!ignoreLink) { + // OSC links always use underline and pointer decorations + result.push({ + text, + range, + activate: (e, text) => (linkHandler ? linkHandler.activate(e, text, range) : defaultActivate(e, text)), + hover: (e, text) => linkHandler?.hover?.(e, text, range), + leave: (e, text) => linkHandler?.leave?.(e, text, range) + }); + } } finishLink = false; From e4b473785d77779313471f10f3dd5c5e86dcf68e Mon Sep 17 00:00:00 2001 From: RyotaK <49341894+Ry0taK@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:54:27 +0000 Subject: [PATCH 24/30] Make comment more clear --- typings/xterm.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 836299de..a7c197e1 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1181,9 +1181,9 @@ declare module 'xterm' { leave?(event: MouseEvent, text: string, range: IBufferRange): void; /** - * Whether to allow the use of non HTTP URLs in OscLinkProvider. When false, any usage of non - * HTTP URLs will be ignored. Enabling this option without proper protection in activate function - * may allow XSS. + * Whether to receive non HTTP URLs from LinkProvider. When false, any usage of non HTTP URLs + * will be ignored. Enabling this option without proper protection in `activate` function + * may cause security issues such as XSS. */ allowNonHttpProtocols?: boolean; } From b07c016fea1a8449abc473bddfe2f300f4f902bb Mon Sep 17 00:00:00 2001 From: RyotaK <49341894+Ry0taK@users.noreply.github.com> Date: Fri, 16 Dec 2022 16:58:35 +0000 Subject: [PATCH 25/30] Adjust the comment --- 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 a7c197e1..dc7c38b2 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1181,7 +1181,7 @@ declare module 'xterm' { leave?(event: MouseEvent, text: string, range: IBufferRange): void; /** - * Whether to receive non HTTP URLs from LinkProvider. When false, any usage of non HTTP URLs + * Whether to receive non-HTTP URLs from LinkProvider. When false, any usage of non-HTTP URLs * will be ignored. Enabling this option without proper protection in `activate` function * may cause security issues such as XSS. */ From b3d36478ca52763cbcff24f457001894b9be2841 Mon Sep 17 00:00:00 2001 From: RyotaK <49341894+Ry0taK@users.noreply.github.com> Date: Fri, 16 Dec 2022 17:01:00 +0000 Subject: [PATCH 26/30] Properly handle errors from URL constructor --- src/browser/OscLinkProvider.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/browser/OscLinkProvider.ts b/src/browser/OscLinkProvider.ts index 1b6ee483..648ffa44 100644 --- a/src/browser/OscLinkProvider.ts +++ b/src/browser/OscLinkProvider.ts @@ -69,8 +69,13 @@ export class OscLinkProvider implements ILinkProvider { let ignoreLink = false; if (!linkHandler?.allowNonHttpProtocols) { - const parsed = new URL(text); - if (!['http:', 'https:'].includes(parsed.protocol)) { + try { + const parsed = new URL(text); + if (!['http:', 'https:'].includes(parsed.protocol)) { + ignoreLink = true; + } + } catch (e) { + // Ignore invalid URLs to prevent unexpected behaviors ignoreLink = true; } } From 2bd9c4e83910525003df702cfe5dc4c772f42481 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Dec 2022 09:27:32 -0800 Subject: [PATCH 27/30] Fix canvas renderer selection not re-rendering sometimes Fixes #4056 --- src/browser/Terminal.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 606f3a53..0f8c670d 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -450,12 +450,16 @@ export class Terminal extends CoreTerminal implements ITerminal { this.textarea.setAttribute('autocapitalize', 'off'); this.textarea.setAttribute('spellcheck', 'false'); this.textarea.tabIndex = 0; + + // Register the core browser service before the generic textarea handlers are registered so it + // handles them first. Otherwise the renderers may use the wrong focus state. + this._coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea, this._document.defaultView ?? window); + this._instantiationService.setService(ICoreBrowserService, this._coreBrowserService); + this.register(addDisposableDomListener(this.textarea, 'focus', (ev: KeyboardEvent) => this._handleTextAreaFocus(ev))); this.register(addDisposableDomListener(this.textarea, 'blur', () => this._handleTextAreaBlur())); this._helperContainer.appendChild(this.textarea); - this._coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea, this._document.defaultView ?? window); - this._instantiationService.setService(ICoreBrowserService, this._coreBrowserService); this._charSizeService = this._instantiationService.createInstance(CharSizeService, this._document, this._helperContainer); this._instantiationService.setService(ICharSizeService, this._charSizeService); From ea7571c2b91e99df37ca1e1009c28b25e528e923 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Dec 2022 10:42:05 -0800 Subject: [PATCH 28/30] Fix NPE in webgl renderer Theory is this can happen when a resize down happens as end will be too big See microsoft/vscode#166878 --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index db379214..3cbd429c 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -351,7 +351,7 @@ export class WebglRenderer extends Disposable implements IRenderer { let lastBg: number; let y: number; let row: number; - let line: IBufferLine; + let line: IBufferLine | undefined; let joinedRanges: [number, number][]; let isJoined: boolean; let lastCharX: number; @@ -364,7 +364,10 @@ export class WebglRenderer extends Disposable implements IRenderer { for (y = start; y <= end; y++) { row = y + terminal.buffer.ydisp; - line = terminal.buffer.lines.get(row)!; + line = terminal.buffer.lines.get(row); + if (!line) { + break; + } this._model.lineLengths[y] = 0; joinedRanges = this._characterJoinerService.getJoinedCharacters(row); for (x = 0; x < terminal.cols; x++) { From 167765f93289d6b957ec5ce358e597f64b3bdd3c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Dec 2022 10:53:21 -0800 Subject: [PATCH 29/30] Improve IAttributeData jsdoc Fixes #2603 --- src/common/Types.d.ts | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index c4c470ad..73471512 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -9,7 +9,7 @@ import { IDeleteEvent, IInsertEvent } from 'common/CircularList'; import { IParams } from 'common/parser/Types'; import { ICoreMouseService, ICoreService, IOptionsService, IUnicodeService } from 'common/services/Services'; import { IBufferSet } from 'common/buffer/Types'; -import { UnderlineStyle } from 'common/buffer/Constants'; +import { Attributes, UnderlineStyle } from 'common/buffer/Constants'; export interface ICoreTerminal { coreMouseService: ICoreMouseService; @@ -133,10 +133,24 @@ export interface IOscLinkData { uri: string; } -/** Attribute data */ +/** + * An object that represents all attributes of a cell. + */ export interface IAttributeData { + /** + * "fg" is a 32-bit unsigned integer that stores the foreground color of the cell in the 24 least + * significant bits and additional flags in the remaining 8 bits. + */ fg: number; + /** + * "bg" is a 32-bit unsigned integer that stores the background color of the cell in the 24 least + * significant bits and additional flags in the remaining 8 bits. + */ bg: number; + /** + * "extended", aka "ext", stores extended attributes beyond those available in fg and bg. This + * data is optional on a cell and encodes less common data. + */ extended: IExtendedAttrs; clone(): IAttributeData; @@ -152,8 +166,17 @@ export interface IAttributeData { isStrikethrough(): number; isProtected(): number; - // color modes + /** + * The color mode of the foreground color which determines how to decode {@link getFgColor}, + * possible values include {@link Attributes.CM_DEFAULT}, {@link Attributes.CM_P16}, + * {@link Attributes.CM_P256} and {@link Attributes.CM_RGB}. + */ getFgColorMode(): number; + /** + * The color mode of the background color which determines how to decode {@link getBgColor}, + * possible values include {@link Attributes.CM_DEFAULT}, {@link Attributes.CM_P16}, + * {@link Attributes.CM_P256} and {@link Attributes.CM_RGB}. + */ getBgColorMode(): number; isFgRGB(): boolean; isBgRGB(): boolean; @@ -163,8 +186,15 @@ export interface IAttributeData { isBgDefault(): boolean; isAttributeDefault(): boolean; - // colors + /** + * Gets an integer representation of the foreground color, how to decode the color depends on the + * color mode {@link getFgColorMode}. + */ getFgColor(): number; + /** + * Gets an integer representation of the background color, how to decode the color depends on the + * color mode {@link getBgColorMode}. + */ getBgColor(): number; // extended attrs From ffeaa2b976f8b0459f55838715868805c392beb9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Dec 2022 11:05:03 -0800 Subject: [PATCH 30/30] Remove ! to improve safety See microsoft/vscode#166909 This doesn't necessarily fix that, but it does remove the hacky ! which could potentially let an error slip past TS. --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index db379214..7f8c6afc 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -40,8 +40,8 @@ export class WebglRenderer extends Disposable implements IRenderer { private _canvas: HTMLCanvasElement; private _gl: IWebGL2RenderingContext; - private _rectangleRenderer!: RectangleRenderer; - private _glyphRenderer!: GlyphRenderer; + private _rectangleRenderer: RectangleRenderer; + private _glyphRenderer: GlyphRenderer; public readonly dimensions: IRenderDimensions; @@ -127,7 +127,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._core.screenElement!.appendChild(this._canvas); - this._initializeWebGLState(); + [this._rectangleRenderer, this._glyphRenderer] = this._initializeWebGLState(); this._isAttached = this._coreBrowserService.window.document.body.contains(this._core.screenElement!); @@ -235,7 +235,7 @@ export class WebglRenderer extends Disposable implements IRenderer { /** * Initializes members dependent on WebGL context state. */ - private _initializeWebGLState(): void { + private _initializeWebGLState(): [RectangleRenderer, GlyphRenderer] { // Dispose any previous rectangle and glyph renderers before creating new ones. this._rectangleRenderer?.dispose(); this._glyphRenderer?.dispose(); @@ -245,6 +245,8 @@ export class WebglRenderer extends Disposable implements IRenderer { // Update dimensions and acquire char atlas this.handleCharSizeChanged(); + + return [this._rectangleRenderer, this._glyphRenderer]; } /** @@ -268,7 +270,6 @@ export class WebglRenderer extends Disposable implements IRenderer { this._coreBrowserService.dpr ); if (this._charAtlas !== atlas) { - this._charAtlasDisposable?.dispose(); this._onChangeTextureAtlas.fire(atlas.pages[0].canvas); this._charAtlasDisposable = getDisposeArrayDisposable([