From d7ea0edfcf27fdd3e37963b041fc647d035b0b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 20 Jan 2019 22:19:50 +0100 Subject: [PATCH] add utf8 input to terminal --- src/InputHandler.ts | 33 ++++++++++++++++++++++++++++++--- src/Terminal.ts | 17 +++++++++++++++++ src/Types.ts | 1 + src/public/Terminal.ts | 3 +++ src/ui/TestUtils.test.ts | 3 +++ typings/xterm.d.ts | 6 ++++++ 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index c41b4165..70491027 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -15,7 +15,7 @@ import { ICharset } from './core/Types'; import { IDisposable } from 'xterm'; import { Disposable } from './common/Lifecycle'; import { concat, utf32ToString } from './common/TypedArrayUtils'; -import { StringToUtf32, stringFromCodePoint } from './core/input/TextDecoder'; +import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32 } from './core/input/TextDecoder'; import { CellData } from './BufferLine'; /** @@ -104,8 +104,9 @@ class DECRQSS implements IDcsHandler { * each function's header comment. */ export class InputHandler extends Disposable implements IInputHandler { - private _parseBuffer: Uint32Array = new Uint32Array(4096); - private _stringDecoder: StringToUtf32 = new StringToUtf32(); + private _parseBuffer = new Uint32Array(4096); + private _stringDecoder = new StringToUtf32(); + private _utf8Decoder = new Utf8ToUtf32(); private _cell: CellData = new CellData(); constructor( @@ -311,6 +312,32 @@ export class InputHandler extends Disposable implements IInputHandler { } } + public parseUtf8(data: Uint8Array): void { + // Ensure the terminal is not disposed + if (!this._terminal) { + return; + } + + let buffer = this._terminal.buffer; + const cursorStartX = buffer.x; + const cursorStartY = buffer.y; + + // TODO: Consolidate debug/logging #1560 + if ((this._terminal).debug) { + this._terminal.log('data: ' + data); + } + + if (this._parseBuffer.length < data.length) { + this._parseBuffer = new Uint32Array(data.length); + } + this._parser.parse(this._parseBuffer, this._utf8Decoder.decode(data, this._parseBuffer)); + + buffer = this._terminal.buffer; + if (buffer.x !== cursorStartX || buffer.y !== cursorStartY) { + this._terminal.emit('cursormove'); + } + } + public print(data: Uint32Array, start: number, end: number): void { let code: number; let chWidth: number; diff --git a/src/Terminal.ts b/src/Terminal.ts index 33d8e60f..e92ef08b 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1301,6 +1301,23 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II } } + /** + * Writes utf8 data to the terminal. + * TODO: This currently does no flow control. + */ + public writeUtf8(data: Uint8Array): void { + if (this._isDisposed) { + return; + } + this._refreshStart = this.buffer.y; + this._refreshEnd = this.buffer.y; + + this._inputHandler.parseUtf8(data); + + this.updateRange(this.buffer.y); + this.refresh(this._refreshStart, this._refreshEnd); + } + /** * Writes text to the terminal. * @param data The text to write to the terminal. diff --git a/src/Types.ts b/src/Types.ts index d176799f..186e2149 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -111,6 +111,7 @@ export interface ICompositionHelper { */ export interface IInputHandler { parse(data: string): void; + parseUtf8(data: Uint8Array): void; print(data: Uint32Array, start: number, end: number): void; /** C0 BEL */ bell(): void; diff --git a/src/public/Terminal.ts b/src/public/Terminal.ts index 87fcfaef..7e219e08 100644 --- a/src/public/Terminal.ts +++ b/src/public/Terminal.ts @@ -122,6 +122,9 @@ export class Terminal implements ITerminalApi { public write(data: string): void { this._core.write(data); } + public writeUtf8(data: Uint8Array): void { + this._core.writeUtf8(data); + } public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'rendererType' | 'termName'): string; public getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; public getOption(key: 'colors'): string[]; diff --git a/src/ui/TestUtils.test.ts b/src/ui/TestUtils.test.ts index 9d525fbf..13abee76 100644 --- a/src/ui/TestUtils.test.ts +++ b/src/ui/TestUtils.test.ts @@ -99,6 +99,9 @@ export class MockTerminal implements ITerminal { write(data: string): void { throw new Error('Method not implemented.'); } + writeUtf8(data: Uint8Array): void { + throw new Error('Method not implemented.'); + } bracketedPasteMode: boolean; mouseHelper: IMouseHelper; renderer: IRenderer; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 11fab909..ffaba90e 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -636,6 +636,12 @@ declare module 'xterm' { */ write(data: string): void; + /** + * Writes UTF8 data to the terminal. + * @param data The data to write to the terminal. + */ + writeUtf8(data: Uint8Array): void; + /** * Retrieves an option's value from the terminal. * @param key The option key.