Skip to content

Commit b7d73f6

Browse files
committed
Add smoothScroll to scrollLines
1 parent 2fdb469 commit b7d73f6

File tree

3 files changed

+85
-9
lines changed

3 files changed

+85
-9
lines changed

src/browser/Terminal.ts

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* http://linux.die.net/man/7/urxvt
2222
*/
2323

24-
import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler, IViewport, ILinkifier2, CharacterJoinerHandler, IBufferRange, IBufferElementProvider } from 'browser/Types';
24+
import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler, IViewport, ILinkifier2, CharacterJoinerHandler, IBufferRange, IBufferElementProvider, ISmoothScrollProgressState } from 'browser/Types';
2525
import { IRenderer } from 'browser/renderer/shared/Types';
2626
import { CompositionHelper } from 'browser/input/CompositionHelper';
2727
import { Viewport } from 'browser/Viewport';
@@ -122,6 +122,13 @@ export class Terminal extends CoreTerminal implements ITerminal {
122122
private _compositionHelper: ICompositionHelper | undefined;
123123
private _accessibilityManager: AccessibilityManager | undefined;
124124

125+
private _smoothScrollProgressState: ISmoothScrollProgressState = {
126+
startTime: 0,
127+
origin: 0,
128+
target: 0,
129+
progress: 0
130+
};
131+
125132
private readonly _onCursorMove = this.register(new EventEmitter<void>());
126133
public readonly onCursorMove = this._onCursorMove.event;
127134
private readonly _onKey = this.register(new EventEmitter<{ key: string, domEvent: KeyboardEvent }>());
@@ -869,11 +876,76 @@ export class Terminal extends CoreTerminal implements ITerminal {
869876
}
870877
}
871878

872-
public scrollLines(disp: number, suppressScrollEvent?: boolean, source = ScrollSource.TERMINAL): void {
879+
private _scrollLines(disp: number, suppressScrollEvent?: boolean, source = ScrollSource.TERMINAL): void {
873880
super.scrollLines(disp, suppressScrollEvent, source);
874881
this.refresh(0, this.rows - 1);
875882
}
876883

884+
public scrollLines(disp: number, suppressScrollEvent?: boolean, source = ScrollSource.TERMINAL): void {
885+
if (source === ScrollSource.VIEWPORT) {
886+
this._scrollLines(disp, suppressScrollEvent, source);
887+
} else {
888+
if (!this.optionsService.rawOptions.smoothScrollDuration) {
889+
this._scrollLines(disp, suppressScrollEvent, source);
890+
} else {
891+
this._smoothScrollProgressState.startTime = Date.now();
892+
if (this._smoothScrollPercent() < 1) {
893+
this._smoothScrollProgressState.origin = 0;
894+
this._smoothScrollProgressState.target = disp;
895+
this._smoothScrollProgressState.progress = 0;
896+
this._smoothScroll(suppressScrollEvent, source);
897+
} else {
898+
this._clearSmoothScrollState();
899+
}
900+
}
901+
}
902+
}
903+
904+
private _smoothScrollPercent(): number {
905+
if (!this.optionsService.rawOptions.smoothScrollDuration || !this._smoothScrollProgressState.startTime) {
906+
return 1;
907+
}
908+
return Math.max(Math.min((Date.now() - this._smoothScrollProgressState.startTime) / this.optionsService.rawOptions.smoothScrollDuration, 1), 0);
909+
}
910+
911+
private _isSmoothScrollEnd(): boolean {
912+
if (this._smoothScrollProgressState.target < 0) {
913+
if (this._smoothScrollProgressState.progress > this._smoothScrollProgressState.target) {
914+
return false;
915+
}
916+
} else if (this._smoothScrollProgressState.target > 0) {
917+
if (this._smoothScrollProgressState.progress < this._smoothScrollProgressState.target) {
918+
return false;
919+
}
920+
}
921+
return true;
922+
}
923+
924+
private _smoothScroll(suppressScrollEvent?: boolean, source = ScrollSource.TERMINAL): void {
925+
if (this._smoothScrollProgressState.startTime === 0 || this._isSmoothScrollEnd()) {
926+
return;
927+
}
928+
929+
const percent = this._smoothScrollPercent();
930+
const step = Math.round(percent * (this._smoothScrollProgressState.target - this._smoothScrollProgressState.origin)) - this._smoothScrollProgressState.progress;
931+
this._smoothScrollProgressState.progress += step;
932+
this._scrollLines(step, suppressScrollEvent, source);
933+
934+
if (this._isSmoothScrollEnd()) {
935+
this._clearSmoothScrollState();
936+
return;
937+
}
938+
939+
this._coreBrowserService?.window.requestAnimationFrame(() => this._smoothScroll(suppressScrollEvent, source));
940+
}
941+
942+
private _clearSmoothScrollState(): void {
943+
this._smoothScrollProgressState.origin = 0;
944+
this._smoothScrollProgressState.target = 0;
945+
this._smoothScrollProgressState.progress = 0;
946+
this._smoothScrollProgressState.startTime = 0;
947+
}
948+
877949
public paste(data: string): void {
878950
paste(data, this.textarea!, this.coreService);
879951
}

src/browser/Types.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ export interface IViewport extends IDisposable {
150150
handleTouchMove(ev: TouchEvent): boolean;
151151
}
152152

153+
export interface ISmoothScrollState {
154+
startTime: number;
155+
origin: number;
156+
target: number;
157+
}
158+
159+
export interface ISmoothScrollProgressState extends ISmoothScrollState {
160+
progress: number;
161+
}
162+
153163
export interface ILinkifierEvent {
154164
x1: number;
155165
y1: number;

src/browser/Viewport.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,14 @@
55

66
import { Disposable } from 'common/Lifecycle';
77
import { addDisposableDomListener } from 'browser/Lifecycle';
8-
import { IColorSet, IViewport, ReadonlyColorSet } from 'browser/Types';
8+
import { IColorSet, ISmoothScrollState, IViewport, ReadonlyColorSet } from 'browser/Types';
99
import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
1010
import { IBufferService, IOptionsService } from 'common/services/Services';
1111
import { IBuffer } from 'common/buffer/Types';
1212
import { IRenderDimensions } from 'browser/renderer/shared/Types';
1313

1414
const FALLBACK_SCROLL_BAR_WIDTH = 15;
1515

16-
interface ISmoothScrollState {
17-
startTime: number;
18-
origin: number;
19-
target: number;
20-
}
21-
2216
/**
2317
* Represents the viewport of a terminal, the visible area within the larger buffer of output.
2418
* Logic for the virtual scroll bar is included in this object.

0 commit comments

Comments
 (0)