From 802543f7cf2a593be079a5d9e782bb07ac6c526b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Fri, 4 Jan 2019 02:58:15 +0100 Subject: [PATCH] replace set(CharData) with setCell --- src/BufferLine.ts | 78 ++++++++++++++++++++++++++++----------------- src/InputHandler.ts | 10 +++--- src/Types.ts | 16 +++++++++- 3 files changed, 68 insertions(+), 36 deletions(-) diff --git a/src/BufferLine.ts b/src/BufferLine.ts index 1700279c0..827e7c939 100644 --- a/src/BufferLine.ts +++ b/src/BufferLine.ts @@ -2,7 +2,7 @@ * Copyright (c) 2018 The xterm.js authors. All rights reserved. * @license MIT */ -import { CharData, IBufferLine } from './Types'; +import { CharData, IBufferLine, ICellData } from './Types'; import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, WHITESPACE_CELL_CHAR, CHAR_DATA_ATTR_INDEX } from './Buffer'; import { stringFromCodePoint } from './core/input/TextDecoder'; @@ -76,7 +76,7 @@ export const enum Content { WIDTH_SHIFT = 22 } -export class CellData { +export class CellData implements ICellData { public content: number = 0; public fg: number = 0; public bg: number = 0; @@ -93,6 +93,31 @@ export class CellData { public get code(): number { return ((this.combined) ? this.combinedData.charCodeAt(this.combinedData.length - 1) : this.content & Content.CODEPOINT_MASK); } + public setFromCharData(value: CharData): void { + this.fg = value[CHAR_DATA_ATTR_INDEX]; + this.bg = 0; + let combined = false; + if (value[CHAR_DATA_CHAR_INDEX].length > 2) { + combined = true; + } else if (value[CHAR_DATA_CHAR_INDEX].length === 2) { + const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0); + if (0xD800 <= code && code <= 0xDBFF) { + const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1); + if (0xDC00 <= second && second <= 0xDFFF) { + this.content = ((code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); + } else { + combined = true; + } + } + combined = true; + } else { + this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); + } + if (combined) { + this.combinedData = value[CHAR_DATA_CHAR_INDEX]; + this.content = Content.IS_COMBINED | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); + } + } } /** @@ -101,16 +126,15 @@ export class CellData { export class BufferLine implements IBufferLine { protected _data: Uint32Array | null = null; protected _combined: {[index: number]: string} = {}; + protected _cell: CellData = new CellData(); public length: number; constructor(cols: number, fillCharData?: CharData, public isWrapped: boolean = false) { - if (!fillCharData) { - fillCharData = [0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]; - } if (cols) { this._data = new Uint32Array(cols * CELL_SIZE); + this._cell.setFromCharData(fillCharData || [0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]); for (let i = 0; i < cols; ++i) { - this.set(i, fillCharData); + this.setCell(i, this._cell); } } this.length = cols; @@ -141,7 +165,7 @@ export class BufferLine implements IBufferLine { } } - public loadCell(index: number, cell: CellData): CellData { + public loadCell(index: number, cell: ICellData): ICellData { cell.content = this._data[index * CELL_SIZE + Cell.CONTENT]; cell.fg = this._data[index * CELL_SIZE + Cell.FG]; cell.bg = this._data[index * CELL_SIZE + Cell.BG]; @@ -151,7 +175,7 @@ export class BufferLine implements IBufferLine { return cell; } - public setCell(index: number, cell: CellData): void { + public setCell(index: number, cell: ICellData): void { if (cell.content & Content.IS_COMBINED) { this._combined[index] = cell.combinedData; // we also need to clear and set codepoint to index @@ -203,31 +227,20 @@ export class BufferLine implements IBufferLine { } } - /** - * Set data from another buffer cell. - * Useful for basic in buffer copy action. - */ - public setDataFromCellData(index: number, content: number, fg: number, bg: number, combined?: string): void { - this._data[index * CELL_SIZE + Cell.CONTENT] = content; - this._data[index * CELL_SIZE + Cell.FG] = fg; - this._data[index * CELL_SIZE + Cell.BG] = bg; - if (content & Content.IS_COMBINED && combined) { - this._combined[index] = combined; - } - } - public insertCells(pos: number, n: number, fillCharData: CharData): void { pos %= this.length; if (n < this.length - pos) { for (let i = this.length - pos - n - 1; i >= 0; --i) { - this.set(pos + n + i, this.get(pos + i)); + this.setCell(pos + n + i, this.loadCell(pos + i, this._cell)); } + this._cell.setFromCharData(fillCharData); for (let i = 0; i < n; ++i) { - this.set(pos + i, fillCharData); + this.setCell(pos + i, this._cell); } } else { + this._cell.setFromCharData(fillCharData); for (let i = pos; i < this.length; ++i) { - this.set(i, fillCharData); + this.setCell(i, this._cell); } } } @@ -236,21 +249,24 @@ export class BufferLine implements IBufferLine { pos %= this.length; if (n < this.length - pos) { for (let i = 0; i < this.length - pos - n; ++i) { - this.set(pos + i, this.get(pos + n + i)); + this.setCell(pos + i, this.loadCell(pos + n + i, this._cell)); } + this._cell.setFromCharData(fillCharData); for (let i = this.length - n; i < this.length; ++i) { - this.set(i, fillCharData); + this.setCell(i, this._cell); } } else { + this._cell.setFromCharData(fillCharData); for (let i = pos; i < this.length; ++i) { - this.set(i, fillCharData); + this.setCell(i, this._cell); } } } public replaceCells(start: number, end: number, fillCharData: CharData): void { + this._cell.setFromCharData(fillCharData); while (start < end && start < this.length) { - this.set(start++, fillCharData); + this.setCell(start++, this._cell); } } @@ -268,8 +284,9 @@ export class BufferLine implements IBufferLine { } } this._data = data; + this._cell.setFromCharData(fillCharData); for (let i = this.length; i < cols; ++i) { - this.set(i, fillCharData); + this.setCell(i, this._cell); } } else if (shrink) { if (cols) { @@ -286,8 +303,9 @@ export class BufferLine implements IBufferLine { /** fill a line with fillCharData */ public fill(fillCharData: CharData): void { this._combined = {}; + this._cell.setFromCharData(fillCharData); for (let i = 0; i < this.length; ++i) { - this.set(i, fillCharData); + this.setCell(i, this._cell); } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 7cc2b8b61..f837f2957 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -7,7 +7,7 @@ import { IInputHandler, IDcsHandler, IEscapeSequenceParser, IBuffer, IInputHandlingTerminal } from './Types'; import { C0, C1 } from './common/data/EscapeSequences'; import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets'; -import { CHAR_DATA_WIDTH_INDEX, DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Buffer'; +import { DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Buffer'; import { FLAGS } from './renderer/Types'; import { wcwidth } from './CharWidth'; import { EscapeSequenceParser } from './EscapeSequenceParser'; @@ -16,6 +16,7 @@ import { IDisposable } from 'xterm'; import { Disposable } from './common/Lifecycle'; import { concat, utf32ToString } from './common/TypedArrayUtils'; import { StringToUtf32, stringFromCodePoint } from './core/input/TextDecoder'; +import { CellData } from './BufferLine'; /** * Map collect to glevel. Used in `selectCharset`. @@ -121,6 +122,7 @@ class DECRQSS implements IDcsHandler { export class InputHandler extends Disposable implements IInputHandler { private _parseBuffer: Uint32Array = new Uint32Array(4096); private _stringDecoder: StringToUtf32 = new StringToUtf32(); + private _cell: CellData = new CellData(); constructor( protected _terminal: IInputHandlingTerminal, @@ -369,8 +371,7 @@ export class InputHandler extends Disposable implements IInputHandler { // since they always follow a cell consuming char // therefore we can test for buffer.x to avoid overflow left if (!chWidth && buffer.x) { - const chMinusOne = bufferRow.get(buffer.x - 1); - if (!chMinusOne[CHAR_DATA_WIDTH_INDEX]) { + if (!bufferRow.loadCell(buffer.x - 1, this._cell).width) { // found empty cell after fullwidth, need to go 2 cells back // it is save to step 2 cells back here // since an empty cell is only set by fullwidth chars @@ -419,8 +420,7 @@ export class InputHandler extends Disposable implements IInputHandler { // test last cell - since the last cell has only room for // a halfwidth char any fullwidth shifted there is lost // and will be set to eraseChar - const lastCell = bufferRow.get(cols - 1); - if (lastCell[CHAR_DATA_WIDTH_INDEX] === 2) { + if (bufferRow.loadCell(cols - 1, this._cell).width === 2) { bufferRow.setDataFromCodePoint(cols - 1, NULL_CELL_CODE, NULL_CELL_WIDTH, curAttr, 0); } } diff --git a/src/Types.ts b/src/Types.ts index b89d5422d..180fe0009 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -511,6 +511,19 @@ export interface IEscapeSequenceParser extends IDisposable { clearErrorHandler(): void; } +/** Cell data */ +export interface ICellData { + content: number; + fg: number; + bg: number; + combinedData: string; + combined: number; + width: number; + chars: string; + code: number; + setFromCharData(value: CharData): void; +} + /** * Interface for a line in the terminal buffer. */ @@ -519,9 +532,10 @@ export interface IBufferLine { isWrapped: boolean; get(index: number): CharData; set(index: number, value: CharData): void; + loadCell(index: number, cell: ICellData): ICellData; + setCell(index: number, cell: ICellData): void; setDataFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number): void; addCharToCell(index: number, codePoint: number): void; - setDataFromCellData(index: number, content: number, fg: number, bg: number, combined?: string): void; insertCells(pos: number, n: number, ch: CharData): void; deleteCells(pos: number, n: number, fill: CharData): void; replaceCells(start: number, end: number, fill: CharData): void;