Merge branch 'master' into reverse_wraparound
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2020 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* @license MIT
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*
|
||||
* Terminal Emulation References:
|
||||
* http://vt100.net/
|
||||
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
|
||||
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
* http://invisible-island.net/vttest/
|
||||
* http://www.inwap.com/pdp10/ansicode.txt
|
||||
* http://linux.die.net/man/4/console_codes
|
||||
* http://linux.die.net/man/7/urxvt
|
||||
*/
|
||||
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, ICoreMouseService, IUnicodeService, IDirtyRowService } from 'common/services/Services';
|
||||
import { InstantiationService } from 'common/services/InstantiationService';
|
||||
import { LogService } from 'common/services/LogService';
|
||||
import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService';
|
||||
import { OptionsService } from 'common/services/OptionsService';
|
||||
import { ITerminalOptions, IDisposable, IBufferLine, IAttributeData, ICoreTerminal } from 'common/Types';
|
||||
import { CoreService } from 'common/services/CoreService';
|
||||
import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter';
|
||||
import { CoreMouseService } from 'common/services/CoreMouseService';
|
||||
import { DirtyRowService } from 'common/services/DirtyRowService';
|
||||
import { UnicodeService } from 'common/services/UnicodeService';
|
||||
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 implements ICoreTerminal {
|
||||
protected readonly _instantiationService: IInstantiationService;
|
||||
protected readonly _bufferService: IBufferService;
|
||||
protected readonly _logService: ILogService;
|
||||
protected readonly _coreService: ICoreService;
|
||||
protected readonly _charsetService: ICharsetService;
|
||||
protected readonly _coreMouseService: ICoreMouseService;
|
||||
protected readonly _dirtyRowService: IDirtyRowService;
|
||||
|
||||
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; }
|
||||
private _onData = new EventEmitter<string>();
|
||||
public get onData(): IEvent<string> { return this._onData.event; }
|
||||
protected _onLineFeed = new EventEmitter<void>();
|
||||
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; }
|
||||
public get buffers(): IBufferSet { return this._bufferService.buffers; }
|
||||
|
||||
constructor(
|
||||
options: ITerminalOptions
|
||||
) {
|
||||
super();
|
||||
|
||||
// Setup and initialize services
|
||||
this._instantiationService = new InstantiationService();
|
||||
this.optionsService = new OptionsService(options);
|
||||
this._instantiationService.setService(IOptionsService, this.optionsService);
|
||||
this._bufferService = this._instantiationService.createInstance(BufferService);
|
||||
this._instantiationService.setService(IBufferService, this._bufferService);
|
||||
this._logService = this._instantiationService.createInstance(LogService);
|
||||
this._instantiationService.setService(ILogService, this._logService);
|
||||
this._coreService = this._instantiationService.createInstance(CoreService, () => this.scrollToBottom());
|
||||
this._instantiationService.setService(ICoreService, this._coreService);
|
||||
this._coreMouseService = this._instantiationService.createInstance(CoreMouseService);
|
||||
this._instantiationService.setService(ICoreMouseService, this._coreMouseService);
|
||||
this._dirtyRowService = this._instantiationService.createInstance(DirtyRowService);
|
||||
this._instantiationService.setService(IDirtyRowService, this._dirtyRowService);
|
||||
this.unicodeService = this._instantiationService.createInstance(UnicodeService);
|
||||
this._instantiationService.setService(IUnicodeService, this.unicodeService);
|
||||
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 {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
super.dispose();
|
||||
this._windowsMode?.dispose();
|
||||
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;
|
||||
}
|
||||
|
||||
x = Math.max(x, MINIMUM_COLS);
|
||||
y = Math.max(y, MINIMUM_ROWS);
|
||||
|
||||
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) {
|
||||
case 'scrollback':
|
||||
this.buffers.resize(this.cols, this.rows);
|
||||
break;
|
||||
case 'windowsMode':
|
||||
if (this.optionsService.options.windowsMode) {
|
||||
this._enableWindowsMode();
|
||||
} else {
|
||||
this._windowsMode?.dispose();
|
||||
this._windowsMode = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected _enableWindowsMode(): void {
|
||||
if (!this._windowsMode) {
|
||||
const disposables: IDisposable[] = [];
|
||||
disposables.push(this.onLineFeed(updateWindowsModeWrappedState.bind(null, this._bufferService)));
|
||||
disposables.push(this.addCsiHandler({ final: 'H' }, () => {
|
||||
updateWindowsModeWrappedState(this._bufferService);
|
||||
return false;
|
||||
}));
|
||||
this._windowsMode = {
|
||||
dispose: () => {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,3 +63,7 @@ export class EventEmitter<T, U = void> implements IEventEmitter<T, U> {
|
||||
this._disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
export function forwardEvent<T>(from: IEvent<T>, to: IEventEmitter<T>): IDisposable {
|
||||
return from(e => to.fire(e));
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,13 +9,15 @@ import { clone } from 'common/Clone';
|
||||
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
|
||||
import { IBufferSet, IBuffer } from 'common/buffer/Types';
|
||||
import { BufferSet } from 'common/buffer/BufferSet';
|
||||
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset } from 'common/Types';
|
||||
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset, IModes } from 'common/Types';
|
||||
import { UnicodeV6 } from 'common/input/UnicodeV6';
|
||||
|
||||
export class MockBufferService implements IBufferService {
|
||||
public serviceBrand: any;
|
||||
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,
|
||||
@@ -31,6 +33,7 @@ export class MockBufferService implements IBufferService {
|
||||
}
|
||||
|
||||
export class MockCoreMouseService implements ICoreMouseService {
|
||||
public areMouseEventsActive: boolean = false;
|
||||
public activeEncoding: string = '';
|
||||
public activeProtocol: string = '';
|
||||
public addEncoding(name: string): void {}
|
||||
@@ -47,7 +50,6 @@ export class MockCharsetService implements ICharsetService {
|
||||
public serviceBrand: any;
|
||||
public charset: ICharset | undefined;
|
||||
public glevel: number = 0;
|
||||
public charsets: ReadonlyArray<ICharset> = [];
|
||||
public reset(): void {}
|
||||
public setgLevel(g: number): void {}
|
||||
public setgCharset(g: number, charset: ICharset): void {}
|
||||
@@ -58,11 +60,16 @@ export class MockCoreService implements ICoreService {
|
||||
public isCursorInitialized: boolean = false;
|
||||
public isCursorHidden: boolean = false;
|
||||
public isFocused: boolean = false;
|
||||
public modes: IModes = {
|
||||
insertMode: false
|
||||
};
|
||||
public decPrivateModes: IDecPrivateModes = {
|
||||
applicationCursorKeys: false,
|
||||
applicationKeypad: false,
|
||||
bracketedPasteMode: false,
|
||||
origin: false,
|
||||
reverseWraparound: false,
|
||||
sendFocus: false,
|
||||
wraparound: true
|
||||
};
|
||||
public onData: IEvent<string> = new EventEmitter<string>().event;
|
||||
|
||||
Vendored
+107
-1
@@ -3,13 +3,29 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: The options that are not in the public API should be reviewed
|
||||
export interface ITerminalOptions extends IPublicTerminalOptions {
|
||||
[key: string]: any;
|
||||
cancelEvents?: boolean;
|
||||
convertEol?: boolean;
|
||||
termName?: string;
|
||||
}
|
||||
|
||||
export type XtermListener = (...args: any[]) => void;
|
||||
|
||||
/**
|
||||
@@ -41,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;
|
||||
@@ -150,12 +166,17 @@ export interface IMarker extends IDisposable {
|
||||
readonly isDisposed: boolean;
|
||||
readonly line: number;
|
||||
}
|
||||
export interface IModes {
|
||||
insertMode: boolean;
|
||||
}
|
||||
|
||||
export interface IDecPrivateModes {
|
||||
applicationCursorKeys: boolean;
|
||||
applicationKeypad: boolean;
|
||||
bracketedPasteMode: boolean;
|
||||
origin: boolean;
|
||||
reverseWraparound: boolean;
|
||||
sendFocus: boolean;
|
||||
wraparound: boolean; // defaults: xterm - true, vt100 - false
|
||||
}
|
||||
|
||||
@@ -287,3 +308,88 @@ export interface IWindowOptions {
|
||||
popTitle?: boolean;
|
||||
setWinLines?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the parser and handles actions generated by the parser.
|
||||
*/
|
||||
export interface IInputHandler {
|
||||
onTitleChange: IEvent<string>;
|
||||
onRequestScroll: IEvent<IAttributeData, boolean | void>;
|
||||
|
||||
parse(data: string | Uint8Array): void;
|
||||
print(data: Uint32Array, start: number, end: number): void;
|
||||
|
||||
/** C0 BEL */ bell(): void;
|
||||
/** C0 LF */ lineFeed(): void;
|
||||
/** C0 CR */ carriageReturn(): void;
|
||||
/** C0 BS */ backspace(): void;
|
||||
/** C0 HT */ tab(): void;
|
||||
/** C0 SO */ shiftOut(): void;
|
||||
/** C0 SI */ shiftIn(): void;
|
||||
|
||||
/** CSI @ */ insertChars(params: IParams): void;
|
||||
/** CSI SP @ */ scrollLeft(params: IParams): void;
|
||||
/** CSI A */ cursorUp(params: IParams): void;
|
||||
/** CSI SP A */ scrollRight(params: IParams): void;
|
||||
/** CSI B */ cursorDown(params: IParams): void;
|
||||
/** CSI C */ cursorForward(params: IParams): void;
|
||||
/** CSI D */ cursorBackward(params: IParams): void;
|
||||
/** CSI E */ cursorNextLine(params: IParams): void;
|
||||
/** CSI F */ cursorPrecedingLine(params: IParams): void;
|
||||
/** CSI G */ cursorCharAbsolute(params: IParams): void;
|
||||
/** CSI H */ cursorPosition(params: IParams): void;
|
||||
/** CSI I */ cursorForwardTab(params: IParams): void;
|
||||
/** CSI J */ eraseInDisplay(params: IParams): void;
|
||||
/** CSI K */ eraseInLine(params: IParams): void;
|
||||
/** CSI L */ insertLines(params: IParams): void;
|
||||
/** CSI M */ deleteLines(params: IParams): void;
|
||||
/** CSI P */ deleteChars(params: IParams): void;
|
||||
/** CSI S */ scrollUp(params: IParams): void;
|
||||
/** CSI T */ scrollDown(params: IParams, collect?: string): void;
|
||||
/** CSI X */ eraseChars(params: IParams): void;
|
||||
/** CSI Z */ cursorBackwardTab(params: IParams): void;
|
||||
/** CSI ` */ charPosAbsolute(params: IParams): void;
|
||||
/** CSI a */ hPositionRelative(params: IParams): void;
|
||||
/** CSI b */ repeatPrecedingCharacter(params: IParams): void;
|
||||
/** CSI c */ sendDeviceAttributesPrimary(params: IParams): void;
|
||||
/** CSI > c */ sendDeviceAttributesSecondary(params: IParams): void;
|
||||
/** CSI d */ linePosAbsolute(params: IParams): void;
|
||||
/** CSI e */ vPositionRelative(params: IParams): void;
|
||||
/** CSI f */ hVPosition(params: IParams): void;
|
||||
/** CSI g */ tabClear(params: IParams): void;
|
||||
/** CSI h */ setMode(params: IParams, collect?: string): void;
|
||||
/** CSI l */ resetMode(params: IParams, collect?: string): void;
|
||||
/** CSI m */ charAttributes(params: IParams): void;
|
||||
/** CSI n */ deviceStatus(params: IParams, collect?: string): void;
|
||||
/** CSI p */ softReset(params: IParams, collect?: string): void;
|
||||
/** CSI q */ setCursorStyle(params: IParams, collect?: string): void;
|
||||
/** CSI r */ setScrollRegion(params: IParams, collect?: string): void;
|
||||
/** CSI s */ saveCursor(params: IParams): void;
|
||||
/** CSI u */ restoreCursor(params: IParams): void;
|
||||
/** CSI ' } */ insertColumns(params: IParams): void;
|
||||
/** CSI ' ~ */ deleteColumns(params: IParams): void;
|
||||
/** OSC 0
|
||||
OSC 2 */ setTitle(data: string): void;
|
||||
/** ESC E */ nextLine(): void;
|
||||
/** ESC = */ keypadApplicationMode(): void;
|
||||
/** ESC > */ keypadNumericMode(): void;
|
||||
/** ESC % G
|
||||
ESC % @ */ selectDefaultCharset(): void;
|
||||
/** ESC ( C
|
||||
ESC ) C
|
||||
ESC * C
|
||||
ESC + C
|
||||
ESC - C
|
||||
ESC . C
|
||||
ESC / C */ selectCharset(collectAndFlag: string): void;
|
||||
/** ESC D */ index(): void;
|
||||
/** ESC H */ tabSet(): void;
|
||||
/** ESC M */ reverseIndex(): void;
|
||||
/** ESC c */ fullReset(): void;
|
||||
/** ESC n
|
||||
ESC o
|
||||
ESC |
|
||||
ESC }
|
||||
ESC ~ */ setgLevel(level: number): void;
|
||||
/** ESC # 8 */ screenAlignmentPattern(): void;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export class Buffer implements IBuffer {
|
||||
public savedY: number = 0;
|
||||
public savedX: number = 0;
|
||||
public savedCurAttrData = DEFAULT_ATTR_DATA.clone();
|
||||
public savedCharset: ICharset | null = DEFAULT_CHARSET;
|
||||
public savedCharset: ICharset | undefined = DEFAULT_CHARSET;
|
||||
public markers: Marker[] = [];
|
||||
private _nullCell: ICellData = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
||||
private _whitespaceCell: ICellData = CellData.fromCharData([0, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE]);
|
||||
|
||||
Vendored
+1
-1
@@ -31,7 +31,7 @@ export interface IBuffer {
|
||||
hasScrollback: boolean;
|
||||
savedY: number;
|
||||
savedX: number;
|
||||
savedCharset: ICharset | null;
|
||||
savedCharset: ICharset | undefined;
|
||||
savedCurAttrData: IAttributeData;
|
||||
isCursorInViewport: boolean;
|
||||
markers: IMarker[];
|
||||
|
||||
@@ -10,12 +10,12 @@ import { ICharset } from 'common/Types';
|
||||
* to be represented within the terminal with only 8-bit encoding. See ISO 2022
|
||||
* for a discussion on character sets. Only VT100 character sets are supported.
|
||||
*/
|
||||
export const CHARSETS: { [key: string]: ICharset | null } = {};
|
||||
export const CHARSETS: { [key: string]: ICharset | undefined } = {};
|
||||
|
||||
/**
|
||||
* The default character set, US.
|
||||
*/
|
||||
export const DEFAULT_CHARSET: ICharset | null = CHARSETS['B'];
|
||||
export const DEFAULT_CHARSET: ICharset | undefined = CHARSETS['B'];
|
||||
|
||||
/**
|
||||
* DEC Special Character and Line Drawing Set.
|
||||
@@ -74,7 +74,7 @@ CHARSETS['A'] = {
|
||||
* United States character set
|
||||
* ESC (B
|
||||
*/
|
||||
CHARSETS['B'] = null;
|
||||
CHARSETS['B'] = undefined;
|
||||
|
||||
/**
|
||||
* Dutch character set
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { IBufferService, IOptionsService } from 'common/services/Services';
|
||||
import { BufferSet } from 'common/buffer/BufferSet';
|
||||
import { IBufferSet, IBuffer } from 'common/buffer/Types';
|
||||
import { EventEmitter, IEvent } from 'common/EventEmitter';
|
||||
|
||||
export const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
|
||||
export const MINIMUM_ROWS = 1;
|
||||
@@ -16,6 +17,11 @@ 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; }
|
||||
|
||||
public get buffer(): IBuffer { return this.buffers.active; }
|
||||
|
||||
@@ -30,9 +36,13 @@ export class BufferService implements IBufferService {
|
||||
public resize(cols: number, rows: number): void {
|
||||
this.cols = cols;
|
||||
this.rows = rows;
|
||||
this.buffers.resize(cols, rows);
|
||||
this.buffers.setupTabStops(this.cols);
|
||||
this._onResize.fire({ cols, rows });
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.buffers = new BufferSet(this._optionsService, this);
|
||||
this.isUserScrolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,22 +10,23 @@ export class CharsetService implements ICharsetService {
|
||||
public serviceBrand: any;
|
||||
|
||||
public charset: ICharset | undefined;
|
||||
public charsets: ICharset[] = [];
|
||||
public glevel: number = 0;
|
||||
|
||||
private _charsets: (ICharset | undefined)[] = [];
|
||||
|
||||
public reset(): void {
|
||||
this.charset = undefined;
|
||||
this.charsets = [];
|
||||
this._charsets = [];
|
||||
this.glevel = 0;
|
||||
}
|
||||
|
||||
public setgLevel(g: number): void {
|
||||
this.glevel = g;
|
||||
this.charset = this.charsets[g];
|
||||
this.charset = this._charsets[g];
|
||||
}
|
||||
|
||||
public setgCharset(g: number, charset: ICharset): void {
|
||||
this.charsets[g] = charset;
|
||||
public setgCharset(g: number, charset: ICharset | undefined): void {
|
||||
this._charsets[g] = charset;
|
||||
if (this.glevel === g) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@@ -192,6 +192,10 @@ export class CoreMouseService implements ICoreMouseService {
|
||||
return this._activeProtocol;
|
||||
}
|
||||
|
||||
public get areMouseEventsActive(): boolean {
|
||||
return this._protocols[this._activeProtocol].events !== 0;
|
||||
}
|
||||
|
||||
public set activeProtocol(name: string) {
|
||||
if (!this._protocols[name]) {
|
||||
throw new Error(`unknown protocol "${name}"`);
|
||||
|
||||
@@ -5,14 +5,20 @@
|
||||
|
||||
import { ICoreService, ILogService, IOptionsService, IBufferService } from 'common/services/Services';
|
||||
import { EventEmitter, IEvent } from 'common/EventEmitter';
|
||||
import { IDecPrivateModes } from 'common/Types';
|
||||
import { IDecPrivateModes, IModes } from 'common/Types';
|
||||
import { clone } from 'common/Clone';
|
||||
|
||||
const DEFAULT_MODES: IModes = Object.freeze({
|
||||
insertMode: false
|
||||
});
|
||||
|
||||
const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({
|
||||
applicationCursorKeys: false,
|
||||
applicationKeypad: false,
|
||||
bracketedPasteMode: false,
|
||||
origin: false,
|
||||
reverseWraparound: false,
|
||||
sendFocus: false,
|
||||
wraparound: true // defaults: xterm - true, vt100 - false
|
||||
});
|
||||
|
||||
@@ -21,6 +27,7 @@ export class CoreService implements ICoreService {
|
||||
|
||||
public isCursorInitialized: boolean = false;
|
||||
public isCursorHidden: boolean = false;
|
||||
public modes: IModes;
|
||||
public decPrivateModes: IDecPrivateModes;
|
||||
|
||||
private _onData = new EventEmitter<string>();
|
||||
@@ -37,10 +44,12 @@ export class CoreService implements ICoreService {
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@IOptionsService private readonly _optionsService: IOptionsService
|
||||
) {
|
||||
this.modes = clone(DEFAULT_MODES);
|
||||
this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES);
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.modes = clone(DEFAULT_MODES);
|
||||
this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,19 +5,20 @@
|
||||
|
||||
import { IEvent } from 'common/EventEmitter';
|
||||
import { IBuffer, IBufferSet } from 'common/buffer/Types';
|
||||
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharset, IWindowOptions } from 'common/Types';
|
||||
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharset, IWindowOptions, IModes } from 'common/Types';
|
||||
import { createDecorator } from 'common/services/ServiceRegistry';
|
||||
|
||||
export const IBufferService = createDecorator<IBufferService>('BufferService');
|
||||
export interface IBufferService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
|
||||
readonly cols: number;
|
||||
readonly rows: number;
|
||||
readonly buffer: IBuffer;
|
||||
readonly buffers: IBufferSet;
|
||||
isUserScrolling: boolean;
|
||||
|
||||
// TODO: Move resize event here
|
||||
onResize: IEvent<{ cols: number, rows: number }>;
|
||||
|
||||
resize(cols: number, rows: number): void;
|
||||
reset(): void;
|
||||
@@ -27,6 +28,7 @@ export const ICoreMouseService = createDecorator<ICoreMouseService>('CoreMouseSe
|
||||
export interface ICoreMouseService {
|
||||
activeProtocol: string;
|
||||
activeEncoding: string;
|
||||
areMouseEventsActive: boolean;
|
||||
addProtocol(name: string, protocol: ICoreMouseProtocol): void;
|
||||
addEncoding(name: string, encoding: CoreMouseEncoding): void;
|
||||
reset(): void;
|
||||
@@ -51,12 +53,12 @@ export interface ICoreMouseService {
|
||||
/**
|
||||
* Human readable version of mouse events.
|
||||
*/
|
||||
explainEvents(events: CoreMouseEventType): {[event: string]: boolean};
|
||||
explainEvents(events: CoreMouseEventType): { [event: string]: boolean };
|
||||
}
|
||||
|
||||
export const ICoreService = createDecorator<ICoreService>('CoreService');
|
||||
export interface ICoreService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Initially the cursor will not be visible until the first time the terminal
|
||||
@@ -65,6 +67,7 @@ export interface ICoreService {
|
||||
isCursorInitialized: boolean;
|
||||
isCursorHidden: boolean;
|
||||
|
||||
readonly modes: IModes;
|
||||
readonly decPrivateModes: IDecPrivateModes;
|
||||
|
||||
readonly onData: IEvent<string>;
|
||||
@@ -92,11 +95,10 @@ export interface ICoreService {
|
||||
|
||||
export const ICharsetService = createDecorator<ICharsetService>('CharsetService');
|
||||
export interface ICharsetService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
|
||||
charset: ICharset | undefined;
|
||||
readonly glevel: number;
|
||||
readonly charsets: ReadonlyArray<ICharset>;
|
||||
|
||||
reset(): void;
|
||||
|
||||
@@ -111,12 +113,12 @@ export interface ICharsetService {
|
||||
* @param g
|
||||
* @param charset
|
||||
*/
|
||||
setgCharset(g: number, charset: ICharset): void;
|
||||
setgCharset(g: number, charset: ICharset | undefined): void;
|
||||
}
|
||||
|
||||
export const IDirtyRowService = createDecorator<IDirtyRowService>('DirtyRowService');
|
||||
export interface IDirtyRowService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
|
||||
readonly start: number;
|
||||
readonly end: number;
|
||||
@@ -132,61 +134,32 @@ export interface IServiceIdentifier<T> {
|
||||
type: T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature0<T> {
|
||||
new(...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
export interface IBrandedService {
|
||||
serviceBrand: undefined;
|
||||
};
|
||||
|
||||
export interface IConstructorSignature1<A1, T> {
|
||||
new(first: A1, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature2<A1, A2, T> {
|
||||
new(first: A1, second: A2, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature3<A1, A2, A3, T> {
|
||||
new(first: A1, second: A2, third: A3, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature4<A1, A2, A3, A4, T> {
|
||||
new(first: A1, second: A2, third: A3, fourth: A4, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature5<A1, A2, A3, A4, A5, T> {
|
||||
new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature6<A1, A2, A3, A4, A5, A6, T> {
|
||||
new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature7<A1, A2, A3, A4, A5, A6, A7, T> {
|
||||
new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
|
||||
export interface IConstructorSignature8<A1, A2, A3, A4, A5, A6, A7, A8, T> {
|
||||
new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8, ...services: { serviceBrand: any }[]): T;
|
||||
}
|
||||
type GetLeadingNonServiceArgs<Args> =
|
||||
Args extends [...IBrandedService[]] ? []
|
||||
: Args extends [infer A1, ...IBrandedService[]] ? [A1]
|
||||
: Args extends [infer A1, infer A2, ...IBrandedService[]] ? [A1, A2]
|
||||
: Args extends [infer A1, infer A2, infer A3, ...IBrandedService[]] ? [A1, A2, A3]
|
||||
: Args extends [infer A1, infer A2, infer A3, infer A4, ...IBrandedService[]] ? [A1, A2, A3, A4]
|
||||
: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, ...IBrandedService[]] ? [A1, A2, A3, A4, A5]
|
||||
: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, ...IBrandedService[]] ? [A1, A2, A3, A4, A5, A6]
|
||||
: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, ...IBrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7]
|
||||
: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, ...IBrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7, A8]
|
||||
: never;
|
||||
|
||||
export const IInstantiationService = createDecorator<IInstantiationService>('InstantiationService');
|
||||
export interface IInstantiationService {
|
||||
setService<T>(id: IServiceIdentifier<T>, instance: T): void;
|
||||
getService<T>(id: IServiceIdentifier<T>): T | undefined;
|
||||
|
||||
createInstance<T>(ctor: IConstructorSignature0<T>): T;
|
||||
createInstance<A1, T>(ctor: IConstructorSignature1<A1, T>, first: A1): T;
|
||||
createInstance<A1, A2, T>(ctor: IConstructorSignature2<A1, A2, T>, first: A1, second: A2): T;
|
||||
createInstance<A1, A2, A3, T>(ctor: IConstructorSignature3<A1, A2, A3, T>, first: A1, second: A2, third: A3): T;
|
||||
createInstance<A1, A2, A3, A4, T>(ctor: IConstructorSignature4<A1, A2, A3, A4, T>, first: A1, second: A2, third: A3, fourth: A4): T;
|
||||
createInstance<A1, A2, A3, A4, A5, T>(ctor: IConstructorSignature5<A1, A2, A3, A4, A5, T>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5): T;
|
||||
createInstance<A1, A2, A3, A4, A5, A6, T>(ctor: IConstructorSignature6<A1, A2, A3, A4, A5, A6, T>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6): T;
|
||||
createInstance<A1, A2, A3, A4, A5, A6, A7, T>(ctor: IConstructorSignature7<A1, A2, A3, A4, A5, A6, A7, T>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7): T;
|
||||
createInstance<A1, A2, A3, A4, A5, A6, A7, A8, T>(ctor: IConstructorSignature8<A1, A2, A3, A4, A5, A6, A7, A8, T>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8): T;
|
||||
createInstance<Ctor extends new (...args: any[]) => any, R extends InstanceType<Ctor>>(t: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R;
|
||||
}
|
||||
|
||||
export const ILogService = createDecorator<ILogService>('LogService');
|
||||
export interface ILogService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
|
||||
debug(message: any, ...optionalParams: any[]): void;
|
||||
info(message: any, ...optionalParams: any[]): void;
|
||||
@@ -196,7 +169,7 @@ export interface ILogService {
|
||||
|
||||
export const IOptionsService = createDecorator<IOptionsService>('OptionsService');
|
||||
export interface IOptionsService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
|
||||
readonly options: ITerminalOptions;
|
||||
|
||||
@@ -311,7 +284,7 @@ export interface ITheme {
|
||||
|
||||
export const IUnicodeService = createDecorator<IUnicodeService>('UnicodeService');
|
||||
export interface IUnicodeService {
|
||||
serviceBrand: any;
|
||||
serviceBrand: undefined;
|
||||
/** Register an Unicode version provider. */
|
||||
register(provider: IUnicodeVersionProvider): void;
|
||||
/** Registered Unicode versions. */
|
||||
|
||||
@@ -10,5 +10,8 @@
|
||||
],
|
||||
"baseUrl": ".."
|
||||
},
|
||||
"include": [ "./**/*" ]
|
||||
"include": [
|
||||
"./**/*",
|
||||
"../../typings/xterm.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user