xterm
[VSoRC/.git] / node_modules / xterm / src / common / buffer / CellData.ts
1 /**
2  * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3  * @license MIT
4  */
5
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';
10
11 /**
12  * CellData - represents a single Cell in the terminal buffer.
13  */
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);
19     return obj;
20   }
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;
29   }
30   /** Width of the cell. */
31   public getWidth(): number {
32     return this.content >> Content.WIDTH_SHIFT;
33   }
34   /** JS string of the content. */
35   public getChars(): string {
36     if (this.content & Content.IS_COMBINED_MASK) {
37       return this.combinedData;
38     }
39     if (this.content & Content.CODEPOINT_MASK) {
40       return stringFromCodePoint(this.content & Content.CODEPOINT_MASK);
41     }
42     return '';
43   }
44   /**
45    * Codepoint of cell
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.
49    * */
50   public getCode(): number {
51     return (this.isCombined())
52       ? this.combinedData.charCodeAt(this.combinedData.length - 1)
53       : this.content & Content.CODEPOINT_MASK;
54   }
55   /** Set data from CharData */
56   public setFromCharData(value: CharData): void {
57     this.fg = value[CHAR_DATA_ATTR_INDEX];
58     this.bg = 0;
59     let combined = false;
60     // surrogates and combined strings need special treatment
61     if (value[CHAR_DATA_CHAR_INDEX].length > 2) {
62       combined = true;
63     }
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);
72         }
73         else {
74           combined = true;
75         }
76       }
77       else {
78         combined = true;
79       }
80     }
81     else {
82       this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
83     }
84     if (combined) {
85       this.combinedData = value[CHAR_DATA_CHAR_INDEX];
86       this.content = Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
87     }
88   }
89   /** Get data as CharData. */
90   public getAsCharData(): CharData {
91     return [this.fg, this.getChars(), this.getWidth(), this.getCode()];
92   }
93 }