From a55728dd28f45f3da643aa38196a616e1334fcb1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 27 Jul 2022 05:41:00 -0700 Subject: [PATCH 1/6] Add duration-based smooth scroll Fixes #1140 --- src/browser/Viewport.ts | 50 ++++++++++++++++++++++++++- src/common/services/OptionsService.ts | 1 + src/common/services/Services.ts | 1 + typings/xterm-headless.d.ts | 9 ++++- typings/xterm.d.ts | 6 ++++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 1eb9dc4e..65ccc333 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -36,6 +36,9 @@ export class Viewport extends Disposable implements IViewport { private _refreshAnimationFrame: number | null = null; private _ignoreNextScrollEvent: boolean = false; + private _lastSmoothScrollOrigin?: number = undefined; + private _lastSmoothScrollTarget?: number = undefined; + private _lastSmoothScrollStartTime?: number = undefined; constructor( private readonly _scrollLines: (amount: number) => void, @@ -168,6 +171,33 @@ export class Viewport extends Disposable implements IViewport { this._scrollLines(diff); } + private _smoothScroll(): void { + // Check valid state + if (this._isDisposed || this._lastSmoothScrollOrigin === undefined || this._lastSmoothScrollTarget === undefined) { + return; + } + + // Calculate position complete + const percent = this._smoothScrollPercent(); + this._viewportElement.scrollTop = this._lastSmoothScrollOrigin + Math.round(percent * (this._lastSmoothScrollTarget - this._lastSmoothScrollOrigin)); + + // Continue or finish smooth scroll + if (percent < 1) { + window.requestAnimationFrame(() => this._smoothScroll()); + } else { + this._lastSmoothScrollStartTime = undefined; + this._lastSmoothScrollOrigin = undefined; + this._lastSmoothScrollTarget = undefined; + } + } + + private _smoothScrollPercent(): number { + if (!this._optionsService.rawOptions.smoothScrollingDuration || !this._lastSmoothScrollStartTime) { + return 1; + } + return Math.max(Math.min((Date.now() - this._lastSmoothScrollStartTime) / this._optionsService.rawOptions.smoothScrollingDuration, 1), 0); + } + /** * Handles bubbling of scroll event in case the viewport has reached top or bottom * @param ev The scroll event. @@ -196,7 +226,25 @@ export class Viewport extends Disposable implements IViewport { if (amount === 0) { return false; } - this._viewportElement.scrollTop += amount; + if (!this._optionsService.rawOptions.smoothScrollingDuration) { + this._viewportElement.scrollTop += amount; + } else { + this._lastSmoothScrollStartTime = Date.now(); + if (this._smoothScrollPercent() < 1) { + this._lastSmoothScrollOrigin = this._viewportElement.scrollTop; + if (this._lastSmoothScrollTarget === undefined) { + this._lastSmoothScrollTarget = this._viewportElement.scrollTop + amount; + } else { + this._lastSmoothScrollTarget += amount; + } + this._lastSmoothScrollTarget = Math.max(Math.min(this._lastSmoothScrollTarget, this._viewportElement.scrollHeight), 0); + this._smoothScroll(); + } else { + this._lastSmoothScrollStartTime = undefined; + this._lastSmoothScrollOrigin = undefined; + this._lastSmoothScrollTarget = undefined; + } + } return this._bubbleScroll(ev, amount); } diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 4f9600a4..32358bdd 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -37,6 +37,7 @@ export const DEFAULT_OPTIONS: Readonly = { scrollback: 1000, scrollSensitivity: 1, screenReaderMode: false, + smoothScrollingDuration: 125, macOptionIsMeta: false, macOptionClickForcesSelection: false, minimumContrastRatio: 1, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index fab8435a..72418ee2 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -241,6 +241,7 @@ export interface ITerminalOptions { screenReaderMode: boolean; scrollback: number; scrollSensitivity: number; + smoothScrollingDuration: number; tabStopWidth: number; theme: ITheme; windowsMode: boolean; diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 26a01e4c..cc08039e 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -182,10 +182,17 @@ declare module 'xterm-headless' { scrollback?: number; /** - * The scrolling speed multiplier used for adjusting normal scrolling speed. + * The duration to smoothly scroll between the origin and the target in + * milliseconds. Set to 0 to disable smooth scrolling and scroll instantly. */ scrollSensitivity?: number; + /** + * The duration to smoothly scroll between the origin and the target. Set + * this to 0 to disable smooth scrolling and scroll instantly. + */ + smoothScrollingDuration?: number; + /** * The size of tab stops in the terminal. */ diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index a3f47300..afa138d7 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -233,6 +233,12 @@ declare module 'xterm' { */ scrollSensitivity?: number; + /** + * The duration to smoothly scroll between the origin and the target in + * milliseconds. Set to 0 to disable smooth scrolling and scroll instantly. + */ + smoothScrollingDuration?: number; + /** * The size of tab stops in the terminal. */ From fb4cb0f140a42d61359048eded4b74aa14645c84 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 27 Jul 2022 05:44:34 -0700 Subject: [PATCH 2/6] Reduce smooth scroll GC --- src/browser/Viewport.ts | 48 +++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 65ccc333..c1afabd3 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -13,6 +13,12 @@ import { IRenderDimensions } from 'browser/renderer/Types'; const FALLBACK_SCROLL_BAR_WIDTH = 15; +interface ISmoothScrollState { + startTime: number; + origin: number; + target: number; +} + /** * Represents the viewport of a terminal, the visible area within the larger buffer of output. * Logic for the virtual scroll bar is included in this object. @@ -36,9 +42,11 @@ export class Viewport extends Disposable implements IViewport { private _refreshAnimationFrame: number | null = null; private _ignoreNextScrollEvent: boolean = false; - private _lastSmoothScrollOrigin?: number = undefined; - private _lastSmoothScrollTarget?: number = undefined; - private _lastSmoothScrollStartTime?: number = undefined; + private _smoothScrollState: ISmoothScrollState = { + startTime: 0, + origin: -1, + target: -1 + }; constructor( private readonly _scrollLines: (amount: number) => void, @@ -173,29 +181,33 @@ export class Viewport extends Disposable implements IViewport { private _smoothScroll(): void { // Check valid state - if (this._isDisposed || this._lastSmoothScrollOrigin === undefined || this._lastSmoothScrollTarget === undefined) { + if (this._isDisposed || this._smoothScrollState.origin === -1 || this._smoothScrollState.target === -1) { return; } // Calculate position complete const percent = this._smoothScrollPercent(); - this._viewportElement.scrollTop = this._lastSmoothScrollOrigin + Math.round(percent * (this._lastSmoothScrollTarget - this._lastSmoothScrollOrigin)); + this._viewportElement.scrollTop = this._smoothScrollState.origin + Math.round(percent * (this._smoothScrollState.target - this._smoothScrollState.origin)); // Continue or finish smooth scroll if (percent < 1) { window.requestAnimationFrame(() => this._smoothScroll()); } else { - this._lastSmoothScrollStartTime = undefined; - this._lastSmoothScrollOrigin = undefined; - this._lastSmoothScrollTarget = undefined; + this._clearSmoothScrollState(); } } private _smoothScrollPercent(): number { - if (!this._optionsService.rawOptions.smoothScrollingDuration || !this._lastSmoothScrollStartTime) { + if (!this._optionsService.rawOptions.smoothScrollingDuration || !this._smoothScrollState.startTime) { return 1; } - return Math.max(Math.min((Date.now() - this._lastSmoothScrollStartTime) / this._optionsService.rawOptions.smoothScrollingDuration, 1), 0); + return Math.max(Math.min((Date.now() - this._smoothScrollState.startTime) / this._optionsService.rawOptions.smoothScrollingDuration, 1), 0); + } + + private _clearSmoothScrollState(): void { + this._smoothScrollState.startTime = 0; + this._smoothScrollState.origin = -1; + this._smoothScrollState.target = -1; } /** @@ -229,20 +241,18 @@ export class Viewport extends Disposable implements IViewport { if (!this._optionsService.rawOptions.smoothScrollingDuration) { this._viewportElement.scrollTop += amount; } else { - this._lastSmoothScrollStartTime = Date.now(); + this._smoothScrollState.startTime = Date.now(); if (this._smoothScrollPercent() < 1) { - this._lastSmoothScrollOrigin = this._viewportElement.scrollTop; - if (this._lastSmoothScrollTarget === undefined) { - this._lastSmoothScrollTarget = this._viewportElement.scrollTop + amount; + this._smoothScrollState.origin = this._viewportElement.scrollTop; + if (this._smoothScrollState.target === -1) { + this._smoothScrollState.target = this._viewportElement.scrollTop + amount; } else { - this._lastSmoothScrollTarget += amount; + this._smoothScrollState.target += amount; } - this._lastSmoothScrollTarget = Math.max(Math.min(this._lastSmoothScrollTarget, this._viewportElement.scrollHeight), 0); + this._smoothScrollState.target = Math.max(Math.min(this._smoothScrollState.target, this._viewportElement.scrollHeight), 0); this._smoothScroll(); } else { - this._lastSmoothScrollStartTime = undefined; - this._lastSmoothScrollOrigin = undefined; - this._lastSmoothScrollTarget = undefined; + this._clearSmoothScrollState(); } } return this._bubbleScroll(ev, amount); From 4b8e7a57683a2c39e1b838ed59697850593185c0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 27 Jul 2022 05:45:56 -0700 Subject: [PATCH 3/6] Change default to 0 --- src/browser/Viewport.ts | 6 +++--- src/common/services/OptionsService.ts | 2 +- src/common/services/Services.ts | 2 +- typings/xterm-headless.d.ts | 2 +- typings/xterm.d.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index c1afabd3..6cff1f98 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -198,10 +198,10 @@ export class Viewport extends Disposable implements IViewport { } private _smoothScrollPercent(): number { - if (!this._optionsService.rawOptions.smoothScrollingDuration || !this._smoothScrollState.startTime) { + if (!this._optionsService.rawOptions.smoothScrollDuration || !this._smoothScrollState.startTime) { return 1; } - return Math.max(Math.min((Date.now() - this._smoothScrollState.startTime) / this._optionsService.rawOptions.smoothScrollingDuration, 1), 0); + return Math.max(Math.min((Date.now() - this._smoothScrollState.startTime) / this._optionsService.rawOptions.smoothScrollDuration, 1), 0); } private _clearSmoothScrollState(): void { @@ -238,7 +238,7 @@ export class Viewport extends Disposable implements IViewport { if (amount === 0) { return false; } - if (!this._optionsService.rawOptions.smoothScrollingDuration) { + if (!this._optionsService.rawOptions.smoothScrollDuration) { this._viewportElement.scrollTop += amount; } else { this._smoothScrollState.startTime = Date.now(); diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 32358bdd..87d04ff9 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -37,7 +37,7 @@ export const DEFAULT_OPTIONS: Readonly = { scrollback: 1000, scrollSensitivity: 1, screenReaderMode: false, - smoothScrollingDuration: 125, + smoothScrollDuration: 0, macOptionIsMeta: false, macOptionClickForcesSelection: false, minimumContrastRatio: 1, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 72418ee2..15cfd8ea 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -241,7 +241,7 @@ export interface ITerminalOptions { screenReaderMode: boolean; scrollback: number; scrollSensitivity: number; - smoothScrollingDuration: number; + smoothScrollDuration: number; tabStopWidth: number; theme: ITheme; windowsMode: boolean; diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index cc08039e..85433829 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -191,7 +191,7 @@ declare module 'xterm-headless' { * The duration to smoothly scroll between the origin and the target. Set * this to 0 to disable smooth scrolling and scroll instantly. */ - smoothScrollingDuration?: number; + smoothScrollDuration?: number; /** * The size of tab stops in the terminal. diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index afa138d7..1413f66b 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -237,7 +237,7 @@ declare module 'xterm' { * The duration to smoothly scroll between the origin and the target in * milliseconds. Set to 0 to disable smooth scrolling and scroll instantly. */ - smoothScrollingDuration?: number; + smoothScrollDuration?: number; /** * The size of tab stops in the terminal. From 78bfe0b89d5a1556f693b42257536c9d9dac6da6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 27 Jul 2022 05:47:39 -0700 Subject: [PATCH 4/6] Revert accidental setting change --- typings/xterm-headless.d.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 85433829..07c1749d 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -182,16 +182,15 @@ declare module 'xterm-headless' { scrollback?: number; /** - * The duration to smoothly scroll between the origin and the target in - * milliseconds. Set to 0 to disable smooth scrolling and scroll instantly. + * The scrolling speed multiplier used for adjusting normal scrolling speed. */ scrollSensitivity?: number; /** - * The duration to smoothly scroll between the origin and the target. Set - * this to 0 to disable smooth scrolling and scroll instantly. + * The duration to smoothly scroll between the origin and the target in + * milliseconds. Set to 0 to disable smooth scrolling and scroll instantly. */ - smoothScrollDuration?: number; + smoothScrollDuration?: number; /** * The size of tab stops in the terminal. From 0b0662c4d9d5bb0cd60f84dfab0c3e697003e8e6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 28 Jul 2022 07:27:27 -0700 Subject: [PATCH 5/6] xterm-addon-canvas@0.1.0 --- addons/xterm-addon-canvas/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-canvas/package.json b/addons/xterm-addon-canvas/package.json index 3d08e9db..ba19e674 100644 --- a/addons/xterm-addon-canvas/package.json +++ b/addons/xterm-addon-canvas/package.json @@ -1,6 +1,6 @@ { "name": "xterm-addon-canvas", - "version": "0.12.0", + "version": "0.1.0", "author": { "name": "The xterm.js authors", "url": "https://xtermjs.org/" From 1be14e4338cf174740414752ad1d7e9770f143c9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 28 Jul 2022 09:09:44 -0700 Subject: [PATCH 6/6] Fix version of published addons --- bin/publish.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/publish.js b/bin/publish.js index cb6c836a..78ebde13 100644 --- a/bin/publish.js +++ b/bin/publish.js @@ -98,9 +98,13 @@ function getNextBetaVersion(packageJson) { process.exit(1); } const tag = 'beta'; - // const stableVersion = packageJson.version.split('.'); - // const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`; - const nextStableVersion = `5.0.0`; + let nextStableVersion; + if (packageJson.name = 'xterm') { + nextStableVersion = `5.0.0`; + } else { + const stableVersion = packageJson.version.split('.'); + nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`; + } const publishedVersions = getPublishedVersions(packageJson, nextStableVersion, tag); if (publishedVersions.length === 0) { return `${nextStableVersion}-${tag}.1`;