2 * Copyright (c) 2018 The xterm.js authors. All rights reserved.
6 import { CharData, ICellData } from 'common/Types';
7 import { stringFromCodePoint } from 'common/input/TextDecoder';
8 import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, Content } from 'common/buffer/Constants';
9 import { AttributeData } from 'common/buffer/AttributeData';
12 * CellData - represents a single Cell in the terminal buffer.
14 export class CellData extends AttributeData implements ICellData {
15 /** Helper to create CellData from CharData. */
16 public static fromCharData(value: CharData): CellData {
17 const obj = new CellData();
18 obj.setFromCharData(value);
21 /** Primitives from terminal buffer. */
22 public content: number = 0;
23 public fg: number = 0;
24 public bg: number = 0;
25 public combinedData: string = '';
26 /** Whether cell contains a combined string. */
27 public isCombined(): number {
28 return this.content & Content.IS_COMBINED_MASK;
30 /** Width of the cell. */
31 public getWidth(): number {
32 return this.content >> Content.WIDTH_SHIFT;
34 /** JS string of the content. */
35 public getChars(): string {
36 if (this.content & Content.IS_COMBINED_MASK) {
37 return this.combinedData;
39 if (this.content & Content.CODEPOINT_MASK) {
40 return stringFromCodePoint(this.content & Content.CODEPOINT_MASK);
46 * Note this returns the UTF32 codepoint of single chars,
47 * if content is a combined string it returns the codepoint
48 * of the last char in string to be in line with code in CharData.
50 public getCode(): number {
51 return (this.isCombined())
52 ? this.combinedData.charCodeAt(this.combinedData.length - 1)
53 : this.content & Content.CODEPOINT_MASK;
55 /** Set data from CharData */
56 public setFromCharData(value: CharData): void {
57 this.fg = value[CHAR_DATA_ATTR_INDEX];
60 // surrogates and combined strings need special treatment
61 if (value[CHAR_DATA_CHAR_INDEX].length > 2) {
64 else if (value[CHAR_DATA_CHAR_INDEX].length === 2) {
65 const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0);
66 // if the 2-char string is a surrogate create single codepoint
67 // everything else is combined
68 if (0xD800 <= code && code <= 0xDBFF) {
69 const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1);
70 if (0xDC00 <= second && second <= 0xDFFF) {
71 this.content = ((code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
82 this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
85 this.combinedData = value[CHAR_DATA_CHAR_INDEX];
86 this.content = Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
89 /** Get data as CharData. */
90 public getAsCharData(): CharData {
91 return [this.fg, this.getChars(), this.getWidth(), this.getCode()];