mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #4482 from tisilent/#4121
Add smoothScroll to scrollLines
This commit is contained in:
@@ -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;
|
||||
@@ -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: {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Vendored
+20
@@ -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;
|
||||
@@ -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 {
|
||||
|
||||
+23
-3
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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) {
|
||||
|
||||
+11
-17
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user