From 21bcef5008de7ee49b2899f1549356d84c2c897c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 09:54:44 -0700 Subject: [PATCH] Move a bunch of scroll logic into CoreTerminal This change will now reset userScrolling on RIS --- src/Terminal.ts | 78 ++-------------------------- src/common/CoreTerminal.ts | 72 ++++++++++++++++++++++++- src/common/TestUtils.test.ts | 1 + src/common/services/BufferService.ts | 3 ++ src/common/services/Services.ts | 1 + 5 files changed, 80 insertions(+), 75 deletions(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 2385ad19..9f55e2bd 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -85,9 +85,6 @@ export class Terminal extends CoreTerminal implements ITerminal { private _selectionService: ISelectionService; private _soundService: ISoundService; - // Store if user went browsing history in scrollback - private _userScrolling: boolean; - /** * Records whether the keydown event has already been handled and triggered a data event, if so * the keypress event should not trigger a data event but should still print to the textarea so @@ -113,8 +110,6 @@ export class Terminal extends CoreTerminal implements ITerminal { public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> { return this._onKey.event; } private _onRender = new EventEmitter<{ start: number, end: number }>(); public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; } - private _onScroll = new EventEmitter(); - public get onScroll(): IEvent { return this._onScroll.event; } private _onSelectionChange = new EventEmitter(); public get onSelectionChange(): IEvent { return this._onSelectionChange.event; } private _onTitleChange = new EventEmitter(); @@ -178,7 +173,6 @@ export class Terminal extends CoreTerminal implements ITerminal { this._customKeyEventHandler = null; - this._userScrolling = false; if (!this.linkifier) { this.linkifier = this._instantiationService.createInstance(Linkifier); } @@ -862,13 +856,13 @@ export class Terminal extends CoreTerminal implements ITerminal { if (!willBufferBeTrimmed) { this.buffer.ybase++; // Only scroll the ydisp with ybase if the user has not scrolled up - if (!this._userScrolling) { + if (!this._bufferService.isUserScrolling) { this.buffer.ydisp++; } } else { // When the buffer is full and the user has scrolled up, keep the text // stable unless ydisp is right at the top - if (this._userScrolling) { + if (this._bufferService.isUserScrolling) { this.buffer.ydisp = Math.max(this.buffer.ydisp - 1, 0); } } @@ -882,7 +876,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // Move the viewport to the bottom of the buffer unless the user is // scrolling. - if (!this._userScrolling) { + if (!this._bufferService.isUserScrolling) { this.buffer.ydisp = this.buffer.ybase; } @@ -892,67 +886,11 @@ export class Terminal extends CoreTerminal implements ITerminal { this._onScroll.fire(this.buffer.ydisp); } - /** - * 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. - */ public scrollLines(disp: number, suppressScrollEvent?: boolean): void { - if (disp < 0) { - if (this.buffer.ydisp === 0) { - return; - } - this._userScrolling = true; - } else if (disp + this.buffer.ydisp >= this.buffer.ybase) { - this._userScrolling = false; - } - - const oldYdisp = this.buffer.ydisp; - this.buffer.ydisp = Math.max(Math.min(this.buffer.ydisp + disp, this.buffer.ybase), 0); - - // No change occurred, don't trigger scroll/refresh - if (oldYdisp === this.buffer.ydisp) { - return; - } - - if (!suppressScrollEvent) { - this._onScroll.fire(this.buffer.ydisp); - } - + super.scrollLines(disp, suppressScrollEvent); this.refresh(0, this.rows - 1); } - /** - * 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); - } - } - public paste(data: string): void { paste(data, this.textarea, this._coreService); } @@ -1299,19 +1237,13 @@ export class Terminal extends CoreTerminal implements ITerminal { this.options.rows = this.rows; this.options.cols = this.cols; const customKeyEventHandler = this._customKeyEventHandler; - const userScrolling = this._userScrolling; this._setup(); - this._inputHandler.reset(); - this._bufferService.reset(); - this._charsetService.reset(); - this._coreService.reset(); - this._coreMouseService.reset(); + super.reset(); this._selectionService?.reset(); // reattach this._customKeyEventHandler = customKeyEventHandler; - this._userScrolling = userScrolling; // do a full screen refresh this.refresh(0, this.rows - 1); diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index f98ef0dc..a870a765 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -64,6 +64,8 @@ export abstract class CoreTerminal extends Disposable { public get onLineFeed(): IEvent { return this._onLineFeed.event; } private _onResize = new EventEmitter<{ cols: number, rows: number }>(); public get onResize(): IEvent<{ cols: number, rows: number }> { return this._onResize.event; } + protected _onScroll = new EventEmitter(); + public get onScroll(): IEvent { return this._onScroll.event; } public get cols(): number { return this._bufferService.cols; } public get rows(): number { return this._bufferService.rows; } @@ -136,6 +138,66 @@ export abstract class CoreTerminal extends Disposable { this._bufferService.resize(x, y); } + /** + * 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. + */ + public scrollLines(disp: number, suppressScrollEvent?: boolean): void { + const buffer = this._bufferService.buffer; + if (disp < 0) { + if (buffer.ydisp === 0) { + return; + } + this._bufferService.isUserScrolling = true; + } else if (disp + buffer.ydisp >= buffer.ybase) { + this._bufferService.isUserScrolling = false; + } + + const oldYdisp = buffer.ydisp; + buffer.ydisp = Math.max(Math.min(buffer.ydisp + disp, buffer.ybase), 0); + + // No change occurred, don't trigger scroll/refresh + if (oldYdisp === buffer.ydisp) { + return; + } + + if (!suppressScrollEvent) { + 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._bufferService.buffer.ydisp); + } + + /** + * Scrolls the display of the terminal to the bottom. + */ + public scrollToBottom(): void { + this.scrollLines(this._bufferService.buffer.ybase - this._bufferService.buffer.ydisp); + } + + public scrollToLine(line: number): void { + 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. */ public addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable { return this._inputHandler.addEscHandler(id, callback); @@ -162,6 +224,14 @@ export abstract class CoreTerminal extends Disposable { } } + public reset(): void { + this._inputHandler.reset(); + this._bufferService.reset(); + this._charsetService.reset(); + this._coreService.reset(); + this._coreMouseService.reset(); + } + protected _updateOptions(key: string): void { // TODO: These listeners should be owned by individual components switch (key) { @@ -194,6 +264,4 @@ export abstract class CoreTerminal extends Disposable { }; } } - - public abstract scrollToBottom(): void; } diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 55e34084..71faed99 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -17,6 +17,7 @@ export class MockBufferService implements IBufferService { public get buffer(): IBuffer { return this.buffers.active; } public buffers: IBufferSet = {} as any; public onResize: IEvent<{ cols: number, rows: number }> = new EventEmitter<{ cols: number, rows: number }>().event; + public isUserScrolling: boolean = false; constructor( public cols: number, public rows: number, diff --git a/src/common/services/BufferService.ts b/src/common/services/BufferService.ts index d62d2cb0..8de44e43 100644 --- a/src/common/services/BufferService.ts +++ b/src/common/services/BufferService.ts @@ -17,6 +17,8 @@ export class BufferService implements IBufferService { public cols: number; public rows: number; public buffers: IBufferSet; + /** Whether the user is scrolling (locks the scroll position) */ + public isUserScrolling: boolean = false; private _onResize = new EventEmitter<{ cols: number, rows: number }>(); public get onResize(): IEvent<{ cols: number, rows: number }> { return this._onResize.event; } @@ -41,5 +43,6 @@ export class BufferService implements IBufferService { public reset(): void { this.buffers = new BufferSet(this._optionsService, this); + this.isUserScrolling = false; } } diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 6829d7b9..e123bd8b 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -16,6 +16,7 @@ export interface IBufferService { readonly rows: number; readonly buffer: IBuffer; readonly buffers: IBufferSet; + isUserScrolling: boolean; onResize: IEvent<{ cols: number, rows: number }>;