diff --git a/src/Terminal.ts b/src/Terminal.ts index 19fd2a885..6192beec5 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -43,13 +43,12 @@ import { IKeyboardEvent, KeyboardResultType, IBufferLine, IAttributeData, CoreMo import { evaluateKeyboardEvent } from 'common/input/Keyboard'; import { EventEmitter, IEvent } from 'common/EventEmitter'; import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { updateWindowsModeWrappedState } from 'common/WindowsMode'; import { ColorManager } from 'browser/ColorManager'; import { RenderService } from 'browser/services/RenderService'; import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService, ICoreBrowserService } from 'browser/services/Services'; import { CharSizeService } from 'browser/services/CharSizeService'; import { MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; -import { IBufferSet, IBuffer } from 'common/buffer/Types'; +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'; @@ -119,7 +118,6 @@ export class Terminal extends CoreTerminal implements ITerminal, IInputHandlingT private _accessibilityManager: AccessibilityManager; private _colorManager: ColorManager; private _theme: ITheme; - private _windowsMode: IDisposable | undefined; // bufferline to clone/copy from for new blank lines private _blankLine: IBufferLine = null; @@ -128,8 +126,6 @@ export class Terminal extends CoreTerminal implements ITerminal, IInputHandlingT public get onCursorMove(): IEvent { return this._onCursorMove.event; } private _onKey = new EventEmitter<{ key: string, domEvent: KeyboardEvent }>(); public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> { return this._onKey.event; } - private _onLineFeed = new EventEmitter(); - public get onLineFeed(): IEvent { return this._onLineFeed.event; } private _onRender = new EventEmitter<{ start: number, end: number }>(); public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; } private _onResize = new EventEmitter<{ cols: number, rows: number }>(); @@ -167,7 +163,6 @@ export class Terminal extends CoreTerminal implements ITerminal, IInputHandlingT ) { super(options); - this._setupOptionsListeners(); this._setup(); this._writeBuffer = new WriteBuffer(data => this._inputHandler.parse(data)); @@ -220,22 +215,6 @@ export class Terminal extends CoreTerminal implements ITerminal, IInputHandlingT } } - private _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()); - } - }; - } - } - /** * Convenience property to active buffer. */ @@ -243,10 +222,6 @@ export class Terminal extends CoreTerminal implements ITerminal, IInputHandlingT return this.buffers.active; } - public get buffers(): IBufferSet { - return this._bufferService.buffers; - } - /** * Focus the terminal. Delegates focus handling to the terminal's DOM element. */ @@ -256,68 +231,59 @@ export class Terminal extends CoreTerminal implements ITerminal, IInputHandlingT } } - private _setupOptionsListeners(): void { + protected _updateOptions(key: string): void { + super._updateOptions(key); + // TODO: These listeners should be owned by individual components - this.optionsService.onOptionChange(key => { - switch (key) { - case 'fontFamily': - case 'fontSize': - // When the font changes the size of the cells may change which requires a renderer clear - this._renderService?.clear(); - this._charSizeService?.measure(); - break; - case 'cursorBlink': - case 'cursorStyle': - // The DOM renderer needs a row refresh to update the cursor styles - this.refresh(this.buffer.y, this.buffer.y); - break; - case 'drawBoldTextInBrightColors': - case 'letterSpacing': - case 'lineHeight': - case 'fontWeight': - case 'fontWeightBold': - case 'minimumContrastRatio': - // When the font changes the size of the cells may change which requires a renderer clear - if (this._renderService) { - this._renderService.clear(); - this._renderService.onResize(this.cols, this.rows); - this.refresh(0, this.rows - 1); + switch (key) { + case 'fontFamily': + case 'fontSize': + // When the font changes the size of the cells may change which requires a renderer clear + this._renderService?.clear(); + this._charSizeService?.measure(); + break; + case 'cursorBlink': + case 'cursorStyle': + // The DOM renderer needs a row refresh to update the cursor styles + this.refresh(this.buffer.y, this.buffer.y); + break; + case 'drawBoldTextInBrightColors': + case 'letterSpacing': + case 'lineHeight': + case 'fontWeight': + case 'fontWeightBold': + case 'minimumContrastRatio': + // When the font changes the size of the cells may change which requires a renderer clear + if (this._renderService) { + this._renderService.clear(); + this._renderService.onResize(this.cols, this.rows); + this.refresh(0, this.rows - 1); + } + break; + case 'rendererType': + if (this._renderService) { + this._renderService.setRenderer(this._createRenderer()); + this._renderService.onResize(this.cols, this.rows); + } + break; + case 'scrollback': + this.viewport?.syncScrollArea(); + break; + case 'screenReaderMode': + if (this.optionsService.options.screenReaderMode) { + if (!this._accessibilityManager && this._renderService) { + this._accessibilityManager = new AccessibilityManager(this, this._renderService); } - break; - case 'rendererType': - if (this._renderService) { - this._renderService.setRenderer(this._createRenderer()); - this._renderService.onResize(this.cols, this.rows); - } - break; - case 'scrollback': - this.buffers.resize(this.cols, this.rows); - this.viewport?.syncScrollArea(); - break; - case 'screenReaderMode': - if (this.optionsService.options.screenReaderMode) { - if (!this._accessibilityManager && this._renderService) { - this._accessibilityManager = new AccessibilityManager(this, this._renderService); - } - } else { - this._accessibilityManager?.dispose(); - this._accessibilityManager = null; - } - break; - case 'tabStopWidth': this.buffers.setupTabStops(); break; - case 'theme': - this._setTheme(this.optionsService.options.theme); - break; - case 'windowsMode': - if (this.optionsService.options.windowsMode) { - this._enableWindowsMode(); - } else { - this._windowsMode?.dispose(); - this._windowsMode = undefined; - } - break; - } - }); + } else { + this._accessibilityManager?.dispose(); + this._accessibilityManager = null; + } + break; + case 'tabStopWidth': this.buffers.setupTabStops(); break; + case 'theme': + this._setTheme(this.optionsService.options.theme); + break; + } } /** diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index dfffa1d40..7a8f5bffe 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -27,13 +27,16 @@ import { InstantiationService } from 'common/services/InstantiationService'; import { LogService } from 'common/services/LogService'; import { BufferService } from 'common/services/BufferService'; import { OptionsService } from 'common/services/OptionsService'; -import { ITerminalOptions } from './Types'; +import { ITerminalOptions, IDisposable } from './Types'; import { CoreService } from 'common/services/CoreService'; import { EventEmitter, IEvent } 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'; export abstract class CoreTerminal extends Disposable { protected readonly _instantiationService: IInstantiationService; @@ -47,10 +50,18 @@ export abstract class CoreTerminal extends Disposable { public readonly unicodeService: IUnicodeService; public readonly optionsService: IOptionsService; - private _onData = new EventEmitter(); - public get onData(): IEvent { return this._onData.event; } + protected _windowsMode: IDisposable | undefined; + private _onBinary = new EventEmitter(); public get onBinary(): IEvent { return this._onBinary.event; } + private _onData = new EventEmitter(); + public get onData(): IEvent { return this._onData.event; } + protected _onLineFeed = new EventEmitter(); + public get onLineFeed(): IEvent { return this._onLineFeed.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 @@ -67,8 +78,6 @@ export abstract class CoreTerminal extends Disposable { this._instantiationService.setService(ILogService, this._logService); this._coreService = this._instantiationService.createInstance(CoreService, () => this.scrollToBottom()); this._instantiationService.setService(ICoreService, this._coreService); - this._coreService.onData(e => this._onData.fire(e)); - this._coreService.onBinary(e => this._onBinary.fire(e)); this._coreMouseService = this._instantiationService.createInstance(CoreMouseService); this._instantiationService.setService(ICoreMouseService, this._coreMouseService); this._dirtyRowService = this._instantiationService.createInstance(DirtyRowService); @@ -77,10 +86,46 @@ export abstract class CoreTerminal extends Disposable { this._instantiationService.setService(IUnicodeService, this.unicodeService); this._charsetService = this._instantiationService.createInstance(CharsetService); this._instantiationService.setService(ICharsetService, this._charsetService); + + // Setup listeners + this._coreService.onData(e => this._onData.fire(e)); + this._coreService.onBinary(e => this._onBinary.fire(e)); + this.optionsService.onOptionChange(key => this._updateOptions(key)); } - public get cols(): number { return this._bufferService.cols; } - public get rows(): number { return this._bufferService.rows; } + 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()); + } + }; + } + } public abstract scrollToBottom(): void; + public abstract addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; }