Skip to content

Commit

Permalink
Merge pull request #4482 from tisilent/#4121
Browse files Browse the repository at this point in the history
Add smoothScroll to scrollLines
  • Loading branch information
Tyriar committed Aug 1, 2023
2 parents f6738ec + 1067ec1 commit db6e0cd
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 62 deletions.
3 changes: 2 additions & 1 deletion src/browser/Terminal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { MockViewport, MockCompositionHelper, MockRenderer, TestTerminal } from
import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
import { CellData } from 'common/buffer/CellData';
import { MockUnicodeService } from 'common/TestUtils.test';
import { IMarker } from 'common/Types';
import { IMarker, ScrollSource } from 'common/Types';
import { ICoreService } from 'common/services/Services';

const INIT_COLS = 80;
Expand All @@ -29,6 +29,7 @@ describe('Terminal', () => {
term.refresh = () => { };
(term as any).renderer = new MockRenderer();
term.viewport = new MockViewport();
term.viewport.onRequestScrollLines(e => term.scrollLines(e.amount, e.suppressScrollEvent, ScrollSource.VIEWPORT));
(term as any)._compositionHelper = new MockCompositionHelper();
(term as any).element = {
classList: {
Expand Down
17 changes: 9 additions & 8 deletions src/browser/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -497,11 +497,8 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._mouseService = this._instantiationService.createInstance(MouseService);
this._instantiationService.setService(IMouseService, this._mouseService);

this.viewport = this._instantiationService.createInstance(Viewport,
(amount: number) => this.scrollLines(amount, true, ScrollSource.VIEWPORT),
this._viewportElement,
this._viewportScrollArea
);
this.viewport = this._instantiationService.createInstance(Viewport, this._viewportElement, this._viewportScrollArea);
this.viewport.onRequestScrollLines(e => this.scrollLines(e.amount, e.suppressScrollEvent, ScrollSource.VIEWPORT)),
this.register(this._inputHandler.onRequestSyncScrollBar(() => this.viewport!.syncScrollArea()));
this.register(this.viewport);

Expand Down Expand Up @@ -870,8 +867,12 @@ export class Terminal extends CoreTerminal implements ITerminal {
}

public scrollLines(disp: number, suppressScrollEvent?: boolean, source = ScrollSource.TERMINAL): void {
super.scrollLines(disp, suppressScrollEvent, source);
this.refresh(0, this.rows - 1);
if (source === ScrollSource.VIEWPORT) {
super.scrollLines(disp, suppressScrollEvent, source);
this.refresh(0, this.rows - 1);
} else {
this.viewport?.scrollLines(disp);
}
}

public paste(data: string): void {
Expand Down Expand Up @@ -1003,7 +1004,7 @@ export class Terminal extends CoreTerminal implements ITerminal {

if (!shouldIgnoreComposition && !this._compositionHelper!.keydown(event)) {
if (this.options.scrollOnUserInput && this.buffer.ybase !== this.buffer.ydisp) {
this._bufferService.scrollToBottom();
this.scrollToBottom();
}
return false;
}
Expand Down
5 changes: 5 additions & 0 deletions src/browser/TestUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ export class MockRenderer implements IRenderer {
}

export class MockViewport implements IViewport {
private readonly _onRequestScrollLines = new EventEmitter<{ amount: number, suppressScrollEvent: boolean }>();
public readonly onRequestScrollLines = this._onRequestScrollLines.event;
public dispose(): void {
throw new Error('Method not implemented.');
}
Expand All @@ -319,6 +321,9 @@ export class MockViewport implements IViewport {
public getBufferElements(startLine: number, endLine?: number | undefined): { bufferElements: HTMLElement[], cursorElement?: HTMLElement | undefined } {
throw new Error('Method not implemented.');
}
public scrollLines(disp: number): void {
this._onRequestScrollLines.fire({ amount: disp, suppressScrollEvent: false });
}
}

export class MockCompositionHelper implements ICompositionHelper {
Expand Down
20 changes: 20 additions & 0 deletions src/browser/Types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,28 @@ export interface IPublicTerminal extends IDisposable {
selectAll(): void;
selectLines(start: number, end: number): void;
dispose(): void;
/**
* Scroll the display of the terminal
* @param amount The number of lines to scroll down (negative scroll up).
*/
scrollLines(amount: number): void;
/**
* Scroll the display of the terminal by a number of pages.
* @param pageCount The number of pages to scroll (negative scrolls up).
*/
scrollPages(pageCount: number): void;
/**
* Scrolls the display of the terminal to the top.
*/
scrollToTop(): void;
/**
* Scrolls the display of the terminal to the bottom.
*/
scrollToBottom(): void;
/**
* Scrolls to a line within the buffer.
* @param line The 0-based line index to scroll to.
*/
scrollToLine(line: number): void;
clear(): void;
write(data: string | Uint8Array, callback?: () => void): void;
Expand Down Expand Up @@ -142,12 +160,14 @@ export interface IPartialColorSet {

export interface IViewport extends IDisposable {
scrollBarWidth: number;
readonly onRequestScrollLines: IEvent<{ amount: number, suppressScrollEvent: boolean }>;
syncScrollArea(immediate?: boolean): void;
getLinesScrolled(ev: WheelEvent): number;
getBufferElements(startLine: number, endLine?: number): { bufferElements: HTMLElement[], cursorElement?: HTMLElement };
handleWheel(ev: WheelEvent): boolean;
handleTouchStart(ev: TouchEvent): void;
handleTouchMove(ev: TouchEvent): boolean;
scrollLines(disp: number): void; // todo api name?
}

export interface ILinkifierEvent {
Expand Down
26 changes: 23 additions & 3 deletions src/browser/Viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService }
import { IBufferService, IOptionsService } from 'common/services/Services';
import { IBuffer } from 'common/buffer/Types';
import { IRenderDimensions } from 'browser/renderer/shared/Types';
import { EventEmitter } from 'common/EventEmitter';

const FALLBACK_SCROLL_BAR_WIDTH = 15;

Expand Down Expand Up @@ -48,8 +49,10 @@ export class Viewport extends Disposable implements IViewport {
target: -1
};

private readonly _onRequestScrollLines = this.register(new EventEmitter<{ amount: number, suppressScrollEvent: boolean }>());
public readonly onRequestScrollLines = this._onRequestScrollLines.event;

constructor(
private readonly _scrollLines: (amount: number) => void,
private readonly _viewportElement: HTMLElement,
private readonly _scrollArea: HTMLElement,
@IBufferService private readonly _bufferService: IBufferService,
Expand Down Expand Up @@ -175,13 +178,13 @@ export class Viewport extends Disposable implements IViewport {
if (this._ignoreNextScrollEvent) {
this._ignoreNextScrollEvent = false;
// Still trigger the scroll so lines get refreshed
this._scrollLines(0);
this._onRequestScrollLines.fire({ amount: 0, suppressScrollEvent: true });
return;
}

const newRow = Math.round(this._lastScrollTop / this._currentRowHeight);
const diff = newRow - this._bufferService.buffer.ydisp;
this._scrollLines(diff);
this._onRequestScrollLines.fire({ amount: diff, suppressScrollEvent: true });
}

private _smoothScroll(): void {
Expand Down Expand Up @@ -263,6 +266,23 @@ export class Viewport extends Disposable implements IViewport {
return this._bubbleScroll(ev, amount);
}

public scrollLines(disp: number): void {
if (!this._optionsService.rawOptions.smoothScrollDuration) {
this._onRequestScrollLines.fire({ amount: disp, suppressScrollEvent: false });
} else {
const amount = disp * this._currentRowHeight;
this._smoothScrollState.startTime = Date.now();
if (this._smoothScrollPercent() < 1) {
this._smoothScrollState.origin = this._viewportElement.scrollTop;
this._smoothScrollState.target = this._smoothScrollState.origin + amount;
this._smoothScrollState.target = Math.max(Math.min(this._smoothScrollState.target, this._viewportElement.scrollHeight), 0);
this._smoothScroll();
} else {
this._clearSmoothScrollState();
}
}
}

private _getPixelsScrolled(ev: WheelEvent): number {
// Do nothing if it's not a vertical scroll event
if (ev.deltaY === 0 || ev.shiftKey) {
Expand Down
28 changes: 11 additions & 17 deletions src/common/CoreTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,38 +195,32 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
/**
* Scroll the display of the terminal
* @param disp The number of lines to scroll down (negative scroll up).
* @param suppressScrollEvent Don't emit the scroll event as scrollLines. This is used
* to avoid unwanted events being handled by the viewport when the event was triggered from the
* viewport originally.
* @param suppressScrollEvent Don't emit the scroll event as scrollLines. This is used to avoid
* unwanted events being handled by the viewport when the event was triggered from the viewport
* originally.
* @param source Which component the event came from.
*/
public scrollLines(disp: number, suppressScrollEvent?: boolean, source?: ScrollSource): void {
this._bufferService.scrollLines(disp, suppressScrollEvent, source);
}

/**
* Scroll the display of the terminal by a number of pages.
* @param pageCount The number of pages to scroll (negative scrolls up).
*/
public scrollPages(pageCount: number): void {
this._bufferService.scrollPages(pageCount);
this.scrollLines(pageCount * (this.rows - 1));
}

/**
* Scrolls the display of the terminal to the top.
*/
public scrollToTop(): void {
this._bufferService.scrollToTop();
this.scrollLines(-this._bufferService.buffer.ydisp);
}

/**
* Scrolls the display of the terminal to the bottom.
*/
public scrollToBottom(): void {
this._bufferService.scrollToBottom();
this.scrollLines(this._bufferService.buffer.ybase - this._bufferService.buffer.ydisp);
}

public scrollToLine(line: number): void {
this._bufferService.scrollToLine(line);
const scrollAmount = line - this._bufferService.buffer.ydisp;
if (scrollAmount !== 0) {
this.scrollLines(scrollAmount);
}
}

/** Add handler for ESC escape sequence. See xterm.d.ts for details. */
Expand Down
29 changes: 0 additions & 29 deletions src/common/services/BufferService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,33 +147,4 @@ export class BufferService extends Disposable implements IBufferService {
this._onScroll.fire(buffer.ydisp);
}
}

/**
* Scroll the display of the terminal by a number of pages.
* @param pageCount The number of pages to scroll (negative scrolls up).
*/
public scrollPages(pageCount: number): void {
this.scrollLines(pageCount * (this.rows - 1));
}

/**
* Scrolls the display of the terminal to the top.
*/
public scrollToTop(): void {
this.scrollLines(-this.buffer.ydisp);
}

/**
* Scrolls the display of the terminal to the bottom.
*/
public scrollToBottom(): void {
this.scrollLines(this.buffer.ybase - this.buffer.ydisp);
}

public scrollToLine(line: number): void {
const scrollAmount = line - this.buffer.ydisp;
if (scrollAmount !== 0) {
this.scrollLines(scrollAmount);
}
}
}
4 changes: 0 additions & 4 deletions src/common/services/Services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ export interface IBufferService {
onResize: IEvent<{ cols: number, rows: number }>;
onScroll: IEvent<number>;
scroll(eraseAttr: IAttributeData, isWrapped?: boolean): void;
scrollToBottom(): void;
scrollToTop(): void;
scrollToLine(line: number): void;
scrollLines(disp: number, suppressScrollEvent?: boolean, source?: ScrollSource): void;
scrollPages(pageCount: number): void;
resize(cols: number, rows: number): void;
reset(): void;
}
Expand Down

0 comments on commit db6e0cd

Please sign in to comment.