Merge pull request #2876 from Tyriar/layers3
Move more parts of Terminal into CoreTerminal and move everything else into browser/
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
"paths": {
|
||||
"common/*": ["../../../src/common/*"],
|
||||
"browser/*": ["../../../src/browser/*"],
|
||||
"public/*": ["../../../src/public/*"],
|
||||
"Terminal": ["../../../src/Terminal"],
|
||||
"SerializeAddon": ["../src/SerializeAddon"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
* @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 { ITerminal, IColorSet, ILinkifierEvent } from 'browser/Types';
|
||||
import { IRenderDimensions } from 'browser/renderer/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));
|
||||
|
||||
@@ -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',
|
||||
];
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
/// <reference path="../typings/xterm.d.ts"/>
|
||||
|
||||
// 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';
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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';
|
||||
import * as Browser from 'common/Platform';
|
||||
import { IDisposable, IMarker, IEvent, ISelectionPosition, ILinkProvider } from 'xterm';
|
||||
import { Terminal } from './Terminal';
|
||||
import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { IColorManager, IColorSet, ILinkMatcherOptions, ILinkifier, IViewport, ILinkifier2 } 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<void>;
|
||||
public onFocus: IEvent<void>;
|
||||
public onA11yChar: IEvent<string>;
|
||||
public onA11yTab: IEvent<number>;
|
||||
public onCursorMove: IEvent<void>;
|
||||
public onLineFeed: IEvent<void>;
|
||||
public onSelectionChange: IEvent<void>;
|
||||
public onData: IEvent<string>;
|
||||
public onBinary: IEvent<string>;
|
||||
public onTitleChange: IEvent<string>;
|
||||
public onScroll: IEvent<number>;
|
||||
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 = <any>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, suppressScrollEvent: boolean): 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<IBufferLine>;
|
||||
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<IBufferLine>): 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<IRequestRedrawEvent>;
|
||||
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;
|
||||
}
|
||||
}
|
||||
Vendored
-120
@@ -1,120 +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 } 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';
|
||||
|
||||
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, IElementAccessor, IBufferAccessor, ILinkifierAccessor {
|
||||
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;
|
||||
|
||||
onBlur: IEvent<void>;
|
||||
onFocus: IEvent<void>;
|
||||
onA11yChar: IEvent<string>;
|
||||
onA11yTab: IEvent<number>;
|
||||
|
||||
scrollLines(disp: number, suppressScrollEvent?: boolean): void;
|
||||
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<void>;
|
||||
onData: IEvent<string>;
|
||||
onBinary: IEvent<string>;
|
||||
onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>;
|
||||
onLineFeed: IEvent<void>;
|
||||
onScroll: IEvent<number>;
|
||||
onSelectionChange: IEvent<void>;
|
||||
onRender: IEvent<{ start: number, end: number }>;
|
||||
onResize: IEvent<{ cols: number, rows: number }>;
|
||||
onTitleChange: IEvent<string>;
|
||||
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 IBufferAccessor {
|
||||
buffer: IBuffer;
|
||||
}
|
||||
|
||||
export interface IElementAccessor {
|
||||
readonly element: HTMLElement | undefined;
|
||||
}
|
||||
|
||||
export interface ILinkifierAccessor {
|
||||
linkifier: ILinkifier;
|
||||
linkifier2: ILinkifier2;
|
||||
}
|
||||
|
||||
export interface IBrowser {
|
||||
isNode: boolean;
|
||||
userAgent: string;
|
||||
platform: string;
|
||||
isFirefox: boolean;
|
||||
isMac: boolean;
|
||||
isIpad: boolean;
|
||||
isIphone: boolean;
|
||||
isWindows: boolean;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -103,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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -21,13 +21,13 @@
|
||||
* 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';
|
||||
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';
|
||||
@@ -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';
|
||||
@@ -49,49 +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 { 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';
|
||||
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 = <any>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;
|
||||
|
||||
// write buffer
|
||||
private _writeBuffer: WriteBuffer;
|
||||
|
||||
// Store if user went browsing history in scrollback
|
||||
private _userScrolling: boolean;
|
||||
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
|
||||
@@ -100,18 +91,14 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
*/
|
||||
private _keyDownHandled: boolean = false;
|
||||
|
||||
private _inputHandler: InputHandler;
|
||||
public linkifier: ILinkifier;
|
||||
public linkifier2: ILinkifier2;
|
||||
public viewport: IViewport;
|
||||
private _compositionHelper: ICompositionHelper;
|
||||
private _mouseZoneManager: IMouseZoneManager;
|
||||
private _accessibilityManager: AccessibilityManager;
|
||||
private _colorManager: ColorManager;
|
||||
private _theme: ITheme;
|
||||
|
||||
// bufferline to clone/copy from for new blank lines
|
||||
private _blankLine: IBufferLine = null;
|
||||
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<void>();
|
||||
public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; }
|
||||
@@ -119,8 +106,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<number>();
|
||||
public get onScroll(): IEvent<number> { return this._onScroll.event; }
|
||||
private _onSelectionChange = new EventEmitter<void>();
|
||||
public get onSelectionChange(): IEvent<void> { return this._onSelectionChange.event; }
|
||||
private _onTitleChange = new EventEmitter<string>();
|
||||
@@ -154,10 +139,22 @@ 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()));
|
||||
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));
|
||||
|
||||
this._writeBuffer = new WriteBuffer(data => this._inputHandler.parse(data));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -166,41 +163,15 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
this._userScrolling = false;
|
||||
if (!this.linkifier) {
|
||||
this.linkifier = this._instantiationService.createInstance(Linkifier);
|
||||
}
|
||||
if (!this.linkifier2) {
|
||||
this.linkifier2 = this._instantiationService.createInstance(Linkifier2);
|
||||
}
|
||||
this._customKeyEventHandler = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,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;
|
||||
@@ -282,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();
|
||||
}
|
||||
@@ -292,7 +263,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
* textarea.
|
||||
*/
|
||||
public blur(): void {
|
||||
return this.textarea.blur();
|
||||
return this.textarea?.blur();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,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();
|
||||
}
|
||||
|
||||
@@ -317,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);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -349,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!);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -361,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)));
|
||||
}
|
||||
|
||||
@@ -385,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');
|
||||
@@ -441,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);
|
||||
@@ -463,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),
|
||||
@@ -478,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) {
|
||||
@@ -532,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}"`);
|
||||
}
|
||||
}
|
||||
@@ -545,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -566,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 ((<any>ev).overrideType || ev.type) {
|
||||
case 'mousemove':
|
||||
action = CoreMouseAction.MOVE;
|
||||
@@ -646,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);
|
||||
@@ -682,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);
|
||||
@@ -701,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);
|
||||
@@ -709,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;
|
||||
@@ -735,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;
|
||||
}
|
||||
|
||||
@@ -746,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);
|
||||
@@ -760,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) {
|
||||
@@ -783,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);
|
||||
}
|
||||
}));
|
||||
@@ -827,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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -843,134 +813,13 @@ 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._userScrolling) {
|
||||
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) {
|
||||
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._userScrolling) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
paste(data, this.textarea!, this._coreService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -986,25 +835,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.
|
||||
@@ -1036,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);
|
||||
}
|
||||
}
|
||||
@@ -1051,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;
|
||||
@@ -1074,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1086,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]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1122,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();
|
||||
}
|
||||
@@ -1167,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 });
|
||||
@@ -1260,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);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1306,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;
|
||||
@@ -1334,18 +1164,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._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);
|
||||
@@ -1372,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;
|
||||
}
|
||||
@@ -1392,14 +1217,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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 './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;
|
||||
@@ -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<void>;
|
||||
public onFocus!: IEvent<void>;
|
||||
public onA11yChar!: IEvent<string>;
|
||||
public onA11yTab!: IEvent<number>;
|
||||
public onCursorMove!: IEvent<void>;
|
||||
public onLineFeed!: IEvent<void>;
|
||||
public onSelectionChange!: IEvent<void>;
|
||||
public onData!: IEvent<string>;
|
||||
public onBinary!: IEvent<string>;
|
||||
public onTitleChange!: IEvent<string>;
|
||||
public onScroll!: IEvent<number>;
|
||||
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 = <any>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<IBufferLine>;
|
||||
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<IBufferLine>): 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<IRequestRedrawEvent>;
|
||||
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;
|
||||
|
||||
Vendored
+99
-1
@@ -3,9 +3,107 @@
|
||||
* @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';
|
||||
import { IFunctionIdentifier, IParams } from 'common/parser/Types';
|
||||
|
||||
export interface ITerminal extends IPublicTerminal, ICoreTerminal {
|
||||
element: HTMLElement | undefined;
|
||||
screenElement: HTMLElement | undefined;
|
||||
browser: IBrowser;
|
||||
buffer: IBuffer;
|
||||
buffers: IBufferSet;
|
||||
viewport: IViewport | undefined;
|
||||
// TODO: We should remove options once components adopt optionsService
|
||||
options: ITerminalOptions;
|
||||
linkifier: ILinkifier;
|
||||
linkifier2: ILinkifier2;
|
||||
|
||||
onBlur: IEvent<void>;
|
||||
onFocus: IEvent<void>;
|
||||
onA11yChar: IEvent<string>;
|
||||
onA11yTab: IEvent<number>;
|
||||
|
||||
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<void>;
|
||||
onData: IEvent<string>;
|
||||
onBinary: IEvent<string>;
|
||||
onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>;
|
||||
onLineFeed: IEvent<void>;
|
||||
onScroll: IEvent<number>;
|
||||
onSelectionChange: IEvent<void>;
|
||||
onRender: IEvent<{ start: number, end: number }>;
|
||||
onResize: IEvent<{ cols: number, rows: number }>;
|
||||
onTitleChange: IEvent<string>;
|
||||
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 | undefined;
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
@@ -4,12 +4,12 @@
|
||||
*/
|
||||
|
||||
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';
|
||||
import { Terminal as TerminalCore } from '../Terminal';
|
||||
import * as Strings from '../browser/LocalizableStrings';
|
||||
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 {
|
||||
@@ -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 {
|
||||
|
||||
+181
-5
@@ -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, 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';
|
||||
@@ -37,8 +37,10 @@ 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';
|
||||
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;
|
||||
@@ -50,7 +52,11 @@ export abstract class CoreTerminal extends Disposable {
|
||||
public readonly unicodeService: IUnicodeService;
|
||||
public readonly optionsService: IOptionsService;
|
||||
|
||||
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<string>();
|
||||
public get onBinary(): IEvent<string> { return this._onBinary.event; }
|
||||
@@ -60,6 +66,8 @@ export abstract class CoreTerminal extends Disposable {
|
||||
public get onLineFeed(): IEvent<void> { 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<number>();
|
||||
public get onScroll(): IEvent<number> { return this._onScroll.event; }
|
||||
|
||||
public get cols(): number { return this._bufferService.cols; }
|
||||
public get rows(): number { return this._bufferService.rows; }
|
||||
@@ -89,11 +97,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)));
|
||||
|
||||
// Setup WriteBuffer
|
||||
this._writeBuffer = new WriteBuffer(data => this._inputHandler.parse(data));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -105,6 +121,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;
|
||||
@@ -116,12 +140,167 @@ 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).
|
||||
* @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);
|
||||
}
|
||||
|
||||
/** 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();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -154,7 +333,4 @@ export abstract class CoreTerminal extends Disposable {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public abstract scrollToBottom(): void;
|
||||
public abstract addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Vendored
+7
-1
@@ -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;
|
||||
@@ -51,7 +57,7 @@ export interface ICircularList<T> {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface IBufferService {
|
||||
readonly rows: number;
|
||||
readonly buffer: IBuffer;
|
||||
readonly buffers: IBufferSet;
|
||||
isUserScrolling: boolean;
|
||||
|
||||
onResize: IEvent<{ cols: number, rows: number }>;
|
||||
|
||||
|
||||
@@ -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" }
|
||||
]
|
||||
}
|
||||
@@ -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 = '';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{ "path": "./src" },
|
||||
{ "path": "./src/browser" },
|
||||
{ "path": "./test/api" },
|
||||
{ "path": "./test/benchmark" },
|
||||
{ "path": "./addons/xterm-addon-attach/src" },
|
||||
|
||||
Vendored
+3
-2
@@ -799,13 +799,14 @@ 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.
|
||||
*/
|
||||
addMarker(cursorYOffset: number): IMarker;
|
||||
addMarker(cursorYOffset: number): IMarker | undefined;
|
||||
|
||||
/**
|
||||
* Gets whether the terminal has an active selection.
|
||||
|
||||
+1
-1
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user