From 224fb5c6a2bfd9667e35db6e9c3d4a0aea79a0f1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 18 Dec 2019 10:53:05 +1100 Subject: [PATCH] Move charset into own service --- src/InputHandler.test.ts | 20 ++++++++-------- src/InputHandler.ts | 33 ++++++++++++++------------- src/Terminal.ts | 10 +++++--- src/common/TestUtils.test.ts | 24 ++++++++++--------- src/common/Types.d.ts | 8 +------ src/common/services/CharsetService.ts | 33 +++++++++++++++++++++++++++ src/common/services/CoreService.ts | 25 +------------------- src/common/services/Services.ts | 16 +++++++++---- 8 files changed, 94 insertions(+), 75 deletions(-) create mode 100644 src/common/services/CharsetService.ts diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts index d8defa1cc..fa9ef67c9 100644 --- a/src/InputHandler.test.ts +++ b/src/InputHandler.test.ts @@ -13,7 +13,7 @@ import { CellData } from 'common/buffer/CellData'; import { Attributes } from 'common/buffer/Constants'; import { AttributeData } from 'common/buffer/AttributeData'; import { Params } from 'common/parser/Params'; -import { MockCoreService, MockBufferService, MockDirtyRowService, MockOptionsService, MockLogService, MockCoreMouseService } from 'common/TestUtils.test'; +import { MockCoreService, MockBufferService, MockDirtyRowService, MockOptionsService, MockLogService, MockCoreMouseService, MockCharsetService } from 'common/TestUtils.test'; import { IBufferService } from 'common/services/Services'; import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; import { clone } from 'common/Clone'; @@ -41,7 +41,7 @@ describe('InputHandler', () => { bufferService.buffer.x = 1; bufferService.buffer.y = 2; bufferService.buffer.ybase = 0; - const inputHandler = new InputHandler(terminal, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(terminal, bufferService, new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); // Save cursor position inputHandler.saveCursor(); assert.equal(bufferService.buffer.x, 1); @@ -60,7 +60,7 @@ describe('InputHandler', () => { describe('setCursorStyle', () => { it('should call Terminal.setOption with correct params', () => { const optionsService = new MockOptionsService(); - const inputHandler = new InputHandler(new MockInputHandlingTerminal(), new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), optionsService, new MockCoreMouseService()); + const inputHandler = new InputHandler(new MockInputHandlingTerminal(), new MockBufferService(80, 30), new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), optionsService, new MockCoreMouseService()); inputHandler.setCursorStyle(Params.fromArray([0])); assert.equal(optionsService.options['cursorStyle'], 'block'); @@ -101,7 +101,7 @@ describe('InputHandler', () => { it('should toggle Terminal.bracketedPasteMode', () => { const terminal = new MockInputHandlingTerminal(); terminal.bracketedPasteMode = false; - const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); // Set bracketed paste mode inputHandler.setModePrivate(Params.fromArray([2004])); assert.equal(terminal.bracketedPasteMode, true); @@ -120,7 +120,7 @@ describe('InputHandler', () => { it('insertChars', function(): void { const term = new Terminal(); const bufferService = new MockBufferService(80, 30); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(term, bufferService, new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); // insert some data in first and second line inputHandler.parse(Array(bufferService.cols - 9).join('a')); @@ -158,7 +158,7 @@ describe('InputHandler', () => { it('deleteChars', function(): void { const term = new Terminal(); const bufferService = new MockBufferService(80, 30); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(term, bufferService, new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); // insert some data in first and second line inputHandler.parse(Array(bufferService.cols - 9).join('a')); @@ -199,7 +199,7 @@ describe('InputHandler', () => { it('eraseInLine', function(): void { const term = new Terminal(); const bufferService = new MockBufferService(80, 30); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(term, bufferService, new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); // fill 6 lines to test 3 different states inputHandler.parse(Array(bufferService.cols + 1).join('a')); @@ -228,7 +228,7 @@ describe('InputHandler', () => { it('eraseInDisplay', function(): void { const term = new Terminal({cols: 80, rows: 7}); const bufferService = new MockBufferService(80, 7); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(term, bufferService, new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); // fill display with a's for (let i = 0; i < bufferService.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a')); @@ -363,7 +363,7 @@ describe('InputHandler', () => { describe('print', () => { it('should not cause an infinite loop (regression test)', () => { const term = new Terminal(); - const inputHandler = new InputHandler(term, new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + const inputHandler = new InputHandler(term, new MockBufferService(80, 30), new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); const container = new Uint32Array(10); container[0] = 0x200B; inputHandler.print(container, 0, 1); @@ -378,7 +378,7 @@ describe('InputHandler', () => { beforeEach(() => { term = new Terminal(); bufferService = new MockBufferService(80, 30); - handler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); + handler = new InputHandler(term, bufferService, new MockCharsetService(), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService(), new MockCoreMouseService()); }); it('should handle DECSET/DECRST 47 (alt screen buffer)', () => { handler.parse('\x1b[?47h\r\n\x1b[31mJUNK\x1b[?47lTEST'); diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 1c9e65747..79c769c7c 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -19,7 +19,7 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content import { CellData } from 'common/buffer/CellData'; import { AttributeData } from 'common/buffer/AttributeData'; import { IAttributeData, IDisposable } from 'common/Types'; -import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService } from 'common/services/Services'; +import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService, ICharsetService } from 'common/services/Services'; import { OscHandler } from 'common/parser/OscParser'; import { DcsHandler } from 'common/parser/DcsParser'; @@ -140,6 +140,7 @@ export class InputHandler extends Disposable implements IInputHandler { constructor( protected _terminal: IInputHandlingTerminal, private readonly _bufferService: IBufferService, + private readonly _charsetService: ICharsetService, private readonly _coreService: ICoreService, private readonly _dirtyRowService: IDirtyRowService, private readonly _logService: ILogService, @@ -381,7 +382,7 @@ export class InputHandler extends Disposable implements IInputHandler { let code: number; let chWidth: number; const buffer = this._bufferService.buffer; - const charset = this._coreService.charsetModes.charset; + const charset = this._charsetService.charset; const screenReaderMode = this._optionsService.options.screenReaderMode; const cols = this._bufferService.cols; const wraparoundMode = this._terminal.wraparoundMode; @@ -608,7 +609,7 @@ export class InputHandler extends Disposable implements IInputHandler { * G1 character set. */ public shiftOut(): void { - this._coreService.setgLevel(1); + this._charsetService.setgLevel(1); } /** @@ -617,7 +618,7 @@ export class InputHandler extends Disposable implements IInputHandler { * character set (the default). */ public shiftIn(): void { - this._coreService.setgLevel(0); + this._charsetService.setgLevel(0); } /** @@ -1396,10 +1397,10 @@ export class InputHandler extends Disposable implements IInputHandler { this._coreService.decPrivateModes.applicationCursorKeys = true; break; case 2: - this._coreService.setgCharset(0, DEFAULT_CHARSET); - this._coreService.setgCharset(1, DEFAULT_CHARSET); - this._coreService.setgCharset(2, DEFAULT_CHARSET); - this._coreService.setgCharset(3, DEFAULT_CHARSET); + this._charsetService.setgCharset(0, DEFAULT_CHARSET); + this._charsetService.setgCharset(1, DEFAULT_CHARSET); + this._charsetService.setgCharset(2, DEFAULT_CHARSET); + this._charsetService.setgCharset(3, DEFAULT_CHARSET); // set VT100 mode here break; case 3: // 132 col mode @@ -1974,7 +1975,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._bufferService.buffer.scrollBottom = this._bufferService.rows - 1; this._terminal.curAttrData = DEFAULT_ATTR_DATA.clone(); this._bufferService.buffer.x = this._bufferService.buffer.y = 0; // ? - this._coreService.softReset(); + this._charsetService.reset(); } /** @@ -2038,7 +2039,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._bufferService.buffer.savedY = this._bufferService.buffer.ybase + this._bufferService.buffer.y; this._bufferService.buffer.savedCurAttrData.fg = this._terminal.curAttrData.fg; this._bufferService.buffer.savedCurAttrData.bg = this._terminal.curAttrData.bg; - this._bufferService.buffer.savedCharset = this._coreService.charsetModes.charset; + this._bufferService.buffer.savedCharset = this._charsetService.charset; } @@ -2052,9 +2053,9 @@ export class InputHandler extends Disposable implements IInputHandler { this._bufferService.buffer.y = Math.max(this._bufferService.buffer.savedY - this._bufferService.buffer.ybase, 0); this._terminal.curAttrData.fg = this._bufferService.buffer.savedCurAttrData.fg; this._terminal.curAttrData.bg = this._bufferService.buffer.savedCurAttrData.bg; - this._coreService.charsetModes.charset = (this as any)._savedCharset; + this._charsetService.charset = (this as any)._savedCharset; if (this._bufferService.buffer.savedCharset) { - this._coreService.charsetModes.charset = this._bufferService.buffer.savedCharset; + this._charsetService.charset = this._bufferService.buffer.savedCharset; } this._restrictCursor(); } @@ -2113,8 +2114,8 @@ export class InputHandler extends Disposable implements IInputHandler { * therefore ESC % G does the same. */ public selectDefaultCharset(): void { - this._coreService.setgLevel(0); - this._coreService.setgCharset(0, DEFAULT_CHARSET); // US (default) + this._charsetService.setgLevel(0); + this._charsetService.setgCharset(0, DEFAULT_CHARSET); // US (default) } /** @@ -2141,7 +2142,7 @@ export class InputHandler extends Disposable implements IInputHandler { if (collectAndFlag[0] === '/') { return; // TODO: Is this supported? } - this._coreService.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] || DEFAULT_CHARSET); + this._charsetService.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] || DEFAULT_CHARSET); return; } @@ -2220,7 +2221,7 @@ export class InputHandler extends Disposable implements IInputHandler { * you use another locking shift. (partly supported) */ public setgLevel(level: number): void { - this._coreService.setgLevel(level); + this._charsetService.setgLevel(level); } /** diff --git a/src/Terminal.ts b/src/Terminal.ts index eb199ea11..2de11f8d0 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -46,7 +46,7 @@ import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { handleWindowsModeLineFeed } from 'common/WindowsMode'; import { ColorManager } from 'browser/ColorManager'; import { RenderService } from 'browser/services/RenderService'; -import { IOptionsService, IBufferService, ICoreMouseService, ICoreService, ILogService, IDirtyRowService, IInstantiationService } from 'common/services/Services'; +import { IOptionsService, IBufferService, ICoreMouseService, ICoreService, ILogService, IDirtyRowService, IInstantiationService, ICharsetService } from 'common/services/Services'; import { OptionsService } from 'common/services/OptionsService'; import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService, ICoreBrowserService } from 'browser/services/Services'; import { CharSizeService } from 'browser/services/CharSizeService'; @@ -64,6 +64,7 @@ import { InstantiationService } from 'common/services/InstantiationService'; import { CoreMouseService } from 'common/services/CoreMouseService'; import { WriteBuffer } from 'common/input/WriteBuffer'; import { CoreBrowserService } from 'browser/services/CoreBrowserService'; +import { CharsetService } from 'common/services/CharsetService'; // Let it work inside Node.js for automated testing purposes. const document = (typeof window !== 'undefined') ? window.document : null; @@ -96,6 +97,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // common services private _bufferService: IBufferService; private _coreService: ICoreService; + private _charsetService: ICharsetService; private _coreMouseService: ICoreMouseService; private _dirtyRowService: IDirtyRowService; private _instantiationService: IInstantiationService; @@ -221,6 +223,8 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._instantiationService.setService(ICoreMouseService, this._coreMouseService); this._dirtyRowService = this._instantiationService.createInstance(DirtyRowService); this._instantiationService.setService(IDirtyRowService, this._dirtyRowService); + this._charsetService = this._instantiationService.createInstance(CharsetService); + this._instantiationService.setService(ICharsetService, this._charsetService); this._setupOptionsListeners(); this._setup(); @@ -254,7 +258,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this.bracketedPasteMode = false; // charset - this._coreService.softReset(); + this._charsetService.reset(); this.curAttrData = DEFAULT_ATTR_DATA.clone(); this._eraseAttrData = DEFAULT_ATTR_DATA.clone(); @@ -265,7 +269,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._userScrolling = false; // Register input handler and refire/handle events - this._inputHandler = new InputHandler(this, this._bufferService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService); + this._inputHandler = new InputHandler(this, this._bufferService, this._charsetService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService); this._inputHandler.onRequestRefreshRows((start, end) => this.refresh(start, end)); this._inputHandler.onCursorMove(() => this._onCursorMove.fire()); this._inputHandler.onLineFeed(() => this._onLineFeed.fire()); diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 96027804c..11bb84bce 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -3,13 +3,13 @@ * @license MIT */ -import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IPartialTerminalOptions, IDirtyRowService, ICoreMouseService } from 'common/services/Services'; +import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IPartialTerminalOptions, IDirtyRowService, ICoreMouseService, ICharsetService } from 'common/services/Services'; import { IEvent, EventEmitter } from 'common/EventEmitter'; 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, ICharsetModes, ICharset } from 'common/Types'; +import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset } from 'common/Types'; export class MockBufferService implements IBufferService { serviceBrand: any; @@ -42,24 +42,26 @@ export class MockCoreMouseService implements ICoreMouseService { } } +export class MockCharsetService implements ICharsetService { + serviceBrand: any; + charset: ICharset | undefined; + glevel: number = 0; + charsets: readonly ICharset[] = []; + reset(): void {} + setgLevel(g: number): void {} + setgCharset(g: number, charset: ICharset): void {} +} + export class MockCoreService implements ICoreService { + serviceBrand: any; isCursorInitialized: boolean = false; isCursorHidden: boolean = false; isFocused: boolean = false; - serviceBrand: any; - charsetModes: ICharsetModes = { - charset: undefined, - charsets: [], - glevel: 0 - }; decPrivateModes: IDecPrivateModes = {} as any; onData: IEvent = new EventEmitter().event; onUserInput: IEvent = new EventEmitter().event; onBinary: IEvent = new EventEmitter().event; reset(): void {} - softReset(): void {} - setgLevel(g: number): void {} - setgCharset(g: number, charset: ICharset): void {} triggerDataEvent(data: string, wasUserInput?: boolean): void {} triggerBinaryEvent(data: string): void {} } diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index b8cb9b802..35567dee7 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -62,13 +62,7 @@ export interface IKeyboardResult { } export interface ICharset { - [key: string]: string; -} - -export interface ICharsetModes { - charset: ICharset | undefined; - glevel: number; - charsets: ICharset[]; + [key: string]: string | undefined; } export type CharData = [number, string, number, number]; diff --git a/src/common/services/CharsetService.ts b/src/common/services/CharsetService.ts new file mode 100644 index 000000000..5d20628f3 --- /dev/null +++ b/src/common/services/CharsetService.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ICharsetService } from 'common/services/Services'; +import { ICharset } from 'common/Types'; + +export class CharsetService implements ICharsetService { + serviceBrand: any; + + public charset: ICharset | undefined; + public charsets: ICharset[] = []; + public glevel: number = 0; + + public reset(): void { + this.charset = undefined; + this.charsets = []; + this.glevel = 0; + } + + public setgLevel(g: number): void { + this.glevel = g; + this.charset = this.charsets[g]; + } + + public setgCharset(g: number, charset: ICharset): void { + this.charsets[g] = charset; + if (this.glevel === g) { + this.charset = charset; + } + } +} diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index af0d5f63e..58552f3f7 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -5,7 +5,7 @@ import { ICoreService, ILogService, IOptionsService, IBufferService } from 'common/services/Services'; import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { IDecPrivateModes, ICharset, ICharsetModes } from 'common/Types'; +import { IDecPrivateModes, ICharset } from 'common/Types'; import { clone } from 'common/Clone'; const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({ @@ -18,11 +18,6 @@ export class CoreService implements ICoreService { public isCursorInitialized: boolean = false; public isCursorHidden: boolean = false; public decPrivateModes: IDecPrivateModes; - public charsetModes: ICharsetModes = { - charset: undefined, - charsets: [], - glevel: 0 - }; private _onData = new EventEmitter(); public get onData(): IEvent { return this._onData.event; } @@ -45,12 +40,6 @@ export class CoreService implements ICoreService { this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES); } - public softReset(): void { - this.charsetModes.charset = undefined; - this.charsetModes.charsets = []; - this.charsetModes.glevel = 0; - } - public triggerDataEvent(data: string, wasUserInput: boolean = false): void { // Prevents all events to pty process if stdin is disabled if (this._optionsService.options.disableStdin) { @@ -80,16 +69,4 @@ export class CoreService implements ICoreService { this._logService.debug(`sending binary "${data}"`, () => data.split('').map(e => e.charCodeAt(0))); this._onBinary.fire(data); } - - public setgLevel(g: number): void { - this.charsetModes.glevel = g; - this.charsetModes.charset = this.charsetModes.charsets[g]; - } - - public setgCharset(g: number, charset: ICharset): void { - this.charsetModes.charsets[g] = charset; - if (this.charsetModes.glevel === g) { - this.charsetModes.charset = charset; - } - } } diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 9e47be263..32274f5e9 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -5,7 +5,7 @@ import { IEvent } from 'common/EventEmitter'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharsetModes, ICharset } from 'common/Types'; +import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharset } from 'common/Types'; import { createDecorator } from 'common/services/ServiceRegistry'; export const IBufferService = createDecorator('BufferService'); @@ -65,8 +65,6 @@ export interface ICoreService { isCursorInitialized: boolean; isCursorHidden: boolean; - charsetModes: ICharsetModes; - readonly decPrivateModes: IDecPrivateModes; readonly onData: IEvent; @@ -74,7 +72,6 @@ export interface ICoreService { readonly onBinary: IEvent; reset(): void; - softReset(): void; /** * Triggers the onData event in the public API. @@ -91,6 +88,17 @@ export interface ICoreService { * @param data The data that is being emitted. */ triggerBinaryEvent(data: string): void; +} + +export const ICharsetService = createDecorator('CharsetService'); +export interface ICharsetService { + serviceBrand: any; + + charset: ICharset | undefined; + readonly glevel: number; + readonly charsets: ReadonlyArray; + + reset(): void; /** * Set the G level of the terminal.