From b9dee59900d98fdbae18c619474186bfe6a0ddad Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 09:36:56 -0700 Subject: [PATCH 01/10] Move InputHandler init into CoreTerminal --- src/Terminal.ts | 52 +++++++++----------------------------- src/common/CoreTerminal.ts | 30 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 61c997bd0..54863ce01 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -27,7 +27,7 @@ import { CompositionHelper } from 'browser/input/CompositionHelper'; import { Viewport } from 'browser/Viewport'; import { rightClickHandler, moveTextAreaUnderMouseCursor, handlePasteEvent, copyHandler, paste } from 'browser/Clipboard'; import { C0 } from 'common/data/EscapeSequences'; -import { InputHandler, WindowsOptionsReportType } from './common/InputHandler'; +import { WindowsOptionsReportType } from './common/InputHandler'; import { Renderer } from 'browser/renderer/Renderer'; import { Linkifier } from 'browser/Linkifier'; import { SelectionService } from 'browser/services/SelectionService'; @@ -49,7 +49,6 @@ import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISo import { CharSizeService } from 'browser/services/CharSizeService'; import { IBuffer } from 'common/buffer/Types'; import { MouseService } from 'browser/services/MouseService'; -import { IParams, IFunctionIdentifier } from 'common/parser/Types'; import { ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport, ILinkifier2 } from 'browser/Types'; import { WriteBuffer } from 'common/input/WriteBuffer'; import { Linkifier2 } from 'browser/Linkifier2'; @@ -100,7 +99,6 @@ export class Terminal extends CoreTerminal implements ITerminal { */ private _keyDownHandled: boolean = false; - private _inputHandler: InputHandler; public linkifier: ILinkifier; public linkifier2: ILinkifier2; public viewport: IViewport; @@ -154,6 +152,16 @@ export class Terminal extends CoreTerminal implements ITerminal { this._setup(); + this.register(this._inputHandler.onRequestBell(() => this.bell())); + this.register(this._inputHandler.onRequestRefreshRows((start, end) => this.refresh(start, end))); + this.register(this._inputHandler.onRequestReset(() => this.reset())); + this.register(this._inputHandler.onRequestScroll((eraseAttr, isWrapped) => this.scroll(eraseAttr, isWrapped || undefined))); + this.register(this._inputHandler.onRequestWindowsOptionsReport(type => this._reportWindowsOptions(type))); + this.register(forwardEvent(this._inputHandler.onCursorMove, this._onCursorMove)); + this.register(forwardEvent(this._inputHandler.onTitleChange, this._onTitleChange)); + this.register(forwardEvent(this._inputHandler.onA11yChar, this._onA11yCharEmitter)); + this.register(forwardEvent(this._inputHandler.onA11yTab, this._onA11yTabEmitter)); + // Setup listeners this._bufferService.onResize(e => this._afterResize(e.cols, e.rows)); @@ -172,24 +180,6 @@ export class Terminal extends CoreTerminal implements ITerminal { } protected _setup(): void { - if (this._inputHandler) { - this._inputHandler.reset(); - } else { - // Register input handler and refire/handle events - this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService, this.unicodeService); - this.register(this._inputHandler.onRequestBell(() => this.bell())); - this.register(this._inputHandler.onRequestRefreshRows((start, end) => this.refresh(start, end))); - this.register(this._inputHandler.onRequestReset(() => this.reset())); - this.register(this._inputHandler.onRequestScroll((eraseAttr, isWrapped) => this.scroll(eraseAttr, isWrapped || undefined))); - this.register(this._inputHandler.onRequestWindowsOptionsReport(type => this._reportWindowsOptions(type))); - this.register(forwardEvent(this._inputHandler.onCursorMove, this._onCursorMove)); - this.register(forwardEvent(this._inputHandler.onLineFeed, this._onLineFeed)); - this.register(forwardEvent(this._inputHandler.onTitleChange, this._onTitleChange)); - this.register(forwardEvent(this._inputHandler.onA11yChar, this._onA11yCharEmitter)); - this.register(forwardEvent(this._inputHandler.onA11yTab, this._onA11yTabEmitter)); - this.register(this._inputHandler); - } - super._setup(); this._customKeyEventHandler = null; @@ -986,25 +976,6 @@ export class Terminal extends CoreTerminal implements ITerminal { this._customKeyEventHandler = customKeyEventHandler; } - /** 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); - } - - /** Add handler for DCS escape sequence. See xterm.d.ts for details. */ - public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable { - return this._inputHandler.addDcsHandler(id, callback); - } - - /** Add handler for CSI escape sequence. See xterm.d.ts for details. */ - public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable { - return this._inputHandler.addCsiHandler(id, callback); - } - /** Add handler for OSC escape sequence. See xterm.d.ts for details. */ - public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable { - return this._inputHandler.addOscHandler(ident, callback); - } - /** * Registers a link matcher, allowing custom link patterns to be matched and * handled. @@ -1337,6 +1308,7 @@ export class Terminal extends CoreTerminal implements ITerminal { const userScrolling = this._userScrolling; this._setup(); + this._inputHandler.reset(); this._bufferService.reset(); this._charsetService.reset(); this._coreService.reset(); diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 49f3509db..8df2bd6ba 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -27,7 +27,7 @@ import { InstantiationService } from 'common/services/InstantiationService'; import { LogService } from 'common/services/LogService'; import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; import { OptionsService } from 'common/services/OptionsService'; -import { ITerminalOptions, IDisposable } from './Types'; +import { ITerminalOptions, IDisposable } from 'common/Types'; import { CoreService } from 'common/services/CoreService'; import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; import { CoreMouseService } from 'common/services/CoreMouseService'; @@ -37,6 +37,7 @@ import { CharsetService } from 'common/services/CharsetService'; import { updateWindowsModeWrappedState } from 'common/WindowsMode'; import { IFunctionIdentifier, IParams } from 'common/parser/Types'; import { IBufferSet } from 'common/buffer/Types'; +import { InputHandler } from 'common/InputHandler'; export abstract class CoreTerminal extends Disposable { protected readonly _instantiationService: IInstantiationService; @@ -50,6 +51,7 @@ export abstract class CoreTerminal extends Disposable { public readonly unicodeService: IUnicodeService; public readonly optionsService: IOptionsService; + protected _inputHandler: InputHandler; private _windowsMode: IDisposable | undefined; private _onBinary = new EventEmitter(); @@ -94,6 +96,11 @@ export abstract class CoreTerminal extends Disposable { this.register(forwardEvent(this._coreService.onData, this._onData)); this.register(forwardEvent(this._coreService.onBinary, this._onBinary)); this.register(this.optionsService.onOptionChange(key => this._updateOptions(key))); + + // Register input handler and handle/forward events + this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService, this.unicodeService); + this.register(forwardEvent(this._inputHandler.onLineFeed, this._onLineFeed)); + this.register(this._inputHandler); } public dispose(): void { @@ -116,6 +123,26 @@ export abstract class CoreTerminal extends Disposable { this._bufferService.resize(x, y); } + /** 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); + } + + /** Add handler for DCS escape sequence. See xterm.d.ts for details. */ + public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable { + return this._inputHandler.addDcsHandler(id, callback); + } + + /** Add handler for CSI escape sequence. See xterm.d.ts for details. */ + public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable { + return this._inputHandler.addCsiHandler(id, callback); + } + + /** Add handler for OSC escape sequence. See xterm.d.ts for details. */ + public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable { + return this._inputHandler.addOscHandler(ident, callback); + } + protected _setup(): void { if (this.optionsService.options.windowsMode) { this._enableWindowsMode(); @@ -156,5 +183,4 @@ export abstract class CoreTerminal extends Disposable { } public abstract scrollToBottom(): void; - public abstract addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; } From 46e7fc61cc78fdb692c454e4b54ac794a8218f83 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 09:38:34 -0700 Subject: [PATCH 02/10] Move WriteBuffer into CoreTerminal --- src/Terminal.ts | 14 -------------- src/common/CoreTerminal.ts | 21 +++++++++++++++++---- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 54863ce01..2385ad19f 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -50,7 +50,6 @@ import { CharSizeService } from 'browser/services/CharSizeService'; import { IBuffer } from 'common/buffer/Types'; import { MouseService } from 'browser/services/MouseService'; import { ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport, ILinkifier2 } from 'browser/Types'; -import { WriteBuffer } from 'common/input/WriteBuffer'; import { Linkifier2 } from 'browser/Linkifier2'; import { CoreBrowserService } from 'browser/services/CoreBrowserService'; import { CoreTerminal } from 'common/CoreTerminal'; @@ -86,9 +85,6 @@ export class Terminal extends CoreTerminal implements ITerminal { private _selectionService: ISelectionService; private _soundService: ISoundService; - // write buffer - private _writeBuffer: WriteBuffer; - // Store if user went browsing history in scrollback private _userScrolling: boolean; @@ -164,8 +160,6 @@ export class Terminal extends CoreTerminal implements ITerminal { // Setup listeners this._bufferService.onResize(e => this._afterResize(e.cols, e.rows)); - - this._writeBuffer = new WriteBuffer(data => this._inputHandler.parse(data)); } public dispose(): void { @@ -1364,14 +1358,6 @@ export class Terminal extends CoreTerminal implements ITerminal { // return this.options.bellStyle === 'sound' || // this.options.bellStyle === 'both'; } - - public write(data: string | Uint8Array, callback?: () => void): void { - this._writeBuffer.write(data, callback); - } - - public writeSync(data: string | Uint8Array): void { - this._writeBuffer.writeSync(data); - } } /** diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 8df2bd6ba..f98ef0dc7 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -38,6 +38,7 @@ import { updateWindowsModeWrappedState } from 'common/WindowsMode'; import { IFunctionIdentifier, IParams } from 'common/parser/Types'; import { IBufferSet } from 'common/buffer/Types'; import { InputHandler } from 'common/InputHandler'; +import { WriteBuffer } from 'common/input/WriteBuffer'; export abstract class CoreTerminal extends Disposable { protected readonly _instantiationService: IInstantiationService; @@ -52,6 +53,7 @@ export abstract class CoreTerminal extends Disposable { public readonly optionsService: IOptionsService; protected _inputHandler: InputHandler; + private _writeBuffer: WriteBuffer; private _windowsMode: IDisposable | undefined; private _onBinary = new EventEmitter(); @@ -91,16 +93,19 @@ export abstract class CoreTerminal extends Disposable { this._charsetService = this._instantiationService.createInstance(CharsetService); this._instantiationService.setService(ICharsetService, this._charsetService); + // Register input handler and handle/forward events + this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService, this.unicodeService); + this.register(forwardEvent(this._inputHandler.onLineFeed, this._onLineFeed)); + this.register(this._inputHandler); + // Setup listeners this.register(forwardEvent(this._bufferService.onResize, this._onResize)); this.register(forwardEvent(this._coreService.onData, this._onData)); this.register(forwardEvent(this._coreService.onBinary, this._onBinary)); this.register(this.optionsService.onOptionChange(key => this._updateOptions(key))); - // Register input handler and handle/forward events - this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService, this.unicodeService); - this.register(forwardEvent(this._inputHandler.onLineFeed, this._onLineFeed)); - this.register(this._inputHandler); + // Setup WriteBuffer + this._writeBuffer = new WriteBuffer(data => this._inputHandler.parse(data)); } public dispose(): void { @@ -112,6 +117,14 @@ export abstract class CoreTerminal extends Disposable { this._windowsMode = undefined; } + public write(data: string | Uint8Array, callback?: () => void): void { + this._writeBuffer.write(data, callback); + } + + public writeSync(data: string | Uint8Array): void { + this._writeBuffer.writeSync(data); + } + public resize(x: number, y: number): void { if (isNaN(x) || isNaN(y)) { return; From 21bcef5008de7ee49b2899f1549356d84c2c897c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 09:54:44 -0700 Subject: [PATCH 03/10] 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 2385ad19f..9f55e2bdf 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 f98ef0dc7..a870a7650 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 55e34084b..71faed99a 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 d62d2cb00..8de44e43c 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 6829d7b96..e123bd8bd 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 }>; From 2a9b76246b9ee56557ada869d6b6021ed6bced9a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 10:02:59 -0700 Subject: [PATCH 04/10] Move scroll into CoreTerminal --- src/Terminal.ts | 70 +------------------------------------ src/common/CoreTerminal.ts | 71 +++++++++++++++++++++++++++++++++++++- src/common/Types.d.ts | 2 +- 3 files changed, 72 insertions(+), 71 deletions(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 9f55e2bdf..b7c8ba93e 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -39,7 +39,7 @@ import { MouseZoneManager } from 'browser/MouseZoneManager'; import { AccessibilityManager } from './AccessibilityManager'; import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider } from 'xterm'; import { DomRenderer } from 'browser/renderer/dom/DomRenderer'; -import { IKeyboardEvent, KeyboardResultType, IBufferLine, IAttributeData, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions } from 'common/Types'; +import { IKeyboardEvent, KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions } from 'common/Types'; import { evaluateKeyboardEvent } from 'common/input/Keyboard'; import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; @@ -101,9 +101,6 @@ export class Terminal extends CoreTerminal implements ITerminal { private _colorManager: ColorManager; private _theme: ITheme; - // bufferline to clone/copy from for new blank lines - private _blankLine: IBufferLine = null; - private _onCursorMove = new EventEmitter(); public get onCursorMove(): IEvent { return this._onCursorMove.event; } private _onKey = new EventEmitter<{ key: string, domEvent: KeyboardEvent }>(); @@ -821,71 +818,6 @@ export class Terminal extends CoreTerminal implements ITerminal { } } - /** - * Scroll the terminal down 1 row, creating a blank line. - * @param isWrapped Whether the new line is wrapped from the previous line. - */ - public scroll(eraseAttr: IAttributeData, isWrapped: boolean = false): void { - let newLine: IBufferLine; - newLine = this._blankLine; - if (!newLine || newLine.length !== this.cols || newLine.getFg(0) !== eraseAttr.fg || newLine.getBg(0) !== eraseAttr.bg) { - newLine = this.buffer.getBlankLine(eraseAttr, isWrapped); - this._blankLine = newLine; - } - newLine.isWrapped = isWrapped; - - const topRow = this.buffer.ybase + this.buffer.scrollTop; - const bottomRow = this.buffer.ybase + this.buffer.scrollBottom; - - if (this.buffer.scrollTop === 0) { - // Determine whether the buffer is going to be trimmed after insertion. - const willBufferBeTrimmed = this.buffer.lines.isFull; - - // Insert the line using the fastest method - if (bottomRow === this.buffer.lines.length - 1) { - if (willBufferBeTrimmed) { - this.buffer.lines.recycle().copyFrom(newLine); - } else { - this.buffer.lines.push(newLine.clone()); - } - } else { - this.buffer.lines.splice(bottomRow + 1, 0, newLine.clone()); - } - - // Only adjust ybase and ydisp when the buffer is not trimmed - if (!willBufferBeTrimmed) { - this.buffer.ybase++; - // Only scroll the ydisp with ybase if the user has not scrolled up - 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._bufferService.isUserScrolling) { - this.buffer.ydisp = Math.max(this.buffer.ydisp - 1, 0); - } - } - } else { - // scrollTop is non-zero which means no line will be going to the - // scrollback, instead we can just shift them in-place. - const scrollRegionHeight = bottomRow - topRow + 1 /* as it's zero-based */; - this.buffer.lines.shiftElements(topRow + 1, scrollRegionHeight - 1, -1); - this.buffer.lines.set(bottomRow, newLine.clone()); - } - - // Move the viewport to the bottom of the buffer unless the user is - // scrolling. - if (!this._bufferService.isUserScrolling) { - this.buffer.ydisp = this.buffer.ybase; - } - - // Flag rows that need updating - this._dirtyRowService.markRangeDirty(this.buffer.scrollTop, this.buffer.scrollBottom); - - this._onScroll.fire(this.buffer.ydisp); - } - public scrollLines(disp: number, suppressScrollEvent?: boolean): void { super.scrollLines(disp, suppressScrollEvent); this.refresh(0, this.rows - 1); diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index a870a7650..113132c7e 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -27,7 +27,7 @@ import { InstantiationService } from 'common/services/InstantiationService'; import { LogService } from 'common/services/LogService'; import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; import { OptionsService } from 'common/services/OptionsService'; -import { ITerminalOptions, IDisposable } from 'common/Types'; +import { ITerminalOptions, IDisposable, IBufferLine, IAttributeData } from 'common/Types'; import { CoreService } from 'common/services/CoreService'; import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; import { CoreMouseService } from 'common/services/CoreMouseService'; @@ -55,6 +55,8 @@ export abstract class CoreTerminal extends Disposable { protected _inputHandler: InputHandler; private _writeBuffer: WriteBuffer; private _windowsMode: IDisposable | undefined; + /** An IBufferline to clone/copy from for new blank lines */ + private _cachedBlankLine: IBufferLine | undefined; private _onBinary = new EventEmitter(); public get onBinary(): IEvent { return this._onBinary.event; } @@ -138,6 +140,73 @@ export abstract class CoreTerminal extends Disposable { this._bufferService.resize(x, y); } + /** + * Scroll the terminal down 1 row, creating a blank line. + * @param isWrapped Whether the new line is wrapped from the previous line. + */ + public scroll(eraseAttr: IAttributeData, isWrapped: boolean = false): void { + const buffer = this._bufferService.buffer; + + let newLine: IBufferLine | undefined; + newLine = this._cachedBlankLine; + if (!newLine || newLine.length !== this.cols || newLine.getFg(0) !== eraseAttr.fg || newLine.getBg(0) !== eraseAttr.bg) { + newLine = buffer.getBlankLine(eraseAttr, isWrapped); + this._cachedBlankLine = newLine; + } + newLine.isWrapped = isWrapped; + + const topRow = buffer.ybase + buffer.scrollTop; + const bottomRow = buffer.ybase + buffer.scrollBottom; + + if (buffer.scrollTop === 0) { + // Determine whether the buffer is going to be trimmed after insertion. + const willBufferBeTrimmed = buffer.lines.isFull; + + // Insert the line using the fastest method + if (bottomRow === buffer.lines.length - 1) { + if (willBufferBeTrimmed) { + buffer.lines.recycle().copyFrom(newLine); + } else { + buffer.lines.push(newLine.clone()); + } + } else { + buffer.lines.splice(bottomRow + 1, 0, newLine.clone()); + } + + // Only adjust ybase and ydisp when the buffer is not trimmed + if (!willBufferBeTrimmed) { + buffer.ybase++; + // Only scroll the ydisp with ybase if the user has not scrolled up + if (!this._bufferService.isUserScrolling) { + 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._bufferService.isUserScrolling) { + buffer.ydisp = Math.max(buffer.ydisp - 1, 0); + } + } + } else { + // scrollTop is non-zero which means no line will be going to the + // scrollback, instead we can just shift them in-place. + const scrollRegionHeight = bottomRow - topRow + 1 /* as it's zero-based */; + buffer.lines.shiftElements(topRow + 1, scrollRegionHeight - 1, -1); + buffer.lines.set(bottomRow, newLine.clone()); + } + + // Move the viewport to the bottom of the buffer unless the user is + // scrolling. + if (!this._bufferService.isUserScrolling) { + buffer.ydisp = buffer.ybase; + } + + // Flag rows that need updating + this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + + this._onScroll.fire(buffer.ydisp); + } + /** * Scroll the display of the terminal * @param disp The number of lines to scroll down (negative scroll up). diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 49a723b21..b9d43b746 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -51,7 +51,7 @@ export interface ICircularList { get(index: number): T | undefined; set(index: number, value: T): void; push(value: T): void; - recycle(): T | undefined; + recycle(): T; pop(): T | undefined; splice(start: number, deleteCount: number, ...items: T[]): void; trimStart(count: number): void; From 4d01929503d7b496c949f3dbf6db25fddc57d83d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 10:11:24 -0700 Subject: [PATCH 05/10] Introduce ICoreTerminal --- .../src/renderLayer/LinkRenderLayer.ts | 6 ++--- src/TestUtils.test.ts | 2 +- src/Types.d.ts | 25 ++++++------------- src/common/CoreTerminal.ts | 4 +-- src/common/Types.d.ts | 6 +++++ 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts index 10cf9c1fe..a095b4aea 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts @@ -3,18 +3,18 @@ * @license MIT */ -import { ILinkifierAccessor } from '../../../../src/Types'; import { Terminal } from 'xterm'; import { BaseRenderLayer } from './BaseRenderLayer'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { is256Color } from '../atlas/CharAtlasUtils'; -import { IColorSet, ILinkifierEvent } from 'browser/Types'; +import { IColorSet, ILinkifierEvent, ILinkifier, ILinkifier2 } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; +import { ITerminal } from '../../../../src/Types'; export class LinkRenderLayer extends BaseRenderLayer { private _state: ILinkifierEvent | undefined; - constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) { + constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ITerminal) { super(container, 'link', zIndex, true, colors); terminal.linkifier.onShowLinkUnderline(e => this._onShowLinkUnderline(e)); terminal.linkifier.onHideLinkUnderline(e => this._onHideLinkUnderline(e)); diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index 32b2633f8..47a90b6c8 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -171,7 +171,7 @@ export class MockTerminal implements ITerminal { public addDisposableListener(type: string, handler: XtermListener): IDisposable { throw new Error('Method not implemented.'); } - public scrollLines(disp: number, suppressScrollEvent: boolean): void { + public scrollLines(disp: number): void { throw new Error('Method not implemented.'); } public scrollToRow(absoluteRow: number): number { diff --git a/src/Types.d.ts b/src/Types.d.ts index 05c89e158..a8f7f9a86 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -4,12 +4,14 @@ */ import { IDisposable, IMarker, ISelectionPosition, ILinkProvider } from 'xterm'; -import { IAttributeData, CharData, ITerminalOptions } from 'common/Types'; +import { IAttributeData, CharData, ITerminalOptions, ICoreTerminal } from 'common/Types'; import { IEvent } from 'common/EventEmitter'; import { ILinkifier, ILinkMatcherOptions, IViewport, ILinkifier2 } from 'browser/Types'; import { IOptionsService, IUnicodeService } from 'common/services/Services'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { IParams, IFunctionIdentifier } from 'common/parser/Types'; +import { Linkifier } from 'browser/Linkifier'; +import { Linkifier2 } from 'browser/Linkifier2'; export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean; @@ -23,23 +25,23 @@ export interface ICompositionHelper { keydown(ev: KeyboardEvent): boolean; } -export interface ITerminal extends IPublicTerminal, IElementAccessor, IBufferAccessor, ILinkifierAccessor { +export interface ITerminal extends IPublicTerminal, ICoreTerminal { + element: HTMLElement | undefined; screenElement: HTMLElement; browser: IBrowser; buffer: IBuffer; buffers: IBufferSet; viewport: IViewport; - optionsService: IOptionsService; // TODO: We should remove options once components adopt optionsService options: ITerminalOptions; - unicodeService: IUnicodeService; + linkifier: ILinkifier; + linkifier2: ILinkifier2; onBlur: IEvent; onFocus: IEvent; onA11yChar: IEvent; onA11yTab: IEvent; - scrollLines(disp: number, suppressScrollEvent?: boolean): void; cancel(ev: Event, force?: boolean): boolean | void; } @@ -95,19 +97,6 @@ export interface IPublicTerminal extends IDisposable { reset(): void; } -export interface IBufferAccessor { - buffer: IBuffer; -} - -export interface IElementAccessor { - readonly element: HTMLElement | undefined; -} - -export interface ILinkifierAccessor { - linkifier: ILinkifier; - linkifier2: ILinkifier2; -} - export interface IBrowser { isNode: boolean; userAgent: string; diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 113132c7e..3793ae25d 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -27,7 +27,7 @@ import { InstantiationService } from 'common/services/InstantiationService'; import { LogService } from 'common/services/LogService'; import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; import { OptionsService } from 'common/services/OptionsService'; -import { ITerminalOptions, IDisposable, IBufferLine, IAttributeData } from 'common/Types'; +import { ITerminalOptions, IDisposable, IBufferLine, IAttributeData, ICoreTerminal } from 'common/Types'; import { CoreService } from 'common/services/CoreService'; import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; import { CoreMouseService } from 'common/services/CoreMouseService'; @@ -40,7 +40,7 @@ import { IBufferSet } from 'common/buffer/Types'; import { InputHandler } from 'common/InputHandler'; import { WriteBuffer } from 'common/input/WriteBuffer'; -export abstract class CoreTerminal extends Disposable { +export abstract class CoreTerminal extends Disposable implements ICoreTerminal { protected readonly _instantiationService: IInstantiationService; protected readonly _bufferService: IBufferService; protected readonly _logService: ILogService; diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index b9d43b746..4fcb627bb 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -7,6 +7,12 @@ import { ITerminalOptions as IPublicTerminalOptions } from 'xterm'; import { IEvent, IEventEmitter } from 'common/EventEmitter'; import { IDeleteEvent, IInsertEvent } from 'common/CircularList'; import { IParams } from 'common/parser/Types'; +import { IOptionsService, IUnicodeService } from 'common/services/Services'; + +export interface ICoreTerminal { + optionsService: IOptionsService; + unicodeService: IUnicodeService; +} export interface IDisposable { dispose(): void; From f256206fd4435727f7123ee5c39123312c612ee4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 10:18:05 -0700 Subject: [PATCH 06/10] Move Terminal and AccessibilityManager into browser --- src/Terminal2.test.ts | 2 +- src/TestUtils.test.ts | 2 +- src/Types.d.ts | 94 --------------------- src/{ => browser}/AccessibilityManager.ts | 7 +- src/browser/RenderDebouncer.ts | 2 +- src/{ => browser}/Terminal.ts | 4 +- src/browser/Types.d.ts | 99 ++++++++++++++++++++++- src/public/Terminal.ts | 2 +- 8 files changed, 109 insertions(+), 103 deletions(-) rename src/{ => browser}/AccessibilityManager.ts (98%) rename src/{ => browser}/Terminal.ts (99%) diff --git a/src/Terminal2.test.ts b/src/Terminal2.test.ts index f7046240b..720ea6b17 100644 --- a/src/Terminal2.test.ts +++ b/src/Terminal2.test.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; import * as pty from 'node-pty'; -import { Terminal } from './Terminal'; +import { Terminal } from './browser/Terminal'; import { IDisposable } from 'xterm'; // all test files expect terminal in 80x25 diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index 47a90b6c8..965acc880 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -10,7 +10,7 @@ import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, I import { Buffer } from 'common/buffer/Buffer'; import * as Browser from 'common/Platform'; import { IDisposable, IMarker, IEvent, ISelectionPosition, ILinkProvider } from 'xterm'; -import { Terminal } from './Terminal'; +import { Terminal } from './browser/Terminal'; import { AttributeData } from 'common/buffer/AttributeData'; import { IColorManager, IColorSet, ILinkMatcherOptions, ILinkifier, IViewport, ILinkifier2 } from 'browser/Types'; import { IOptionsService, IUnicodeService } from 'common/services/Services'; diff --git a/src/Types.d.ts b/src/Types.d.ts index a8f7f9a86..1ffb7c5ef 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -13,97 +13,3 @@ import { IParams, IFunctionIdentifier } from 'common/parser/Types'; import { Linkifier } from 'browser/Linkifier'; import { Linkifier2 } from 'browser/Linkifier2'; -export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean; - -export type LineData = CharData[]; - -export interface ICompositionHelper { - compositionstart(): void; - compositionupdate(ev: CompositionEvent): void; - compositionend(): void; - updateCompositionElements(dontRecurse?: boolean): void; - keydown(ev: KeyboardEvent): boolean; -} - -export interface ITerminal extends IPublicTerminal, ICoreTerminal { - element: HTMLElement | undefined; - screenElement: HTMLElement; - browser: IBrowser; - buffer: IBuffer; - buffers: IBufferSet; - viewport: IViewport; - // TODO: We should remove options once components adopt optionsService - options: ITerminalOptions; - linkifier: ILinkifier; - linkifier2: ILinkifier2; - - onBlur: IEvent; - onFocus: IEvent; - onA11yChar: IEvent; - onA11yTab: IEvent; - - cancel(ev: Event, force?: boolean): boolean | void; -} - -// Portions of the public API that are required by the internal Terminal -export interface IPublicTerminal extends IDisposable { - textarea: HTMLTextAreaElement | undefined; - rows: number; - cols: number; - buffer: IBuffer; - markers: IMarker[]; - onCursorMove: IEvent; - onData: IEvent; - onBinary: IEvent; - onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>; - onLineFeed: IEvent; - onScroll: IEvent; - onSelectionChange: IEvent; - onRender: IEvent<{ start: number, end: number }>; - onResize: IEvent<{ cols: number, rows: number }>; - onTitleChange: IEvent; - blur(): void; - focus(): void; - resize(columns: number, rows: number): void; - open(parent: HTMLElement): void; - attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; - addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; - addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable; - addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable; - addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; - registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number; - deregisterLinkMatcher(matcherId: number): void; - registerLinkProvider(linkProvider: ILinkProvider): IDisposable; - registerCharacterJoiner(handler: (text: string) => [number, number][]): number; - deregisterCharacterJoiner(joinerId: number): void; - addMarker(cursorYOffset: number): IMarker; - hasSelection(): boolean; - getSelection(): string; - getSelectionPosition(): ISelectionPosition | undefined; - clearSelection(): void; - select(column: number, row: number, length: number): void; - selectAll(): void; - selectLines(start: number, end: number): void; - dispose(): void; - scrollLines(amount: number): void; - scrollPages(pageCount: number): void; - scrollToTop(): void; - scrollToBottom(): void; - scrollToLine(line: number): void; - clear(): void; - write(data: string | Uint8Array, callback?: () => void): void; - paste(data: string): void; - refresh(start: number, end: number): void; - reset(): void; -} - -export interface IBrowser { - isNode: boolean; - userAgent: string; - platform: string; - isFirefox: boolean; - isMac: boolean; - isIpad: boolean; - isIphone: boolean; - isWindows: boolean; -} diff --git a/src/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts similarity index 98% rename from src/AccessibilityManager.ts rename to src/browser/AccessibilityManager.ts index 783915011..b613e9ba6 100644 --- a/src/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -3,8 +3,8 @@ * @license MIT */ -import * as Strings from './browser/LocalizableStrings'; -import { ITerminal } from './Types'; +import * as Strings from 'browser/LocalizableStrings'; +import { ITerminal } from 'browser/Types'; import { IBuffer } from 'common/buffer/Types'; import { isMac } from 'common/Platform'; import { RenderDebouncer } from 'browser/RenderDebouncer'; @@ -79,6 +79,9 @@ export class AccessibilityManager extends Disposable { this._liveRegion.setAttribute('aria-live', 'assertive'); this._accessibilityTreeRoot.appendChild(this._liveRegion); + if (!this._terminal.element) { + throw new Error('Cannot enable accessibility before Terminal.open'); + } this._terminal.element.insertAdjacentElement('afterbegin', this._accessibilityTreeRoot); this.register(this._renderRowsDebouncer); diff --git a/src/browser/RenderDebouncer.ts b/src/browser/RenderDebouncer.ts index 814afcef4..2a06fdd66 100644 --- a/src/browser/RenderDebouncer.ts +++ b/src/browser/RenderDebouncer.ts @@ -26,7 +26,7 @@ export class RenderDebouncer implements IDisposable { } } - public refresh(rowStart: number, rowEnd: number, rowCount: number): void { + public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void { this._rowCount = rowCount; // Get the min/max row start/end for the arg values rowStart = rowStart !== undefined ? rowStart : 0; diff --git a/src/Terminal.ts b/src/browser/Terminal.ts similarity index 99% rename from src/Terminal.ts rename to src/browser/Terminal.ts index b7c8ba93e..2c22a12ca 100644 --- a/src/Terminal.ts +++ b/src/browser/Terminal.ts @@ -21,13 +21,13 @@ * http://linux.die.net/man/7/urxvt */ -import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler } from './Types'; +import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler } from '../Types'; import { IRenderer, CharacterJoinerHandler } from 'browser/renderer/Types'; import { CompositionHelper } from 'browser/input/CompositionHelper'; import { Viewport } from 'browser/Viewport'; import { rightClickHandler, moveTextAreaUnderMouseCursor, handlePasteEvent, copyHandler, paste } from 'browser/Clipboard'; import { C0 } from 'common/data/EscapeSequences'; -import { WindowsOptionsReportType } from './common/InputHandler'; +import { WindowsOptionsReportType } from '../common/InputHandler'; import { Renderer } from 'browser/renderer/Renderer'; import { Linkifier } from 'browser/Linkifier'; import { SelectionService } from 'browser/services/SelectionService'; diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index f4645543f..847d64e57 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -3,9 +3,106 @@ * @license MIT */ +import { IDisposable, IMarker, ISelectionPosition } from 'xterm'; import { IEvent } from 'common/EventEmitter'; -import { IDisposable } from 'common/Types'; +import { ICoreTerminal, CharData, ITerminalOptions } from 'common/Types'; import { IMouseService, IRenderService } from './services/Services'; +import { IBuffer, IBufferSet } from 'common/buffer/Types'; + +export interface ITerminal extends IPublicTerminal, ICoreTerminal { + element: HTMLElement | undefined; + screenElement: HTMLElement; + browser: IBrowser; + buffer: IBuffer; + buffers: IBufferSet; + viewport: IViewport; + // TODO: We should remove options once components adopt optionsService + options: ITerminalOptions; + linkifier: ILinkifier; + linkifier2: ILinkifier2; + + onBlur: IEvent; + onFocus: IEvent; + onA11yChar: IEvent; + onA11yTab: IEvent; + + cancel(ev: Event, force?: boolean): boolean | void; +} + +// Portions of the public API that are required by the internal Terminal +export interface IPublicTerminal extends IDisposable { + textarea: HTMLTextAreaElement | undefined; + rows: number; + cols: number; + buffer: IBuffer; + markers: IMarker[]; + onCursorMove: IEvent; + onData: IEvent; + onBinary: IEvent; + onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>; + onLineFeed: IEvent; + onScroll: IEvent; + onSelectionChange: IEvent; + onRender: IEvent<{ start: number, end: number }>; + onResize: IEvent<{ cols: number, rows: number }>; + onTitleChange: IEvent; + blur(): void; + focus(): void; + resize(columns: number, rows: number): void; + open(parent: HTMLElement): void; + attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; + // addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; + // addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable; + // addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable; + // addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; + registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number; + deregisterLinkMatcher(matcherId: number): void; + registerLinkProvider(linkProvider: ILinkProvider): IDisposable; + registerCharacterJoiner(handler: (text: string) => [number, number][]): number; + deregisterCharacterJoiner(joinerId: number): void; + addMarker(cursorYOffset: number): IMarker; + hasSelection(): boolean; + getSelection(): string; + getSelectionPosition(): ISelectionPosition | undefined; + clearSelection(): void; + select(column: number, row: number, length: number): void; + selectAll(): void; + selectLines(start: number, end: number): void; + dispose(): void; + scrollLines(amount: number): void; + scrollPages(pageCount: number): void; + scrollToTop(): void; + scrollToBottom(): void; + scrollToLine(line: number): void; + clear(): void; + write(data: string | Uint8Array, callback?: () => void): void; + paste(data: string): void; + refresh(start: number, end: number): void; + reset(): void; +} + +export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean; + +export type LineData = CharData[]; + +export interface ICompositionHelper { + compositionstart(): void; + compositionupdate(ev: CompositionEvent): void; + compositionend(): void; + updateCompositionElements(dontRecurse?: boolean): void; + keydown(ev: KeyboardEvent): boolean; +} + +export interface IBrowser { + isNode: boolean; + userAgent: string; + platform: string; + isFirefox: boolean; + isMac: boolean; + isIpad: boolean; + isIphone: boolean; + isWindows: boolean; +} export interface IColorManager { colors: IColorSet; diff --git a/src/public/Terminal.ts b/src/public/Terminal.ts index 61334f08a..d9b951ef4 100644 --- a/src/public/Terminal.ts +++ b/src/public/Terminal.ts @@ -8,7 +8,7 @@ import { ITerminal } from '../Types'; import { IBufferLine, ICellData } from 'common/Types'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { CellData } from 'common/buffer/CellData'; -import { Terminal as TerminalCore } from '../Terminal'; +import { Terminal as TerminalCore } from '../browser/Terminal'; import * as Strings from '../browser/LocalizableStrings'; import { IEvent, EventEmitter } from 'common/EventEmitter'; import { AddonManager } from './AddonManager'; From bdb438972f9b1e79f8d115b22d00b868d23e1cd1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 10:44:44 -0700 Subject: [PATCH 07/10] Fix errors in Terminal and elsewhere This was mostly ! to compel TS, we should actually fix this down the road but that can come later. --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 19 +- .../src/renderLayer/LinkRenderLayer.ts | 3 +- src/TestUtils.test.ts | 3 +- src/browser/AccessibilityManager.ts | 2 +- src/browser/Linkifier2.ts | 2 +- src/browser/Terminal.ts | 249 +++++++++--------- src/browser/Types.d.ts | 15 +- src/browser/services/RenderService.ts | 2 +- src/public/Terminal.ts | 2 +- test/benchmark/Terminal.benchmark.ts | 2 +- typings/xterm.d.ts | 2 +- 11 files changed, 147 insertions(+), 154 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 0333fd208..ac997c960 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -3,7 +3,6 @@ * @license MIT */ -import { ITerminal } from '../../../src/Types'; import { GlyphRenderer } from './GlyphRenderer'; import { LinkRenderLayer } from './renderLayer/LinkRenderLayer'; import { CursorRenderLayer } from './renderLayer/CursorRenderLayer'; @@ -17,7 +16,7 @@ import { NULL_CELL_CODE } from 'common/buffer/Constants'; import { Terminal, IEvent } from 'xterm'; import { IRenderLayer } from './renderLayer/Types'; import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types'; -import { IColorSet } from 'browser/Types'; +import { ITerminal, IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { CellData } from 'common/buffer/CellData'; @@ -52,8 +51,8 @@ export class WebglRenderer extends Disposable implements IRenderer { this._core = (this._terminal as any)._core; this._renderLayers = [ - new LinkRenderLayer(this._core.screenElement, 2, this._colors, this._core), - new CursorRenderLayer(this._core.screenElement, 3, this._colors, this._onRequestRedraw) + new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core), + new CursorRenderLayer(this._core.screenElement!, 3, this._colors, this._onRequestRedraw) ]; this.dimensions = { scaledCharWidth: 0, @@ -83,7 +82,7 @@ export class WebglRenderer extends Disposable implements IRenderer { if (!this._gl) { throw new Error('WebGL2 not supported ' + this._gl); } - this._core.screenElement.appendChild(this._canvas); + this._core.screenElement!.appendChild(this._canvas); this._rectangleRenderer = new RectangleRenderer(this._terminal, this._colors, this._gl, this.dimensions); this._glyphRenderer = new GlyphRenderer(this._terminal, this._colors, this._gl, this.dimensions); @@ -91,12 +90,12 @@ export class WebglRenderer extends Disposable implements IRenderer { // Update dimensions and acquire char atlas this.onCharSizeChanged(); - this._isAttached = document.body.contains(this._core.screenElement); + this._isAttached = document.body.contains(this._core.screenElement!); } public dispose(): void { this._renderLayers.forEach(l => l.dispose()); - this._core.screenElement.removeChild(this._canvas); + this._core.screenElement!.removeChild(this._canvas); super.dispose(); } @@ -150,8 +149,8 @@ export class WebglRenderer extends Disposable implements IRenderer { this._canvas.style.height = `${this.dimensions.canvasHeight}px`; // Resize the screen - this._core.screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._core.screenElement.style.height = `${this.dimensions.canvasHeight}px`; + this._core.screenElement!.style.width = `${this.dimensions.canvasWidth}px`; + this._core.screenElement!.style.height = `${this.dimensions.canvasHeight}px`; this._glyphRenderer.setDimensions(this.dimensions); this._glyphRenderer.onResize(); @@ -229,7 +228,7 @@ export class WebglRenderer extends Disposable implements IRenderer { public renderRows(start: number, end: number): void { if (!this._isAttached) { - if (document.body.contains(this._core.screenElement) && (this._core as any)._charSizeService.width && (this._core as any)._charSizeService.height) { + if (document.body.contains(this._core.screenElement!) && (this._core as any)._charSizeService.width && (this._core as any)._charSizeService.height) { this._updateDimensions(); this._refreshCharAtlas(); this._isAttached = true; diff --git a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts index a095b4aea..8f6b3e6da 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts @@ -7,9 +7,8 @@ import { Terminal } from 'xterm'; import { BaseRenderLayer } from './BaseRenderLayer'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { is256Color } from '../atlas/CharAtlasUtils'; -import { IColorSet, ILinkifierEvent, ILinkifier, ILinkifier2 } from 'browser/Types'; +import { ITerminal, IColorSet, ILinkifierEvent } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; -import { ITerminal } from '../../../../src/Types'; export class LinkRenderLayer extends BaseRenderLayer { private _state: ILinkifierEvent | undefined; diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index 965acc880..102a53537 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -4,7 +4,6 @@ */ import { IRenderer, IRenderDimensions, CharacterJoinerHandler, IRequestRedrawEvent } from 'browser/renderer/Types'; -import { ICompositionHelper, ITerminal, IBrowser } from './Types'; import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, ITerminalOptions } from 'common/Types'; import { Buffer } from 'common/buffer/Buffer'; @@ -12,7 +11,7 @@ import * as Browser from 'common/Platform'; import { IDisposable, IMarker, IEvent, ISelectionPosition, ILinkProvider } from 'xterm'; import { Terminal } from './browser/Terminal'; import { AttributeData } from 'common/buffer/AttributeData'; -import { IColorManager, IColorSet, ILinkMatcherOptions, ILinkifier, IViewport, ILinkifier2 } from 'browser/Types'; +import { IColorManager, IColorSet, ILinkMatcherOptions, ILinkifier, IViewport, ILinkifier2, ICompositionHelper, ITerminal, IBrowser } from 'browser/Types'; import { IOptionsService, IUnicodeService } from 'common/services/Services'; import { IParams, IFunctionIdentifier } from 'common/parser/Types'; import { ISelectionService } from 'browser/services/Services'; diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index b613e9ba6..2a34d6a36 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -106,7 +106,7 @@ export class AccessibilityManager extends Disposable { public dispose(): void { super.dispose(); - this._terminal.element.removeChild(this._accessibilityTreeRoot); + this._terminal.element?.removeChild(this._accessibilityTreeRoot); this._rowElements.length = 0; } diff --git a/src/browser/Linkifier2.ts b/src/browser/Linkifier2.ts index 548121699..458b1bff0 100644 --- a/src/browser/Linkifier2.ts +++ b/src/browser/Linkifier2.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent, ILinkDecorations } from './Types'; +import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent, ILinkDecorations } from 'browser/Types'; import { IDisposable } from 'common/Types'; import { IMouseService, IRenderService } from './services/Services'; import { IBufferService } from 'common/services/Services'; diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 2c22a12ca..7f3ead61c 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -21,7 +21,7 @@ * http://linux.die.net/man/7/urxvt */ -import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler } from '../Types'; +import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler, ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport, ILinkifier2 } from 'browser/Types'; import { IRenderer, CharacterJoinerHandler } from 'browser/renderer/Types'; import { CompositionHelper } from 'browser/input/CompositionHelper'; import { Viewport } from 'browser/Viewport'; @@ -49,41 +49,40 @@ import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISo import { CharSizeService } from 'browser/services/CharSizeService'; import { IBuffer } from 'common/buffer/Types'; import { MouseService } from 'browser/services/MouseService'; -import { ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport, ILinkifier2 } from 'browser/Types'; import { Linkifier2 } from 'browser/Linkifier2'; import { CoreBrowserService } from 'browser/services/CoreBrowserService'; import { CoreTerminal } from 'common/CoreTerminal'; +import { ITerminalOptions as IInitializedTerminalOptions } from 'common/services/Services'; // Let it work inside Node.js for automated testing purposes. -const document = (typeof window !== 'undefined') ? window.document : null; - +const document: Document = (typeof window !== 'undefined') ? window.document : null as any; export class Terminal extends CoreTerminal implements ITerminal { - public textarea: HTMLTextAreaElement; - public element: HTMLElement; - public screenElement: HTMLElement; + public textarea: HTMLTextAreaElement | undefined; + public element: HTMLElement | undefined; + public screenElement: HTMLElement | undefined; - private _document: Document; - private _viewportScrollArea: HTMLElement; - private _viewportElement: HTMLElement; - private _helperContainer: HTMLElement; - private _compositionView: HTMLElement; + private _document: Document | undefined; + private _viewportScrollArea: HTMLElement | undefined; + private _viewportElement: HTMLElement | undefined; + private _helperContainer: HTMLElement | undefined; + private _compositionView: HTMLElement | undefined; - private _visualBellTimer: number; + // private _visualBellTimer: number; public browser: IBrowser = Browser; // TODO: We should remove options once components adopt optionsService - public get options(): ITerminalOptions { return this.optionsService.options; } + public get options(): IInitializedTerminalOptions { return this.optionsService.options; } - private _customKeyEventHandler: CustomKeyEventHandler; + private _customKeyEventHandler: CustomKeyEventHandler | undefined; // browser services - private _charSizeService: ICharSizeService; - private _mouseService: IMouseService; - private _renderService: IRenderService; - private _selectionService: ISelectionService; - private _soundService: ISoundService; + private _charSizeService: ICharSizeService | undefined; + private _mouseService: IMouseService | undefined; + private _renderService: IRenderService | undefined; + private _selectionService: ISelectionService | undefined; + private _soundService: ISoundService | undefined; /** * Records whether the keydown event has already been handled and triggered a data event, if so @@ -94,12 +93,12 @@ export class Terminal extends CoreTerminal implements ITerminal { public linkifier: ILinkifier; public linkifier2: ILinkifier2; - public viewport: IViewport; - private _compositionHelper: ICompositionHelper; - private _mouseZoneManager: IMouseZoneManager; - private _accessibilityManager: AccessibilityManager; - private _colorManager: ColorManager; - private _theme: ITheme; + public viewport: IViewport | undefined; + private _compositionHelper: ICompositionHelper | undefined; + private _mouseZoneManager: IMouseZoneManager | undefined; + private _accessibilityManager: AccessibilityManager | undefined; + private _colorManager: ColorManager | undefined; + private _theme: ITheme | undefined; private _onCursorMove = new EventEmitter(); public get onCursorMove(): IEvent { return this._onCursorMove.event; } @@ -140,6 +139,10 @@ export class Terminal extends CoreTerminal implements ITerminal { this._setup(); + this.linkifier = this._instantiationService.createInstance(Linkifier); + this.linkifier2 = this._instantiationService.createInstance(Linkifier2); + + // Setup InputHandler listeners this.register(this._inputHandler.onRequestBell(() => this.bell())); this.register(this._inputHandler.onRequestRefreshRows((start, end) => this.refresh(start, end))); this.register(this._inputHandler.onRequestReset(() => this.reset())); @@ -160,7 +163,7 @@ export class Terminal extends CoreTerminal implements ITerminal { } super.dispose(); this._renderService?.dispose(); - this._customKeyEventHandler = null; + this._customKeyEventHandler = undefined; this.write = () => { }; this.element?.parentNode?.removeChild(this.element); } @@ -168,14 +171,7 @@ export class Terminal extends CoreTerminal implements ITerminal { protected _setup(): void { super._setup(); - this._customKeyEventHandler = null; - - if (!this.linkifier) { - this.linkifier = this._instantiationService.createInstance(Linkifier); - } - if (!this.linkifier2) { - this.linkifier2 = this._instantiationService.createInstance(Linkifier2); - } + this._customKeyEventHandler = undefined; } /** @@ -239,7 +235,7 @@ export class Terminal extends CoreTerminal implements ITerminal { } } else { this._accessibilityManager?.dispose(); - this._accessibilityManager = null; + this._accessibilityManager = undefined; } break; case 'tabStopWidth': this.buffers.setupTabStops(); break; @@ -257,7 +253,7 @@ export class Terminal extends CoreTerminal implements ITerminal { this._coreService.triggerDataEvent(C0.ESC + '[I'); } this.updateCursorStyle(ev); - this.element.classList.add('focus'); + this.element!.classList.add('focus'); this._showCursor(); this._onFocus.fire(); } @@ -267,7 +263,7 @@ export class Terminal extends CoreTerminal implements ITerminal { * textarea. */ public blur(): void { - return this.textarea.blur(); + return this.textarea?.blur(); } /** @@ -276,12 +272,12 @@ export class Terminal extends CoreTerminal implements ITerminal { private _onTextAreaBlur(): void { // Text can safely be removed on blur. Doing it earlier could interfere with // screen readers reading it out. - this.textarea.value = ''; + this.textarea!.value = ''; this.refresh(this.buffer.y, this.buffer.y); if (this._coreService.decPrivateModes.sendFocus) { this._coreService.triggerDataEvent(C0.ESC + '[O'); } - this.element.classList.remove('focus'); + this.element!.classList.remove('focus'); this._onBlur.fire(); } @@ -292,29 +288,29 @@ export class Terminal extends CoreTerminal implements ITerminal { this._bindKeys(); // Bind clipboard functionality - this.register(addDisposableDomListener(this.element, 'copy', (event: ClipboardEvent) => { + this.register(addDisposableDomListener(this.element!, 'copy', (event: ClipboardEvent) => { // If mouse events are active it means the selection manager is disabled and // copy should be handled by the host program. if (!this.hasSelection()) { return; } - copyHandler(event, this._selectionService); + copyHandler(event, this._selectionService!); })); - const pasteHandlerWrapper = (event: ClipboardEvent): void => handlePasteEvent(event, this.textarea, this._coreService); - this.register(addDisposableDomListener(this.textarea, 'paste', pasteHandlerWrapper)); - this.register(addDisposableDomListener(this.element, 'paste', pasteHandlerWrapper)); + const pasteHandlerWrapper = (event: ClipboardEvent): void => handlePasteEvent(event, this.textarea!, this._coreService); + this.register(addDisposableDomListener(this.textarea!, 'paste', pasteHandlerWrapper)); + this.register(addDisposableDomListener(this.element!, 'paste', pasteHandlerWrapper)); // Handle right click context menus if (Browser.isFirefox) { // Firefox doesn't appear to fire the contextmenu event on right click - this.register(addDisposableDomListener(this.element, 'mousedown', (event: MouseEvent) => { + this.register(addDisposableDomListener(this.element!, 'mousedown', (event: MouseEvent) => { if (event.button === 2) { - rightClickHandler(event, this.textarea, this.screenElement, this._selectionService, this.options.rightClickSelectsWord); + rightClickHandler(event, this.textarea!, this.screenElement!, this._selectionService!, this.options.rightClickSelectsWord); } })); } else { - this.register(addDisposableDomListener(this.element, 'contextmenu', (event: MouseEvent) => { - rightClickHandler(event, this.textarea, this.screenElement, this._selectionService, this.options.rightClickSelectsWord); + this.register(addDisposableDomListener(this.element!, 'contextmenu', (event: MouseEvent) => { + rightClickHandler(event, this.textarea!, this.screenElement!, this._selectionService!, this.options.rightClickSelectsWord); })); } @@ -324,9 +320,9 @@ export class Terminal extends CoreTerminal implements ITerminal { if (Browser.isLinux) { // Use auxclick event over mousedown the latter doesn't seem to work. Note // that the regular click event doesn't fire for the middle mouse button. - this.register(addDisposableDomListener(this.element, 'auxclick', (event: MouseEvent) => { + this.register(addDisposableDomListener(this.element!, 'auxclick', (event: MouseEvent) => { if (event.button === 1) { - moveTextAreaUnderMouseCursor(event, this.textarea, this.screenElement); + moveTextAreaUnderMouseCursor(event, this.textarea!, this.screenElement!); } })); } @@ -336,13 +332,13 @@ export class Terminal extends CoreTerminal implements ITerminal { * Apply key handling to the terminal */ private _bindKeys(): void { - this.register(addDisposableDomListener(this.textarea, 'keyup', (ev: KeyboardEvent) => this._keyUp(ev), true)); - this.register(addDisposableDomListener(this.textarea, 'keydown', (ev: KeyboardEvent) => this._keyDown(ev), true)); - this.register(addDisposableDomListener(this.textarea, 'keypress', (ev: KeyboardEvent) => this._keyPress(ev), true)); - this.register(addDisposableDomListener(this.textarea, 'compositionstart', () => this._compositionHelper.compositionstart())); - this.register(addDisposableDomListener(this.textarea, 'compositionupdate', (e: CompositionEvent) => this._compositionHelper.compositionupdate(e))); - this.register(addDisposableDomListener(this.textarea, 'compositionend', () => this._compositionHelper.compositionend())); - this.register(this.onRender(() => this._compositionHelper.updateCompositionElements())); + this.register(addDisposableDomListener(this.textarea!, 'keyup', (ev: KeyboardEvent) => this._keyUp(ev), true)); + this.register(addDisposableDomListener(this.textarea!, 'keydown', (ev: KeyboardEvent) => this._keyDown(ev), true)); + this.register(addDisposableDomListener(this.textarea!, 'keypress', (ev: KeyboardEvent) => this._keyPress(ev), true)); + this.register(addDisposableDomListener(this.textarea!, 'compositionstart', () => this._compositionHelper!.compositionstart())); + this.register(addDisposableDomListener(this.textarea!, 'compositionupdate', (e: CompositionEvent) => this._compositionHelper!.compositionupdate(e))); + this.register(addDisposableDomListener(this.textarea!, 'compositionend', () => this._compositionHelper!.compositionend())); + this.register(this.onRender(() => this._compositionHelper!.updateCompositionElements())); this.register(this.onRender(e => this._queueLinkification(e.start, e.end))); } @@ -360,7 +356,7 @@ export class Terminal extends CoreTerminal implements ITerminal { this._logService.debug('Terminal.open was called on an element that was not attached to the DOM'); } - this._document = parent.ownerDocument; + this._document = parent.ownerDocument!; // Create main element container this.element = this._document.createElement('div'); @@ -416,16 +412,15 @@ export class Terminal extends CoreTerminal implements ITerminal { this.element.appendChild(fragment); this._theme = this.options.theme || this._theme; - this.options.theme = undefined; this._colorManager = new ColorManager(document, this.options.allowTransparency); - this.optionsService.onOptionChange(e => this._colorManager.onOptionsChange(e)); + this.optionsService.onOptionChange(e => this._colorManager!.onOptionsChange(e)); this._colorManager.setTheme(this._theme); const renderer = this._createRenderer(); this._renderService = this._instantiationService.createInstance(RenderService, renderer, this.rows, this.screenElement); this._instantiationService.setService(IRenderService, this._renderService); this._renderService.onRenderedBufferChange(e => this._onRender.fire(e)); - this.onResize(e => this._renderService.resize(e.cols, e.rows)); + this.onResize(e => this._renderService!.resize(e.cols, e.rows)); this._soundService = this._instantiationService.createInstance(SoundService); this._instantiationService.setService(ISoundService, this._soundService); @@ -438,14 +433,14 @@ export class Terminal extends CoreTerminal implements ITerminal { this._viewportScrollArea ); this.viewport.onThemeChange(this._colorManager.colors); - this.register(this._inputHandler.onRequestSyncScrollBar(() => this.viewport.syncScrollArea())); + this.register(this._inputHandler.onRequestSyncScrollBar(() => this.viewport!.syncScrollArea())); this.register(this.viewport); - this.register(this.onCursorMove(() => this._renderService.onCursorMove())); - this.register(this.onResize(() => this._renderService.onResize(this.cols, this.rows))); - this.register(this.onBlur(() => this._renderService.onBlur())); - this.register(this.onFocus(() => this._renderService.onFocus())); - this.register(this._renderService.onDimensionsChange(() => this.viewport.syncScrollArea())); + this.register(this.onCursorMove(() => this._renderService!.onCursorMove())); + this.register(this.onResize(() => this._renderService!.onResize(this.cols, this.rows))); + this.register(this.onBlur(() => this._renderService!.onBlur())); + this.register(this.onFocus(() => this._renderService!.onFocus())); + this.register(this._renderService.onDimensionsChange(() => this.viewport!.syncScrollArea())); this._selectionService = this._instantiationService.createInstance(SelectionService, (amount: number, suppressEvent: boolean) => this.scrollLines(amount, suppressEvent), @@ -453,29 +448,29 @@ export class Terminal extends CoreTerminal implements ITerminal { this.screenElement); this._instantiationService.setService(ISelectionService, this._selectionService); this.register(this._selectionService.onSelectionChange(() => this._onSelectionChange.fire())); - this.register(this._selectionService.onRedrawRequest(e => this._renderService.onSelectionChanged(e.start, e.end, e.columnSelectMode))); + this.register(this._selectionService.onRedrawRequest(e => this._renderService!.onSelectionChanged(e.start, e.end, e.columnSelectMode))); this.register(this._selectionService.onLinuxMouseSelection(text => { // If there's a new selection, put it into the textarea, focus and select it // in order to register it as a selection on the OS. This event is fired // only on Linux to enable middle click to paste selection. - this.textarea.value = text; - this.textarea.focus(); - this.textarea.select(); + this.textarea!.value = text; + this.textarea!.focus(); + this.textarea!.select(); })); this.register(this.onScroll(() => { - this.viewport.syncScrollArea(); - this._selectionService.refresh(); + this.viewport!.syncScrollArea(); + this._selectionService!.refresh(); })); - this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this._selectionService.refresh())); + this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this._selectionService!.refresh())); this._mouseZoneManager = this._instantiationService.createInstance(MouseZoneManager, this.element, this.screenElement); this.register(this._mouseZoneManager); - this.register(this.onScroll(() => this._mouseZoneManager.clearAll())); + this.register(this.onScroll(() => this._mouseZoneManager!.clearAll())); this.linkifier.attachToDom(this.element, this._mouseZoneManager); this.linkifier2.attachToDom(this.element, this._mouseService, this._renderService); // This event listener must be registered aftre MouseZoneManager is created - this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService.onMouseDown(e))); + this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.onMouseDown(e))); // apply mouse event classes set by escape codes before terminal was attached if (this._coreMouseService.areMouseEventsActive) { @@ -507,8 +502,8 @@ export class Terminal extends CoreTerminal implements ITerminal { private _createRenderer(): IRenderer { switch (this.options.rendererType) { - case 'canvas': return this._instantiationService.createInstance(Renderer, this._colorManager.colors, this.screenElement, this.linkifier, this.linkifier2); - case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier, this.linkifier2); + case 'canvas': return this._instantiationService.createInstance(Renderer, this._colorManager!.colors, this.screenElement!, this.linkifier, this.linkifier2); + case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager!.colors, this.element!, this.screenElement!, this._viewportElement!, this.linkifier, this.linkifier2); default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } } @@ -520,8 +515,8 @@ export class Terminal extends CoreTerminal implements ITerminal { private _setTheme(theme: ITheme): void { this._theme = theme; this._colorManager?.setTheme(theme); - this._renderService?.setColors(this._colorManager.colors); - this.viewport?.onThemeChange(this._colorManager.colors); + this._renderService?.setColors(this._colorManager!.colors); + this.viewport?.onThemeChange(this._colorManager!.colors); } /** @@ -541,18 +536,18 @@ export class Terminal extends CoreTerminal implements ITerminal { */ public bindMouse(): void { const self = this; - const el = this.element; + const el = this.element!; // send event to CoreMouseService function sendEvent(ev: MouseEvent | WheelEvent): boolean { // get mouse coordinates - const pos = self._mouseService.getRawByteCoords(ev, self.screenElement, self.cols, self.rows); + const pos = self._mouseService!.getRawByteCoords(ev, self.screenElement!, self.cols, self.rows); if (!pos) { return false; } let but: CoreMouseButton; - let action: CoreMouseAction; + let action: CoreMouseAction | undefined; switch ((ev).overrideType || ev.type) { case 'mousemove': action = CoreMouseAction.MOVE; @@ -621,14 +616,14 @@ export class Terminal extends CoreTerminal implements ITerminal { mousedrag: null, mousemove: null }; - const eventListeners: { [key: string]: (ev: Event) => void } = { + const eventListeners: { [key: string]: (ev: any) => void | boolean } = { mouseup: (ev: MouseEvent) => { sendEvent(ev); if (!ev.buttons) { // if no other button is held remove global handlers - this._document.removeEventListener('mouseup', requestedEvents.mouseup); + this._document!.removeEventListener('mouseup', requestedEvents.mouseup!); if (requestedEvents.mousedrag) { - this._document.removeEventListener('mousemove', requestedEvents.mousedrag); + this._document!.removeEventListener('mousemove', requestedEvents.mousedrag); } } return this.cancel(ev); @@ -657,18 +652,18 @@ export class Terminal extends CoreTerminal implements ITerminal { if (this.optionsService.options.logLevel === 'debug') { this._logService.debug('Binding to mouse events:', this._coreMouseService.explainEvents(events)); } - this.element.classList.add('enable-mouse-events'); - this._selectionService.disable(); + this.element!.classList.add('enable-mouse-events'); + this._selectionService!.disable(); } else { this._logService.debug('Unbinding from mouse events.'); - this.element.classList.remove('enable-mouse-events'); - this._selectionService.enable(); + this.element!.classList.remove('enable-mouse-events'); + this._selectionService!.enable(); } // add/remove handlers from requestedEvents if (!(events & CoreMouseEventType.MOVE)) { - el.removeEventListener('mousemove', requestedEvents.mousemove); + el.removeEventListener('mousemove', requestedEvents.mousemove!); requestedEvents.mousemove = null; } else if (!requestedEvents.mousemove) { el.addEventListener('mousemove', eventListeners.mousemove); @@ -676,7 +671,7 @@ export class Terminal extends CoreTerminal implements ITerminal { } if (!(events & CoreMouseEventType.WHEEL)) { - el.removeEventListener('wheel', requestedEvents.wheel); + el.removeEventListener('wheel', requestedEvents.wheel!); requestedEvents.wheel = null; } else if (!requestedEvents.wheel) { el.addEventListener('wheel', eventListeners.wheel); @@ -684,14 +679,14 @@ export class Terminal extends CoreTerminal implements ITerminal { } if (!(events & CoreMouseEventType.UP)) { - this._document.removeEventListener('mouseup', requestedEvents.mouseup); + this._document!.removeEventListener('mouseup', requestedEvents.mouseup!); requestedEvents.mouseup = null; } else if (!requestedEvents.mouseup) { requestedEvents.mouseup = eventListeners.mouseup; } if (!(events & CoreMouseEventType.DRAG)) { - this._document.removeEventListener('mousemove', requestedEvents.mousedrag); + this._document!.removeEventListener('mousemove', requestedEvents.mousedrag!); requestedEvents.mousedrag = null; } else if (!requestedEvents.mousedrag) { requestedEvents.mousedrag = eventListeners.mousedrag; @@ -710,7 +705,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // Don't send the mouse button to the pty if mouse events are disabled or // if the selection manager is having selection forced (ie. a modifier is // held). - if (!this._coreMouseService.areMouseEventsActive || this._selectionService.shouldForceSelection(ev)) { + if (!this._coreMouseService.areMouseEventsActive || this._selectionService!.shouldForceSelection(ev)) { return; } @@ -721,10 +716,10 @@ export class Terminal extends CoreTerminal implements ITerminal { // Note: Other emulators also do this for 'mousedown' while a button // is held, we currently limit 'mousedown' to the terminal only. if (requestedEvents.mouseup) { - this._document.addEventListener('mouseup', requestedEvents.mouseup); + this._document!.addEventListener('mouseup', requestedEvents.mouseup); } if (requestedEvents.mousedrag) { - this._document.addEventListener('mousemove', requestedEvents.mousedrag); + this._document!.addEventListener('mousemove', requestedEvents.mousedrag); } return this.cancel(ev); @@ -735,7 +730,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // Convert wheel events into up/down events when the buffer does not have scrollback, this // enables scrolling in apps hosted in the alt buffer such as vim or tmux. if (!this.buffer.hasScrollback) { - const amount = this.viewport.getLinesScrolled(ev); + const amount = this.viewport!.getLinesScrolled(ev); // Do nothing if there's no vertical scroll if (amount === 0) { @@ -758,20 +753,20 @@ export class Terminal extends CoreTerminal implements ITerminal { // the shell for example this.register(addDisposableDomListener(el, 'wheel', (ev: WheelEvent) => { if (requestedEvents.wheel) return; - if (!this.viewport.onWheel(ev)) { + if (!this.viewport!.onWheel(ev)) { return this.cancel(ev); } })); this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => { if (this._coreMouseService.areMouseEventsActive) return; - this.viewport.onTouchStart(ev); + this.viewport!.onTouchStart(ev); return this.cancel(ev); })); this.register(addDisposableDomListener(el, 'touchmove', (ev: TouchEvent) => { if (this._coreMouseService.areMouseEventsActive) return; - if (!this.viewport.onTouchMove(ev)) { + if (!this.viewport!.onTouchMove(ev)) { return this.cancel(ev); } })); @@ -802,9 +797,9 @@ export class Terminal extends CoreTerminal implements ITerminal { */ public updateCursorStyle(ev: KeyboardEvent): void { if (this._selectionService && this._selectionService.shouldColumnSelect(ev)) { - this.element.classList.add('column-select'); + this.element!.classList.add('column-select'); } else { - this.element.classList.remove('column-select'); + this.element!.classList.remove('column-select'); } } @@ -824,7 +819,7 @@ export class Terminal extends CoreTerminal implements ITerminal { } public paste(data: string): void { - paste(data, this.textarea, this._coreService); + paste(data, this.textarea!, this._coreService); } /** @@ -871,13 +866,13 @@ export class Terminal extends CoreTerminal implements ITerminal { } public registerCharacterJoiner(handler: CharacterJoinerHandler): number { - const joinerId = this._renderService.registerCharacterJoiner(handler); + const joinerId = this._renderService!.registerCharacterJoiner(handler); this.refresh(0, this.rows - 1); return joinerId; } public deregisterCharacterJoiner(joinerId: number): void { - if (this._renderService.deregisterCharacterJoiner(joinerId)) { + if (this._renderService!.deregisterCharacterJoiner(joinerId)) { this.refresh(0, this.rows - 1); } } @@ -886,7 +881,7 @@ export class Terminal extends CoreTerminal implements ITerminal { return this.buffer.markers; } - public addMarker(cursorYOffset: number): IMarker { + public addMarker(cursorYOffset: number): IMarker | undefined { // Disallow markers on the alt buffer if (this.buffer !== this.buffers.normal) { return; @@ -909,7 +904,7 @@ export class Terminal extends CoreTerminal implements ITerminal { * @param length The length of the selection. */ public select(column: number, row: number, length: number): void { - this._selectionService.setSelection(column, row, length); + this._selectionService!.setSelection(column, row, length); } /** @@ -921,15 +916,15 @@ export class Terminal extends CoreTerminal implements ITerminal { } public getSelectionPosition(): ISelectionPosition | undefined { - if (!this._selectionService.hasSelection) { + if (!this._selectionService || !this._selectionService.hasSelection) { return undefined; } return { - startColumn: this._selectionService.selectionStart[0], - startRow: this._selectionService.selectionStart[1], - endColumn: this._selectionService.selectionEnd[0], - endRow: this._selectionService.selectionEnd[1] + startColumn: this._selectionService.selectionStart![0], + startRow: this._selectionService.selectionStart![1], + endColumn: this._selectionService.selectionEnd![0], + endRow: this._selectionService.selectionEnd![1] }; } @@ -957,14 +952,14 @@ export class Terminal extends CoreTerminal implements ITerminal { * - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent * @param ev The keydown event to be handled. */ - protected _keyDown(event: KeyboardEvent): boolean { + protected _keyDown(event: KeyboardEvent): boolean | undefined { this._keyDownHandled = false; if (this._customKeyEventHandler && this._customKeyEventHandler(event) === false) { return false; } - if (!this._compositionHelper.keydown(event)) { + if (!this._compositionHelper!.keydown(event)) { if (this.buffer.ybase !== this.buffer.ydisp) { this.scrollToBottom(); } @@ -1002,7 +997,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // will announce deleted characters. This will not work 100% of the time but it should cover // most scenarios. if (result.key === C0.ETX || result.key === C0.CR) { - this.textarea.value = ''; + this.textarea!.value = ''; } this._onKey.fire({ key: result.key, domEvent: event }); @@ -1095,16 +1090,16 @@ export class Terminal extends CoreTerminal implements ITerminal { */ public bell(): void { if (this._soundBell()) { - this._soundService.playBellSound(); + this._soundService!.playBellSound(); } - if (this._visualBell()) { - this.element.classList.add('visual-bell-active'); - clearTimeout(this._visualBellTimer); - this._visualBellTimer = window.setTimeout(() => { - this.element.classList.remove('visual-bell-active'); - }, 200); - } + // if (this._visualBell()) { + // this.element.classList.add('visual-bell-active'); + // clearTimeout(this._visualBellTimer); + // this._visualBellTimer = window.setTimeout(() => { + // this.element.classList.remove('visual-bell-active'); + // }, 200); + // } } /** @@ -1141,7 +1136,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // Don't clear if it's already clear return; } - this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)); + this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)!); this.buffer.lines.length = 1; this.buffer.ydisp = 0; this.buffer.ybase = 0; @@ -1202,7 +1197,7 @@ export class Terminal extends CoreTerminal implements ITerminal { } // TODO: Remove cancel function and cancelEvents option - public cancel(ev: Event, force?: boolean): boolean { + public cancel(ev: Event, force?: boolean): boolean | undefined { if (!this.options.cancelEvents && !force) { return; } diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index 847d64e57..76aa0c8cf 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -8,14 +8,15 @@ import { IEvent } from 'common/EventEmitter'; import { ICoreTerminal, CharData, ITerminalOptions } from 'common/Types'; import { IMouseService, IRenderService } from './services/Services'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; +import { IFunctionIdentifier, IParams } from 'common/parser/Types'; export interface ITerminal extends IPublicTerminal, ICoreTerminal { element: HTMLElement | undefined; - screenElement: HTMLElement; + screenElement: HTMLElement | undefined; browser: IBrowser; buffer: IBuffer; buffers: IBufferSet; - viewport: IViewport; + viewport: IViewport | undefined; // TODO: We should remove options once components adopt optionsService options: ITerminalOptions; linkifier: ILinkifier; @@ -51,16 +52,16 @@ export interface IPublicTerminal extends IDisposable { resize(columns: number, rows: number): void; open(parent: HTMLElement): void; attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; - // addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; - // addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable; - // addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable; - // addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; + addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; + addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable; + addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable; + addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number; deregisterLinkMatcher(matcherId: number): void; registerLinkProvider(linkProvider: ILinkProvider): IDisposable; registerCharacterJoiner(handler: (text: string) => [number, number][]): number; deregisterCharacterJoiner(joinerId: number): void; - addMarker(cursorYOffset: number): IMarker; + addMarker(cursorYOffset: number): IMarker | undefined; hasSelection(): boolean; getSelection(): string; getSelectionPosition(): ISelectionPosition | undefined; diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index a0ca25d2e..d6b305244 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -10,7 +10,7 @@ import { Disposable } from 'common/Lifecycle'; import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; import { addDisposableDomListener } from 'browser/Lifecycle'; import { IColorSet } from 'browser/Types'; -import { IOptionsService, IBufferService, ICoreService } from 'common/services/Services'; +import { IOptionsService, IBufferService } from 'common/services/Services'; import { ICharSizeService, IRenderService } from 'browser/services/Services'; interface ISelectionState { diff --git a/src/public/Terminal.ts b/src/public/Terminal.ts index d9b951ef4..3d4838149 100644 --- a/src/public/Terminal.ts +++ b/src/public/Terminal.ts @@ -4,7 +4,7 @@ */ import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, IParser, IFunctionIdentifier, ILinkProvider, IUnicodeHandling, IUnicodeVersionProvider } from 'xterm'; -import { ITerminal } from '../Types'; +import { ITerminal } from 'browser/Types'; import { IBufferLine, ICellData } from 'common/Types'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { CellData } from 'common/buffer/CellData'; diff --git a/test/benchmark/Terminal.benchmark.ts b/test/benchmark/Terminal.benchmark.ts index 71a36cc70..76139cb64 100644 --- a/test/benchmark/Terminal.benchmark.ts +++ b/test/benchmark/Terminal.benchmark.ts @@ -7,7 +7,7 @@ import { perfContext, before, ThroughputRuntimeCase } from 'xterm-benchmark'; import { spawn } from 'node-pty'; import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder'; -import { Terminal } from 'Terminal'; +import { Terminal } from 'browser/Terminal'; perfContext('Terminal: ls -lR /usr/lib', () => { let content = ''; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 3487c4104..35f43b1b0 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -805,7 +805,7 @@ declare module 'xterm' { /** * @deprecated use `registerMarker` instead. */ - addMarker(cursorYOffset: number): IMarker; + addMarker(cursorYOffset: number): IMarker | undefined; /** * Gets whether the terminal has an active selection. From 03bfd2c842d9947544e19a35e3622ff6771033fc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 10:59:32 -0700 Subject: [PATCH 08/10] Move Terminal*.test into browser --- bin/test.js | 1 - src/TestUtils.test.ts | 326 ---------------------------- src/{ => browser}/Terminal.test.ts | 288 ++++++++++++------------ src/{ => browser}/Terminal2.test.ts | 6 +- src/browser/TestUtils.test.ts | 324 ++++++++++++++++++++++++++- 5 files changed, 468 insertions(+), 477 deletions(-) delete mode 100644 src/TestUtils.test.ts rename src/{ => browser}/Terminal.test.ts (80%) rename src/{ => browser}/Terminal2.test.ts (96%) diff --git a/bin/test.js b/bin/test.js index 1380a5122..b9725acda 100644 --- a/bin/test.js +++ b/bin/test.js @@ -13,7 +13,6 @@ const env = { ...process.env }; env.NODE_PATH = path.resolve(__dirname, '../out'); let testFiles = [ - './out/*test.js', './out/**/*test.js', './addons/**/out/*test.js', ]; diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts deleted file mode 100644 index 102a53537..000000000 --- a/src/TestUtils.test.ts +++ /dev/null @@ -1,326 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderer, IRenderDimensions, CharacterJoinerHandler, IRequestRedrawEvent } from 'browser/renderer/Types'; -import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; -import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, ITerminalOptions } from 'common/Types'; -import { Buffer } from 'common/buffer/Buffer'; -import * as Browser from 'common/Platform'; -import { IDisposable, IMarker, IEvent, ISelectionPosition, ILinkProvider } from 'xterm'; -import { Terminal } from './browser/Terminal'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { IColorManager, IColorSet, ILinkMatcherOptions, ILinkifier, IViewport, ILinkifier2, ICompositionHelper, ITerminal, IBrowser } from 'browser/Types'; -import { IOptionsService, IUnicodeService } from 'common/services/Services'; -import { IParams, IFunctionIdentifier } from 'common/parser/Types'; -import { ISelectionService } from 'browser/services/Services'; - -export class TestTerminal extends Terminal { - public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; } - public keyDown(ev: any): boolean { return this._keyDown(ev); } - public keyPress(ev: any): boolean { return this._keyPress(ev); } -} - -export class MockTerminal implements ITerminal { - public onBlur: IEvent; - public onFocus: IEvent; - public onA11yChar: IEvent; - public onA11yTab: IEvent; - public onCursorMove: IEvent; - public onLineFeed: IEvent; - public onSelectionChange: IEvent; - public onData: IEvent; - public onBinary: IEvent; - public onTitleChange: IEvent; - public onScroll: IEvent; - public onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>; - public onRender: IEvent<{ start: number, end: number }>; - public onResize: IEvent<{ cols: number, rows: number }>; - public markers: IMarker[]; - public optionsService: IOptionsService; - public unicodeService: IUnicodeService; - public addMarker(cursorYOffset: number): IMarker { - throw new Error('Method not implemented.'); - } - public selectLines(start: number, end: number): void { - throw new Error('Method not implemented.'); - } - public scrollToLine(line: number): void { - throw new Error('Method not implemented.'); - } - public static string: any; - public setOption(key: any, value: any): void { - throw new Error('Method not implemented.'); - } - public blur(): void { - throw new Error('Method not implemented.'); - } - public focus(): void { - throw new Error('Method not implemented.'); - } - public resize(columns: number, rows: number): void { - throw new Error('Method not implemented.'); - } - public writeln(data: string): void { - throw new Error('Method not implemented.'); - } - public paste(data: string): void { - throw new Error('Method not implemented.'); - } - public open(parent: HTMLElement): void { - throw new Error('Method not implemented.'); - } - public attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void { - throw new Error('Method not implemented.'); - } - public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable { - throw new Error('Method not implemented.'); - } - public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable { - throw new Error('Method not implemented.'); - } - public addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable { - throw new Error('Method not implemented.'); - } - public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable { - throw new Error('Method not implemented.'); - } - public registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => boolean | void, options?: ILinkMatcherOptions): number { - throw new Error('Method not implemented.'); - } - public deregisterLinkMatcher(matcherId: number): void { - throw new Error('Method not implemented.'); - } - public registerLinkProvider(linkProvider: ILinkProvider): IDisposable { - throw new Error('Method not implemented.'); - } - public hasSelection(): boolean { - throw new Error('Method not implemented.'); - } - public getSelection(): string { - throw new Error('Method not implemented.'); - } - public getSelectionPosition(): ISelectionPosition | undefined { - throw new Error('Method not implemented.'); - } - public clearSelection(): void { - throw new Error('Method not implemented.'); - } - public select(column: number, row: number, length: number): void { - throw new Error('Method not implemented.'); - } - public selectAll(): void { - throw new Error('Method not implemented.'); - } - public dispose(): void { - throw new Error('Method not implemented.'); - } - public scrollPages(pageCount: number): void { - throw new Error('Method not implemented.'); - } - public scrollToTop(): void { - throw new Error('Method not implemented.'); - } - public scrollToBottom(): void { - throw new Error('Method not implemented.'); - } - public clear(): void { - throw new Error('Method not implemented.'); - } - public write(data: string): void { - throw new Error('Method not implemented.'); - } - public writeUtf8(data: Uint8Array): void { - throw new Error('Method not implemented.'); - } - public bracketedPasteMode: boolean; - public renderer: IRenderer; - public linkifier: ILinkifier; - public linkifier2: ILinkifier2; - public isFocused: boolean; - public options: ITerminalOptions = {}; - public element: HTMLElement; - public screenElement: HTMLElement; - public rowContainer: HTMLElement; - public selectionContainer: HTMLElement; - public selectionService: ISelectionService; - public textarea: HTMLTextAreaElement; - public rows: number; - public cols: number; - public browser: IBrowser = Browser; - public writeBuffer: string[]; - public children: HTMLElement[]; - public cursorHidden: boolean; - public cursorState: number; - public scrollback: number; - public buffers: IBufferSet; - public buffer: IBuffer; - public viewport: IViewport; - public applicationCursor: boolean; - public handler(data: string): void { - throw new Error('Method not implemented.'); - } - public on(event: string, callback: (...args: any[]) => void): void { - throw new Error('Method not implemented.'); - } - public off(type: string, listener: XtermListener): void { - throw new Error('Method not implemented.'); - } - public addDisposableListener(type: string, handler: XtermListener): IDisposable { - throw new Error('Method not implemented.'); - } - public scrollLines(disp: number): void { - throw new Error('Method not implemented.'); - } - public scrollToRow(absoluteRow: number): number { - throw new Error('Method not implemented.'); - } - public cancel(ev: Event, force?: boolean): void { - throw new Error('Method not implemented.'); - } - public log(text: string): void { - throw new Error('Method not implemented.'); - } - public emit(event: string, data: any): void { - throw new Error('Method not implemented.'); - } - public reset(): void { - throw new Error('Method not implemented.'); - } - public refresh(start: number, end: number): void { - throw new Error('Method not implemented.'); - } - public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } - public deregisterCharacterJoiner(joinerId: number): void { } -} - -export class MockBuffer implements IBuffer { - public markers: IMarker[]; - public addMarker(y: number): IMarker { - throw new Error('Method not implemented.'); - } - public isCursorInViewport: boolean; - public lines: ICircularList; - public ydisp: number; - public ybase: number; - public hasScrollback: boolean; - public y: number; - public x: number; - public tabs: any; - public scrollBottom: number; - public scrollTop: number; - public savedY: number; - public savedX: number; - public savedCharset: ICharset | null; - public savedCurAttrData = new AttributeData(); - public translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string { - return Buffer.prototype.translateBufferLineToString.apply(this, arguments); - } - public getWrappedRangeForLine(y: number): { first: number, last: number } { - return Buffer.prototype.getWrappedRangeForLine.apply(this, arguments); - } - public nextStop(x?: number): number { - throw new Error('Method not implemented.'); - } - public prevStop(x?: number): number { - throw new Error('Method not implemented.'); - } - public setLines(lines: ICircularList): void { - this.lines = lines; - } - public getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine { - return Buffer.prototype.getBlankLine.apply(this, arguments); - } - public stringIndexToBufferIndex(lineIndex: number, stringIndex: number): number[] { - return Buffer.prototype.stringIndexToBufferIndex.apply(this, arguments); - } - public iterator(trimRight: boolean, startIndex?: number, endIndex?: number): IBufferStringIterator { - return Buffer.prototype.iterator.apply(this, arguments); - } - public getNullCell(attr?: IAttributeData): ICellData { - throw new Error('Method not implemented.'); - } - public getWhitespaceCell(attr?: IAttributeData): ICellData { - throw new Error('Method not implemented.'); - } -} - -export class MockRenderer implements IRenderer { - public onRequestRedraw: IEvent; - public onCanvasResize: IEvent<{ width: number, height: number }>; - public onRender: IEvent<{ start: number, end: number }>; - public dispose(): void { - throw new Error('Method not implemented.'); - } - public colorManager: IColorManager; - public on(type: string, listener: XtermListener): void { - throw new Error('Method not implemented.'); - } - public off(type: string, listener: XtermListener): void { - throw new Error('Method not implemented.'); - } - public emit(type: string, data?: any): void { - throw new Error('Method not implemented.'); - } - public addDisposableListener(type: string, handler: XtermListener): IDisposable { - throw new Error('Method not implemented.'); - } - public dimensions: IRenderDimensions; - public setColors(colors: IColorSet): void { - throw new Error('Method not implemented.'); - } - public onResize(cols: number, rows: number): void { } - public onCharSizeChanged(): void { } - public onBlur(): void { } - public onFocus(): void { } - public onSelectionChanged(start: [number, number], end: [number, number]): void { } - public onCursorMove(): void { } - public onOptionsChanged(): void { } - public onDevicePixelRatioChange(): void { } - public clear(): void { } - public renderRows(start: number, end: number): void { } - public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } - public deregisterCharacterJoiner(): boolean { return true; } -} - -export class MockViewport implements IViewport { - public dispose(): void { - throw new Error('Method not implemented.'); - } - public scrollBarWidth: number = 0; - public onThemeChange(colors: IColorSet): void { - throw new Error('Method not implemented.'); - } - public onWheel(ev: WheelEvent): boolean { - throw new Error('Method not implemented.'); - } - public onTouchStart(ev: TouchEvent): void { - throw new Error('Method not implemented.'); - } - public onTouchMove(ev: TouchEvent): boolean { - throw new Error('Method not implemented.'); - } - public syncScrollArea(): void { } - public getLinesScrolled(ev: WheelEvent): number { - throw new Error('Method not implemented.'); - } -} - -export class MockCompositionHelper implements ICompositionHelper { - public compositionstart(): void { - throw new Error('Method not implemented.'); - } - public compositionupdate(ev: CompositionEvent): void { - throw new Error('Method not implemented.'); - } - public compositionend(): void { - throw new Error('Method not implemented.'); - } - public updateCompositionElements(dontRecurse?: boolean): void { - throw new Error('Method not implemented.'); - } - public keydown(ev: KeyboardEvent): boolean { - return true; - } -} diff --git a/src/Terminal.test.ts b/src/browser/Terminal.test.ts similarity index 80% rename from src/Terminal.test.ts rename to src/browser/Terminal.test.ts index 6488aa43f..729c0d0f2 100644 --- a/src/Terminal.test.ts +++ b/src/browser/Terminal.test.ts @@ -4,7 +4,7 @@ */ import { assert, expect } from 'chai'; -import { MockViewport, MockCompositionHelper, MockRenderer, TestTerminal } from './TestUtils.test'; +import { MockViewport, MockCompositionHelper, MockRenderer, TestTerminal } from 'browser/TestUtils.test'; import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { CellData } from 'common/buffer/CellData'; import { IBufferService, IUnicodeService } from 'common/services/Services'; @@ -395,62 +395,62 @@ describe('Terminal', () => { describe('scroll() function', () => { describe('when scrollback > 0', () => { it('should create a new line and scroll', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(INIT_ROWS - 1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(INIT_ROWS - 1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS + 1); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); - assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).getChars(), 'b'); - assert.equal(term.buffer.lines.get(INIT_ROWS).loadCell(0, new CellData()).getChars(), ''); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'a'); + assert.equal(term.buffer.lines.get(INIT_ROWS - 1)!.loadCell(0, new CellData()).getChars(), 'b'); + assert.equal(term.buffer.lines.get(INIT_ROWS)!.loadCell(0, new CellData()).getChars(), ''); }); it('should properly scroll inside a scroll region (scrollTop set)', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(2)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c'); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'a'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), 'c'); }); it('should properly scroll inside a scroll region (scrollBottom set)', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); - term.buffer.lines.get(3).setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); - term.buffer.lines.get(4).setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(2)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(3)!.setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); + term.buffer.lines.get(4)!.setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); term.buffer.y = 3; term.buffer.scrollBottom = 3; term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS + 1); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a', '\'a\' should be pushed to the scrollback'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'b'); - assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'c'); - assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), 'd'); - assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); - assert.equal(term.buffer.lines.get(5).loadCell(0, new CellData()).getChars(), 'e'); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'a', '\'a\' should be pushed to the scrollback'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), 'b'); + assert.equal(term.buffer.lines.get(2)!.loadCell(0, new CellData()).getChars(), 'c'); + assert.equal(term.buffer.lines.get(3)!.loadCell(0, new CellData()).getChars(), 'd'); + assert.equal(term.buffer.lines.get(4)!.loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); + assert.equal(term.buffer.lines.get(5)!.loadCell(0, new CellData()).getChars(), 'e'); }); it('should properly scroll inside a scroll region (scrollTop and scrollBottom set)', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); - term.buffer.lines.get(3).setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); - term.buffer.lines.get(4).setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(2)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(3)!.setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); + term.buffer.lines.get(4)!.setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; term.buffer.scrollBottom = 3; term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer'); - assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'd'); - assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); - assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), 'e'); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'a'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer'); + assert.equal(term.buffer.lines.get(2)!.loadCell(0, new CellData()).getChars(), 'd'); + assert.equal(term.buffer.lines.get(3)!.loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); + assert.equal(term.buffer.lines.get(4)!.loadCell(0, new CellData()).getChars(), 'e'); }); }); @@ -461,65 +461,65 @@ describe('Terminal', () => { }); it('should create a new line and shift everything up', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(INIT_ROWS - 1).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(INIT_ROWS - 1)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line assert.equal(term.buffer.lines.length, INIT_ROWS); term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); // 'a' gets pushed out of buffer - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'b'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), ''); - assert.equal(term.buffer.lines.get(INIT_ROWS - 2).loadCell(0, new CellData()).getChars(), 'c'); - assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).getChars(), ''); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'b'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), ''); + assert.equal(term.buffer.lines.get(INIT_ROWS - 2)!.loadCell(0, new CellData()).getChars(), 'c'); + assert.equal(term.buffer.lines.get(INIT_ROWS - 1)!.loadCell(0, new CellData()).getChars(), ''); }); it('should properly scroll inside a scroll region (scrollTop set)', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(2)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c'); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'a'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), 'c'); }); it('should properly scroll inside a scroll region (scrollBottom set)', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); - term.buffer.lines.get(3).setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); - term.buffer.lines.get(4).setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(2)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(3)!.setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); + term.buffer.lines.get(4)!.setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); term.buffer.y = 3; term.buffer.scrollBottom = 3; term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'b'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c'); - assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'd'); - assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); - assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), 'e'); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'b'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), 'c'); + assert.equal(term.buffer.lines.get(2)!.loadCell(0, new CellData()).getChars(), 'd'); + assert.equal(term.buffer.lines.get(3)!.loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); + assert.equal(term.buffer.lines.get(4)!.loadCell(0, new CellData()).getChars(), 'e'); }); it('should properly scroll inside a scroll region (scrollTop and scrollBottom set)', () => { - term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); - term.buffer.lines.get(1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); - term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); - term.buffer.lines.get(3).setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); - term.buffer.lines.get(4).setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); + term.buffer.lines.get(0)!.setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); + term.buffer.lines.get(1)!.setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); + term.buffer.lines.get(2)!.setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); + term.buffer.lines.get(3)!.setCell(0, CellData.fromCharData([0, 'd', 0, 'd'.charCodeAt(0)])); + term.buffer.lines.get(4)!.setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; term.buffer.scrollBottom = 3; term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); - assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); - assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer'); - assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'd'); - assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); - assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), 'e'); + assert.equal(term.buffer.lines.get(0)!.loadCell(0, new CellData()).getChars(), 'a'); + assert.equal(term.buffer.lines.get(1)!.loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer'); + assert.equal(term.buffer.lines.get(2)!.loadCell(0, new CellData()).getChars(), 'd'); + assert.equal(term.buffer.lines.get(3)!.loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index'); + assert.equal(term.buffer.lines.get(4)!.loadCell(0, new CellData()).getChars(), 'e'); }); }); }); @@ -722,11 +722,11 @@ describe('Terminal', () => { const cell = new CellData(); for (let i = 0xDC00; i <= 0xDCFF; ++i) { term.writeSync(high + String.fromCharCode(i)); - const tchar = term.buffer.lines.get(0).loadCell(0, cell); + const tchar = term.buffer.lines.get(0)!.loadCell(0, cell); expect(tchar.getChars()).eql(high + String.fromCharCode(i)); expect(tchar.getChars().length).eql(2); expect(tchar.getWidth()).eql(1); - expect(term.buffer.lines.get(0).loadCell(1, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(1, cell).getChars()).eql(''); term.reset(); } }); @@ -736,9 +736,9 @@ describe('Terminal', () => { for (let i = 0xDC00; i <= 0xDCFF; ++i) { term.buffer.x = term.cols - 1; term.writeSync(high + String.fromCharCode(i)); - expect(term.buffer.lines.get(0).loadCell(term.buffer.x - 1, cell).getChars()).eql(high + String.fromCharCode(i)); - expect(term.buffer.lines.get(0).loadCell(term.buffer.x - 1, cell).getChars().length).eql(2); - expect(term.buffer.lines.get(1).loadCell(0, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars()).eql(high + String.fromCharCode(i)); + expect(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars().length).eql(2); + expect(term.buffer.lines.get(1)!.loadCell(0, cell).getChars()).eql(''); term.reset(); } }); @@ -749,10 +749,10 @@ describe('Terminal', () => { term.buffer.x = term.cols - 1; term.writeSync('a' + high + String.fromCharCode(i)); - expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).getChars()).eql('a'); - expect(term.buffer.lines.get(1).loadCell(0, cell).getChars()).eql(high + String.fromCharCode(i)); - expect(term.buffer.lines.get(1).loadCell(0, cell).getChars().length).eql(2); - expect(term.buffer.lines.get(1).loadCell(1, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars()).eql('a'); + expect(term.buffer.lines.get(1)!.loadCell(0, cell).getChars()).eql(high + String.fromCharCode(i)); + expect(term.buffer.lines.get(1)!.loadCell(0, cell).getChars().length).eql(2); + expect(term.buffer.lines.get(1)!.loadCell(1, cell).getChars()).eql(''); term.reset(); } }); @@ -768,9 +768,9 @@ describe('Terminal', () => { } term.writeSync('a' + high + String.fromCharCode(i)); // auto wraparound mode should cut off the rest of the line - expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).getChars()).eql(high + String.fromCharCode(i)); - expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).getChars().length).eql(2); - expect(term.buffer.lines.get(1).loadCell(1, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars()).eql(high + String.fromCharCode(i)); + expect(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars().length).eql(2); + expect(term.buffer.lines.get(1)!.loadCell(1, cell).getChars()).eql(''); term.reset(); } }); @@ -780,11 +780,11 @@ describe('Terminal', () => { for (let i = 0xDC00; i <= 0xDCFF; ++i) { term.writeSync(high); term.writeSync(String.fromCharCode(i)); - const tchar = term.buffer.lines.get(0).loadCell(0, cell); + const tchar = term.buffer.lines.get(0)!.loadCell(0, cell); expect(tchar.getChars()).eql(high + String.fromCharCode(i)); expect(tchar.getChars().length).eql(2); expect(tchar.getWidth()).eql(1); - expect(term.buffer.lines.get(0).loadCell(1, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(1, cell).getChars()).eql(''); term.reset(); } }); @@ -794,7 +794,7 @@ describe('Terminal', () => { const cell = new CellData(); it('café', () => { term.writeSync('cafe\u0301'); - term.buffer.lines.get(0).loadCell(3, cell); + term.buffer.lines.get(0)!.loadCell(3, cell); expect(cell.getChars()).eql('e\u0301'); expect(cell.getChars().length).eql(2); expect(cell.getWidth()).eql(1); @@ -802,11 +802,11 @@ describe('Terminal', () => { it('café - end of line', () => { term.buffer.x = term.cols - 1 - 3; term.writeSync('cafe\u0301'); - term.buffer.lines.get(0).loadCell(term.cols - 1, cell); + term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell); expect(cell.getChars()).eql('e\u0301'); expect(cell.getChars().length).eql(2); expect(cell.getWidth()).eql(1); - term.buffer.lines.get(0).loadCell(1, cell); + term.buffer.lines.get(0)!.loadCell(1, cell); expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); expect(cell.getWidth()).eql(1); @@ -814,12 +814,12 @@ describe('Terminal', () => { it('multiple combined é', () => { term.writeSync(Array(100).join('e\u0301')); for (let i = 0; i < term.cols; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); expect(cell.getChars()).eql('e\u0301'); expect(cell.getChars().length).eql(2); expect(cell.getWidth()).eql(1); } - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('e\u0301'); expect(cell.getChars().length).eql(2); expect(cell.getWidth()).eql(1); @@ -827,12 +827,12 @@ describe('Terminal', () => { it('multiple surrogate with combined', () => { term.writeSync(Array(100).join('\uD800\uDC00\u0301')); for (let i = 0; i < term.cols; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); expect(cell.getChars()).eql('\uD800\uDC00\u0301'); expect(cell.getChars().length).eql(3); expect(cell.getWidth()).eql(1); } - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('\uD800\uDC00\u0301'); expect(cell.getChars().length).eql(3); expect(cell.getWidth()).eql(1); @@ -855,7 +855,7 @@ describe('Terminal', () => { it('line of ¥ even', () => { term.writeSync(Array(50).join('¥')); for (let i = 0; i < term.cols; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); if (i % 2) { expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); @@ -866,7 +866,7 @@ describe('Terminal', () => { expect(cell.getWidth()).eql(2); } } - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('¥'); expect(cell.getChars().length).eql(1); expect(cell.getWidth()).eql(2); @@ -875,7 +875,7 @@ describe('Terminal', () => { term.buffer.x = 1; term.writeSync(Array(50).join('¥')); for (let i = 1; i < term.cols - 1; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); if (!(i % 2)) { expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); @@ -886,11 +886,11 @@ describe('Terminal', () => { expect(cell.getWidth()).eql(2); } } - term.buffer.lines.get(0).loadCell(term.cols - 1, cell); + term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell); expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); expect(cell.getWidth()).eql(1); - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('¥'); expect(cell.getChars().length).eql(1); expect(cell.getWidth()).eql(2); @@ -899,7 +899,7 @@ describe('Terminal', () => { term.buffer.x = 1; term.writeSync(Array(50).join('¥\u0301')); for (let i = 1; i < term.cols - 1; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); if (!(i % 2)) { expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); @@ -910,11 +910,11 @@ describe('Terminal', () => { expect(cell.getWidth()).eql(2); } } - term.buffer.lines.get(0).loadCell(term.cols - 1, cell); + term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell); expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); expect(cell.getWidth()).eql(1); - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('¥\u0301'); expect(cell.getChars().length).eql(2); expect(cell.getWidth()).eql(2); @@ -922,7 +922,7 @@ describe('Terminal', () => { it('line of ¥ with combining even', () => { term.writeSync(Array(50).join('¥\u0301')); for (let i = 0; i < term.cols; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); if (i % 2) { expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); @@ -933,7 +933,7 @@ describe('Terminal', () => { expect(cell.getWidth()).eql(2); } } - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('¥\u0301'); expect(cell.getChars().length).eql(2); expect(cell.getWidth()).eql(2); @@ -942,7 +942,7 @@ describe('Terminal', () => { term.buffer.x = 1; term.writeSync(Array(50).join('\ud843\ude6d\u0301')); for (let i = 1; i < term.cols - 1; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); if (!(i % 2)) { expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); @@ -953,11 +953,11 @@ describe('Terminal', () => { expect(cell.getWidth()).eql(2); } } - term.buffer.lines.get(0).loadCell(term.cols - 1, cell); + term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell); expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); expect(cell.getWidth()).eql(1); - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('\ud843\ude6d\u0301'); expect(cell.getChars().length).eql(3); expect(cell.getWidth()).eql(2); @@ -965,7 +965,7 @@ describe('Terminal', () => { it('line of surrogate fullwidth with combining even', () => { term.writeSync(Array(50).join('\ud843\ude6d\u0301')); for (let i = 0; i < term.cols; ++i) { - term.buffer.lines.get(0).loadCell(i, cell); + term.buffer.lines.get(0)!.loadCell(i, cell); if (i % 2) { expect(cell.getChars()).eql(''); expect(cell.getChars().length).eql(0); @@ -976,7 +976,7 @@ describe('Terminal', () => { expect(cell.getWidth()).eql(2); } } - term.buffer.lines.get(1).loadCell(0, cell); + term.buffer.lines.get(1)!.loadCell(0, cell); expect(cell.getChars()).eql('\ud843\ude6d\u0301'); expect(cell.getChars().length).eql(3); expect(cell.getWidth()).eql(2); @@ -991,11 +991,11 @@ describe('Terminal', () => { term.buffer.y = 0; term.write('\x1b[4h'); term.writeSync('abcde'); - expect(term.buffer.lines.get(0).length).eql(term.cols); - expect(term.buffer.lines.get(0).loadCell(10, cell).getChars()).eql('a'); - expect(term.buffer.lines.get(0).loadCell(14, cell).getChars()).eql('e'); - expect(term.buffer.lines.get(0).loadCell(15, cell).getChars()).eql('0'); - expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql('4'); + expect(term.buffer.lines.get(0)!.length).eql(term.cols); + expect(term.buffer.lines.get(0)!.loadCell(10, cell).getChars()).eql('a'); + expect(term.buffer.lines.get(0)!.loadCell(14, cell).getChars()).eql('e'); + expect(term.buffer.lines.get(0)!.loadCell(15, cell).getChars()).eql('0'); + expect(term.buffer.lines.get(0)!.loadCell(79, cell).getChars()).eql('4'); }); it('fullwidth - insert', () => { term.writeSync(Array(9).join('0123456789').slice(-80)); @@ -1003,12 +1003,12 @@ describe('Terminal', () => { term.buffer.y = 0; term.write('\x1b[4h'); term.writeSync('¥¥¥'); - expect(term.buffer.lines.get(0).length).eql(term.cols); - expect(term.buffer.lines.get(0).loadCell(10, cell).getChars()).eql('¥'); - expect(term.buffer.lines.get(0).loadCell(11, cell).getChars()).eql(''); - expect(term.buffer.lines.get(0).loadCell(14, cell).getChars()).eql('¥'); - expect(term.buffer.lines.get(0).loadCell(15, cell).getChars()).eql(''); - expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql('3'); + expect(term.buffer.lines.get(0)!.length).eql(term.cols); + expect(term.buffer.lines.get(0)!.loadCell(10, cell).getChars()).eql('¥'); + expect(term.buffer.lines.get(0)!.loadCell(11, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(14, cell).getChars()).eql('¥'); + expect(term.buffer.lines.get(0)!.loadCell(15, cell).getChars()).eql(''); + expect(term.buffer.lines.get(0)!.loadCell(79, cell).getChars()).eql('3'); }); it('fullwidth - right border', () => { term.writeSync(Array(41).join('¥')); @@ -1016,15 +1016,15 @@ describe('Terminal', () => { term.buffer.y = 0; term.write('\x1b[4h'); term.writeSync('a'); - expect(term.buffer.lines.get(0).length).eql(term.cols); - expect(term.buffer.lines.get(0).loadCell(10, cell).getChars()).eql('a'); - expect(term.buffer.lines.get(0).loadCell(11, cell).getChars()).eql('¥'); - expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql(''); // fullwidth char got replaced + expect(term.buffer.lines.get(0)!.length).eql(term.cols); + expect(term.buffer.lines.get(0)!.loadCell(10, cell).getChars()).eql('a'); + expect(term.buffer.lines.get(0)!.loadCell(11, cell).getChars()).eql('¥'); + expect(term.buffer.lines.get(0)!.loadCell(79, cell).getChars()).eql(''); // fullwidth char got replaced term.writeSync('b'); - expect(term.buffer.lines.get(0).length).eql(term.cols); - expect(term.buffer.lines.get(0).loadCell(11, cell).getChars()).eql('b'); - expect(term.buffer.lines.get(0).loadCell(12, cell).getChars()).eql('¥'); - expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql(''); // empty cell after fullwidth + expect(term.buffer.lines.get(0)!.length).eql(term.cols); + expect(term.buffer.lines.get(0)!.loadCell(11, cell).getChars()).eql('b'); + expect(term.buffer.lines.get(0)!.loadCell(12, cell).getChars()).eql('¥'); + expect(term.buffer.lines.get(0)!.loadCell(79, cell).getChars()).eql(''); // empty cell after fullwidth }); }); @@ -1269,9 +1269,9 @@ describe('Terminal', () => { terminal.writeSync(input); const s = terminal.buffer.iterator(true).next().content; assert.equal(input, s); - const stringIndex = s.match(/😃/).index; + const stringIndex = s.match(/😃/)!.index!; const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, stringIndex); - assert(terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).getChars(), '😃'); + assert(terminal.buffer.lines.get(bufferIndex[0])!.loadCell(bufferIndex[1], new CellData()).getChars(), '😃'); }); it('multiline fullwidth chars with offset 1 (currently tests for broken behavior)', () => { @@ -1298,7 +1298,7 @@ describe('Terminal', () => { assert.equal(input, s); for (let i = 0; i < input.length; ++i) { const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i, true); - assert.equal(input[i], terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).getChars()); + assert.equal(input[i], terminal.buffer.lines.get(bufferIndex[0])!.loadCell(bufferIndex[1], new CellData()).getChars()); } }); @@ -1316,7 +1316,7 @@ describe('Terminal', () => { : (i % 3 === 1) ? input.substr(i, 2) : input.substr(i - 1, 2), - terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).getChars()); + terminal.buffer.lines.get(bufferIndex[0])!.loadCell(bufferIndex[1], new CellData()).getChars()); } }); @@ -1370,15 +1370,15 @@ describe('Terminal', () => { const normalTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: false}); normalTerminal.writeSync(data.join('')); - assert.equal(normalTerminal.buffer.lines.get(0).isWrapped, false); - assert.equal(normalTerminal.buffer.lines.get(1).isWrapped, false); - assert.equal(normalTerminal.buffer.lines.get(2).isWrapped, false); + assert.equal(normalTerminal.buffer.lines.get(0)!.isWrapped, false); + assert.equal(normalTerminal.buffer.lines.get(1)!.isWrapped, false); + assert.equal(normalTerminal.buffer.lines.get(2)!.isWrapped, false); const windowsModeTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: true}); windowsModeTerminal.writeSync(data.join('')); - assert.equal(windowsModeTerminal.buffer.lines.get(0).isWrapped, false); - assert.equal(windowsModeTerminal.buffer.lines.get(1).isWrapped, true, 'This line should wrap in Windows mode as the previous line ends in a non-null character'); - assert.equal(windowsModeTerminal.buffer.lines.get(2).isWrapped, false); + assert.equal(windowsModeTerminal.buffer.lines.get(0)!.isWrapped, false); + assert.equal(windowsModeTerminal.buffer.lines.get(1)!.isWrapped, true, 'This line should wrap in Windows mode as the previous line ends in a non-null character'); + assert.equal(windowsModeTerminal.buffer.lines.get(2)!.isWrapped, false); }); it('should mark lines as wrapped when the line ends in a non-null character after a CUP', () => { @@ -1390,39 +1390,39 @@ describe('Terminal', () => { const normalTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: false}); normalTerminal.writeSync(data.join('')); - assert.equal(normalTerminal.buffer.lines.get(0).isWrapped, false); - assert.equal(normalTerminal.buffer.lines.get(1).isWrapped, false); - assert.equal(normalTerminal.buffer.lines.get(2).isWrapped, false); + assert.equal(normalTerminal.buffer.lines.get(0)!.isWrapped, false); + assert.equal(normalTerminal.buffer.lines.get(1)!.isWrapped, false); + assert.equal(normalTerminal.buffer.lines.get(2)!.isWrapped, false); const windowsModeTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: true}); windowsModeTerminal.writeSync(data.join('')); - assert.equal(windowsModeTerminal.buffer.lines.get(0).isWrapped, false); - assert.equal(windowsModeTerminal.buffer.lines.get(1).isWrapped, true, 'This line should wrap in Windows mode as the previous line ends in a non-null character'); - assert.equal(windowsModeTerminal.buffer.lines.get(2).isWrapped, false); + assert.equal(windowsModeTerminal.buffer.lines.get(0)!.isWrapped, false); + assert.equal(windowsModeTerminal.buffer.lines.get(1)!.isWrapped, true, 'This line should wrap in Windows mode as the previous line ends in a non-null character'); + assert.equal(windowsModeTerminal.buffer.lines.get(2)!.isWrapped, false); }); }); it('convertEol setting', function(): void { // not converting const termNotConverting = new TestTerminal({cols: 15, rows: 10}); termNotConverting.writeSync('Hello\nWorld'); - expect(termNotConverting.buffer.lines.get(0).translateToString(false)).equals('Hello '); - expect(termNotConverting.buffer.lines.get(1).translateToString(false)).equals(' World '); - expect(termNotConverting.buffer.lines.get(0).translateToString(true)).equals('Hello'); - expect(termNotConverting.buffer.lines.get(1).translateToString(true)).equals(' World'); + expect(termNotConverting.buffer.lines.get(0)!.translateToString(false)).equals('Hello '); + expect(termNotConverting.buffer.lines.get(1)!.translateToString(false)).equals(' World '); + expect(termNotConverting.buffer.lines.get(0)!.translateToString(true)).equals('Hello'); + expect(termNotConverting.buffer.lines.get(1)!.translateToString(true)).equals(' World'); // converting const termConverting = new TestTerminal({cols: 15, rows: 10, convertEol: true}); termConverting.writeSync('Hello\nWorld'); - expect(termConverting.buffer.lines.get(0).translateToString(false)).equals('Hello '); - expect(termConverting.buffer.lines.get(1).translateToString(false)).equals('World '); - expect(termConverting.buffer.lines.get(0).translateToString(true)).equals('Hello'); - expect(termConverting.buffer.lines.get(1).translateToString(true)).equals('World'); + expect(termConverting.buffer.lines.get(0)!.translateToString(false)).equals('Hello '); + expect(termConverting.buffer.lines.get(1)!.translateToString(false)).equals('World '); + expect(termConverting.buffer.lines.get(0)!.translateToString(true)).equals('Hello'); + expect(termConverting.buffer.lines.get(1)!.translateToString(true)).equals('World'); }); describe('Terminal InputHandler integration', () => { function getLines(term: TestTerminal, limit: number = term.rows): string[] { const res: string[] = []; for (let i = 0; i < limit; ++i) { - res.push(term.buffer.lines.get(i).translateToString(true)); + res.push(term.buffer.lines.get(i)!.translateToString(true)); } return res; } diff --git a/src/Terminal2.test.ts b/src/browser/Terminal2.test.ts similarity index 96% rename from src/Terminal2.test.ts rename to src/browser/Terminal2.test.ts index 720ea6b17..32a47b214 100644 --- a/src/Terminal2.test.ts +++ b/src/browser/Terminal2.test.ts @@ -8,14 +8,14 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; import * as pty from 'node-pty'; -import { Terminal } from './browser/Terminal'; +import { Terminal } from 'browser/Terminal'; import { IDisposable } from 'xterm'; // all test files expect terminal in 80x25 const COLS = 80; const ROWS = 25; -const TESTFILES = glob.sync('**/escape_sequence_files/*.in', { cwd: path.join(__dirname, '..')}); +const TESTFILES = glob.sync('**/escape_sequence_files/*.in', { cwd: path.join(__dirname, '../..')}); const SKIP_FILES = [ 't0084-CBT.in', 't0101-NLM.in', @@ -124,7 +124,7 @@ function terminalToString(term: Terminal): string { let result = ''; let lineText = ''; for (let line = term.buffer.ybase; line < term.buffer.ybase + term.rows; line++) { - lineText = term.buffer.lines.get(line).translateToString(true); + lineText = term.buffer.lines.get(line)!.translateToString(true); // rtrim empty cells as xterm does lineText = lineText.replace(/\s+$/, ''); result += lineText; diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index 1869ab874..2d6f6cbba 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -3,10 +3,328 @@ * @license MIT */ +import { IDisposable, IMarker, ISelectionPosition, ILinkProvider } from 'xterm'; import { IEvent, EventEmitter } from 'common/EventEmitter'; -import { ICharSizeService, IMouseService, IRenderService } from 'browser/services/Services'; -import { IRenderDimensions, IRenderer, CharacterJoinerHandler } from 'browser/renderer/Types'; -import { IColorSet } from 'browser/Types'; +import { ICharSizeService, IMouseService, IRenderService, ISelectionService } from 'browser/services/Services'; +import { IRenderDimensions, IRenderer, CharacterJoinerHandler, IRequestRedrawEvent } from 'browser/renderer/Types'; +import { IColorSet, ILinkMatcherOptions, ITerminal, ILinkifier, ILinkifier2, IBrowser, IViewport, IColorManager, ICompositionHelper } from 'browser/Types'; +import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; +import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, ITerminalOptions } from 'common/Types'; +import { Buffer } from 'common/buffer/Buffer'; +import * as Browser from 'common/Platform'; +import { Terminal } from 'browser/Terminal'; +import { IUnicodeService, IOptionsService } from 'common/services/Services'; +import { IFunctionIdentifier, IParams } from 'common/parser/Types'; +import { AttributeData } from 'common/buffer/AttributeData'; + +export class TestTerminal extends Terminal { + public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; } + public keyDown(ev: any): boolean | undefined { return this._keyDown(ev); } + public keyPress(ev: any): boolean { return this._keyPress(ev); } +} + +export class MockTerminal implements ITerminal { + public onBlur!: IEvent; + public onFocus!: IEvent; + public onA11yChar!: IEvent; + public onA11yTab!: IEvent; + public onCursorMove!: IEvent; + public onLineFeed!: IEvent; + public onSelectionChange!: IEvent; + public onData!: IEvent; + public onBinary!: IEvent; + public onTitleChange!: IEvent; + public onScroll!: IEvent; + public onKey!: IEvent<{ key: string, domEvent: KeyboardEvent }>; + public onRender!: IEvent<{ start: number, end: number }>; + public onResize!: IEvent<{ cols: number, rows: number }>; + public markers!: IMarker[]; + public optionsService!: IOptionsService; + public unicodeService!: IUnicodeService; + public addMarker(cursorYOffset: number): IMarker { + throw new Error('Method not implemented.'); + } + public selectLines(start: number, end: number): void { + throw new Error('Method not implemented.'); + } + public scrollToLine(line: number): void { + throw new Error('Method not implemented.'); + } + public static string: any; + public setOption(key: any, value: any): void { + throw new Error('Method not implemented.'); + } + public blur(): void { + throw new Error('Method not implemented.'); + } + public focus(): void { + throw new Error('Method not implemented.'); + } + public resize(columns: number, rows: number): void { + throw new Error('Method not implemented.'); + } + public writeln(data: string): void { + throw new Error('Method not implemented.'); + } + public paste(data: string): void { + throw new Error('Method not implemented.'); + } + public open(parent: HTMLElement): void { + throw new Error('Method not implemented.'); + } + public attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void { + throw new Error('Method not implemented.'); + } + public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable { + throw new Error('Method not implemented.'); + } + public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable { + throw new Error('Method not implemented.'); + } + public addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable { + throw new Error('Method not implemented.'); + } + public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable { + throw new Error('Method not implemented.'); + } + public registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => boolean | void, options?: ILinkMatcherOptions): number { + throw new Error('Method not implemented.'); + } + public deregisterLinkMatcher(matcherId: number): void { + throw new Error('Method not implemented.'); + } + public registerLinkProvider(linkProvider: ILinkProvider): IDisposable { + throw new Error('Method not implemented.'); + } + public hasSelection(): boolean { + throw new Error('Method not implemented.'); + } + public getSelection(): string { + throw new Error('Method not implemented.'); + } + public getSelectionPosition(): ISelectionPosition | undefined { + throw new Error('Method not implemented.'); + } + public clearSelection(): void { + throw new Error('Method not implemented.'); + } + public select(column: number, row: number, length: number): void { + throw new Error('Method not implemented.'); + } + public selectAll(): void { + throw new Error('Method not implemented.'); + } + public dispose(): void { + throw new Error('Method not implemented.'); + } + public scrollPages(pageCount: number): void { + throw new Error('Method not implemented.'); + } + public scrollToTop(): void { + throw new Error('Method not implemented.'); + } + public scrollToBottom(): void { + throw new Error('Method not implemented.'); + } + public clear(): void { + throw new Error('Method not implemented.'); + } + public write(data: string): void { + throw new Error('Method not implemented.'); + } + public writeUtf8(data: Uint8Array): void { + throw new Error('Method not implemented.'); + } + public bracketedPasteMode!: boolean; + public renderer!: IRenderer; + public linkifier!: ILinkifier; + public linkifier2!: ILinkifier2; + public isFocused!: boolean; + public options: ITerminalOptions = {}; + public element!: HTMLElement; + public screenElement!: HTMLElement; + public rowContainer!: HTMLElement; + public selectionContainer!: HTMLElement; + public selectionService!: ISelectionService; + public textarea!: HTMLTextAreaElement; + public rows!: number; + public cols!: number; + public browser: IBrowser = Browser; + public writeBuffer!: string[]; + public children!: HTMLElement[]; + public cursorHidden!: boolean; + public cursorState!: number; + public scrollback!: number; + public buffers!: IBufferSet; + public buffer!: IBuffer; + public viewport!: IViewport; + public applicationCursor!: boolean; + public handler(data: string): void { + throw new Error('Method not implemented.'); + } + public on(event: string, callback: (...args: any[]) => void): void { + throw new Error('Method not implemented.'); + } + public off(type: string, listener: XtermListener): void { + throw new Error('Method not implemented.'); + } + public addDisposableListener(type: string, handler: XtermListener): IDisposable { + throw new Error('Method not implemented.'); + } + public scrollLines(disp: number): void { + throw new Error('Method not implemented.'); + } + public scrollToRow(absoluteRow: number): number { + throw new Error('Method not implemented.'); + } + public cancel(ev: Event, force?: boolean): void { + throw new Error('Method not implemented.'); + } + public log(text: string): void { + throw new Error('Method not implemented.'); + } + public emit(event: string, data: any): void { + throw new Error('Method not implemented.'); + } + public reset(): void { + throw new Error('Method not implemented.'); + } + public refresh(start: number, end: number): void { + throw new Error('Method not implemented.'); + } + public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } + public deregisterCharacterJoiner(joinerId: number): void { } +} + +export class MockBuffer implements IBuffer { + public markers!: IMarker[]; + public addMarker(y: number): IMarker { + throw new Error('Method not implemented.'); + } + public isCursorInViewport!: boolean; + public lines!: ICircularList; + public ydisp!: number; + public ybase!: number; + public hasScrollback!: boolean; + public y!: number; + public x!: number; + public tabs: any; + public scrollBottom!: number; + public scrollTop!: number; + public savedY!: number; + public savedX!: number; + public savedCharset: ICharset | undefined; + public savedCurAttrData = new AttributeData(); + public translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string { + return Buffer.prototype.translateBufferLineToString.apply(this, arguments as any); + } + public getWrappedRangeForLine(y: number): { first: number, last: number } { + return Buffer.prototype.getWrappedRangeForLine.apply(this, arguments as any); + } + public nextStop(x?: number): number { + throw new Error('Method not implemented.'); + } + public prevStop(x?: number): number { + throw new Error('Method not implemented.'); + } + public setLines(lines: ICircularList): void { + this.lines = lines; + } + public getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine { + return Buffer.prototype.getBlankLine.apply(this, arguments as any); + } + public stringIndexToBufferIndex(lineIndex: number, stringIndex: number): number[] { + return Buffer.prototype.stringIndexToBufferIndex.apply(this, arguments as any); + } + public iterator(trimRight: boolean, startIndex?: number, endIndex?: number): IBufferStringIterator { + return Buffer.prototype.iterator.apply(this, arguments as any); + } + public getNullCell(attr?: IAttributeData): ICellData { + throw new Error('Method not implemented.'); + } + public getWhitespaceCell(attr?: IAttributeData): ICellData { + throw new Error('Method not implemented.'); + } +} + +export class MockRenderer implements IRenderer { + public onRequestRedraw!: IEvent; + public onCanvasResize!: IEvent<{ width: number, height: number }>; + public onRender!: IEvent<{ start: number, end: number }>; + public dispose(): void { + throw new Error('Method not implemented.'); + } + public colorManager!: IColorManager; + public on(type: string, listener: XtermListener): void { + throw new Error('Method not implemented.'); + } + public off(type: string, listener: XtermListener): void { + throw new Error('Method not implemented.'); + } + public emit(type: string, data?: any): void { + throw new Error('Method not implemented.'); + } + public addDisposableListener(type: string, handler: XtermListener): IDisposable { + throw new Error('Method not implemented.'); + } + public dimensions!: IRenderDimensions; + public setColors(colors: IColorSet): void { + throw new Error('Method not implemented.'); + } + public onResize(cols: number, rows: number): void { } + public onCharSizeChanged(): void { } + public onBlur(): void { } + public onFocus(): void { } + public onSelectionChanged(start: [number, number], end: [number, number]): void { } + public onCursorMove(): void { } + public onOptionsChanged(): void { } + public onDevicePixelRatioChange(): void { } + public clear(): void { } + public renderRows(start: number, end: number): void { } + public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } + public deregisterCharacterJoiner(): boolean { return true; } +} + +export class MockViewport implements IViewport { + public dispose(): void { + throw new Error('Method not implemented.'); + } + public scrollBarWidth: number = 0; + public onThemeChange(colors: IColorSet): void { + throw new Error('Method not implemented.'); + } + public onWheel(ev: WheelEvent): boolean { + throw new Error('Method not implemented.'); + } + public onTouchStart(ev: TouchEvent): void { + throw new Error('Method not implemented.'); + } + public onTouchMove(ev: TouchEvent): boolean { + throw new Error('Method not implemented.'); + } + public syncScrollArea(): void { } + public getLinesScrolled(ev: WheelEvent): number { + throw new Error('Method not implemented.'); + } +} + +export class MockCompositionHelper implements ICompositionHelper { + public compositionstart(): void { + throw new Error('Method not implemented.'); + } + public compositionupdate(ev: CompositionEvent): void { + throw new Error('Method not implemented.'); + } + public compositionend(): void { + throw new Error('Method not implemented.'); + } + public updateCompositionElements(dontRecurse?: boolean): void { + throw new Error('Method not implemented.'); + } + public keydown(ev: KeyboardEvent): boolean { + return true; + } +} export class MockCharSizeService implements ICharSizeService { public serviceBrand: undefined; From 80c5c94e7ea9a7ceba8cd0c1af37cd60e1e58dc3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 11:06:30 -0700 Subject: [PATCH 09/10] Remove src project --- .../benchmark/SerializeAddon.benchmark.ts | 2 +- .../benchmark/tsconfig.json | 2 -- demo/client.ts | 2 +- src/Types.d.ts | 15 -------- src/{ => browser}/public/AddonManager.test.ts | 6 ++-- src/{ => browser}/public/AddonManager.ts | 0 src/{ => browser}/public/Terminal.ts | 10 +++--- src/tsconfig.json | 34 ------------------- tsconfig.all.json | 2 +- typings/xterm.d.ts | 3 +- webpack.config.js | 2 +- 11 files changed, 14 insertions(+), 64 deletions(-) delete mode 100644 src/Types.d.ts rename src/{ => browser}/public/AddonManager.test.ts (90%) rename src/{ => browser}/public/AddonManager.ts (100%) rename src/{ => browser}/public/Terminal.ts (97%) delete mode 100644 src/tsconfig.json diff --git a/addons/xterm-addon-serialize/benchmark/SerializeAddon.benchmark.ts b/addons/xterm-addon-serialize/benchmark/SerializeAddon.benchmark.ts index fbc16e03d..c1764d8ed 100644 --- a/addons/xterm-addon-serialize/benchmark/SerializeAddon.benchmark.ts +++ b/addons/xterm-addon-serialize/benchmark/SerializeAddon.benchmark.ts @@ -7,7 +7,7 @@ import { perfContext, before, ThroughputRuntimeCase } from 'xterm-benchmark'; import { spawn } from 'node-pty'; import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder'; -import { Terminal } from 'public/Terminal'; +import { Terminal } from 'browser/public/Terminal'; import { SerializeAddon } from 'SerializeAddon'; class TestTerminal extends Terminal { diff --git a/addons/xterm-addon-serialize/benchmark/tsconfig.json b/addons/xterm-addon-serialize/benchmark/tsconfig.json index 4e62ed59a..42aaaa1bf 100644 --- a/addons/xterm-addon-serialize/benchmark/tsconfig.json +++ b/addons/xterm-addon-serialize/benchmark/tsconfig.json @@ -11,8 +11,6 @@ "paths": { "common/*": ["../../../src/common/*"], "browser/*": ["../../../src/browser/*"], - "public/*": ["../../../src/public/*"], - "Terminal": ["../../../src/Terminal"], "SerializeAddon": ["../src/SerializeAddon"] } }, diff --git a/demo/client.ts b/demo/client.ts index b009a534e..eaa6f8c1c 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -8,7 +8,7 @@ /// // Use tsc version (yarn watch) -import { Terminal } from '../out/public/Terminal'; +import { Terminal } from '../out/browser/public/Terminal'; import { AttachAddon } from '../addons/xterm-addon-attach/out/AttachAddon'; import { FitAddon } from '../addons/xterm-addon-fit/out/FitAddon'; import { SearchAddon, ISearchOptions } from '../addons/xterm-addon-search/out/SearchAddon'; diff --git a/src/Types.d.ts b/src/Types.d.ts deleted file mode 100644 index 1ffb7c5ef..000000000 --- a/src/Types.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable, IMarker, ISelectionPosition, ILinkProvider } from 'xterm'; -import { IAttributeData, CharData, ITerminalOptions, ICoreTerminal } from 'common/Types'; -import { IEvent } from 'common/EventEmitter'; -import { ILinkifier, ILinkMatcherOptions, IViewport, ILinkifier2 } from 'browser/Types'; -import { IOptionsService, IUnicodeService } from 'common/services/Services'; -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IParams, IFunctionIdentifier } from 'common/parser/Types'; -import { Linkifier } from 'browser/Linkifier'; -import { Linkifier2 } from 'browser/Linkifier2'; - diff --git a/src/public/AddonManager.test.ts b/src/browser/public/AddonManager.test.ts similarity index 90% rename from src/public/AddonManager.test.ts rename to src/browser/public/AddonManager.test.ts index ea2290954..e947976ac 100644 --- a/src/public/AddonManager.test.ts +++ b/src/browser/public/AddonManager.test.ts @@ -42,9 +42,9 @@ describe('AddonManager', () => { public activate(): void {} public dispose(): void { called++; } } - manager.loadAddon(null, new Addon()); - manager.loadAddon(null, new Addon()); - manager.loadAddon(null, new Addon()); + manager.loadAddon(null!, new Addon()); + manager.loadAddon(null!, new Addon()); + manager.loadAddon(null!, new Addon()); assert.equal(manager.addons.length, 3); manager.dispose(); assert.equal(called, 3); diff --git a/src/public/AddonManager.ts b/src/browser/public/AddonManager.ts similarity index 100% rename from src/public/AddonManager.ts rename to src/browser/public/AddonManager.ts diff --git a/src/public/Terminal.ts b/src/browser/public/Terminal.ts similarity index 97% rename from src/public/Terminal.ts rename to src/browser/public/Terminal.ts index 3d4838149..b49fc6b8f 100644 --- a/src/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -8,8 +8,8 @@ import { ITerminal } from 'browser/Types'; import { IBufferLine, ICellData } from 'common/Types'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { CellData } from 'common/buffer/CellData'; -import { Terminal as TerminalCore } from '../browser/Terminal'; -import * as Strings from '../browser/LocalizableStrings'; +import { Terminal as TerminalCore } from '../Terminal'; +import * as Strings from '../LocalizableStrings'; import { IEvent, EventEmitter } from 'common/EventEmitter'; import { AddonManager } from './AddonManager'; import { IParams } from 'common/parser/Types'; @@ -17,7 +17,7 @@ import { IParams } from 'common/parser/Types'; export class Terminal implements ITerminalApi { private _core: ITerminal; private _addonManager: AddonManager; - private _parser: IParser; + private _parser: IParser | undefined; constructor(options?: ITerminalOptions) { this._core = new TerminalCore(options); @@ -81,11 +81,11 @@ export class Terminal implements ITerminalApi { public deregisterCharacterJoiner(joinerId: number): void { this._core.deregisterCharacterJoiner(joinerId); } - public registerMarker(cursorYOffset: number): IMarker { + public registerMarker(cursorYOffset: number): IMarker | undefined { this._verifyIntegers(cursorYOffset); return this._core.addMarker(cursorYOffset); } - public addMarker(cursorYOffset: number): IMarker { + public addMarker(cursorYOffset: number): IMarker | undefined { return this.registerMarker(cursorYOffset); } public hasSelection(): boolean { diff --git a/src/tsconfig.json b/src/tsconfig.json deleted file mode 100644 index 975766683..000000000 --- a/src/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "extends": "./tsconfig-base", - "compilerOptions": { - "module": "commonjs", - "lib": [ - "dom", - "es5", - "es6", - "scripthost", - "es2015.promise" - ], - "rootDir": ".", - "outDir": "../out", - "baseUrl": ".", - "paths": { - "common/*": [ "./common/*" ], - "browser/*": [ "./browser/*" ] - }, - - "noUnusedLocals": true, - "noImplicitAny": true - }, - "include": [ - "./**/*", - "../typings/xterm.d.ts" - ], - "exclude": [ - "./addons/**/*" - ], - "references": [ - { "path": "./common" }, - { "path": "./browser" } - ] -} diff --git a/tsconfig.all.json b/tsconfig.all.json index 8143ea91b..a8febb72a 100644 --- a/tsconfig.all.json +++ b/tsconfig.all.json @@ -2,7 +2,7 @@ "files": [], "include": [], "references": [ - { "path": "./src" }, + { "path": "./src/browser" }, { "path": "./test/api" }, { "path": "./test/benchmark" }, { "path": "./addons/xterm-addon-attach/src" }, diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 35f43b1b0..dfda85831 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -799,8 +799,9 @@ declare module 'xterm' { * (EXPERIMENTAL) Adds a marker to the normal buffer and returns it. If the * alt buffer is active, undefined is returned. * @param cursorYOffset The y position offset of the marker from the cursor. + * @returns The new marker or undefined. */ - registerMarker(cursorYOffset: number): IMarker; + registerMarker(cursorYOffset: number): IMarker | undefined; /** * @deprecated use `registerMarker` instead. diff --git a/webpack.config.js b/webpack.config.js index a9a60241b..4f9087b51 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -12,7 +12,7 @@ const path = require('path'); * output by tsc (because of `baseUrl` and `paths` in `tsconfig.json`. */ module.exports = { - entry: './out/public/Terminal.js', + entry: './out/browser/public/Terminal.js', devtool: 'source-map', module: { rules: [ From 394bb38913c421ee1959a4add013b9d1df456bdc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 26 Apr 2020 11:11:04 -0700 Subject: [PATCH 10/10] Remove src/tsconfig.json from eslintrc --- .eslintrc.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 41767bedf..32f8e9927 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,6 @@ "project": [ "src/browser/tsconfig.json", "src/common/tsconfig.json", - "src/tsconfig.json", "test/api/tsconfig.json", "test/benchmark/tsconfig.json", "addons/xterm-addon-attach/src/tsconfig.json",