Skip to content

Commit

Permalink
Add duration-based smooth scroll
Browse files Browse the repository at this point in the history
Fixes #1140
  • Loading branch information
Tyriar committed Jul 27, 2022
1 parent b11217a commit a55728d
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 2 deletions.
50 changes: 49 additions & 1 deletion src/browser/Viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions src/common/services/OptionsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const DEFAULT_OPTIONS: Readonly<ITerminalOptions> = {
scrollback: 1000,
scrollSensitivity: 1,
screenReaderMode: false,
smoothScrollingDuration: 125,
macOptionIsMeta: false,
macOptionClickForcesSelection: false,
minimumContrastRatio: 1,
Expand Down
1 change: 1 addition & 0 deletions src/common/services/Services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ export interface ITerminalOptions {
screenReaderMode: boolean;
scrollback: number;
scrollSensitivity: number;
smoothScrollingDuration: number;
tabStopWidth: number;
theme: ITheme;
windowsMode: boolean;
Expand Down
9 changes: 8 additions & 1 deletion typings/xterm-headless.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
6 changes: 6 additions & 0 deletions typings/xterm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down

0 comments on commit a55728d

Please sign in to comment.