xterm
[VSoRC/.git] / node_modules / xterm / src / browser / renderer / dom / DomRendererRowFactory.ts
1 /**
2  * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3  * @license MIT
4  */
5
6 import { IBufferLine } from 'common/Types';
7 import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
8 import { AttributeData } from 'common/buffer/AttributeData';
9 import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants';
10 import { CellData } from 'common/buffer/CellData';
11 import { IOptionsService } from 'common/services/Services';
12
13 export const BOLD_CLASS = 'xterm-bold';
14 export const DIM_CLASS = 'xterm-dim';
15 export const ITALIC_CLASS = 'xterm-italic';
16 export const UNDERLINE_CLASS = 'xterm-underline';
17 export const CURSOR_CLASS = 'xterm-cursor';
18 export const CURSOR_BLINK_CLASS = 'xterm-cursor-blink';
19 export const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block';
20 export const CURSOR_STYLE_BAR_CLASS = 'xterm-cursor-bar';
21 export const CURSOR_STYLE_UNDERLINE_CLASS = 'xterm-cursor-underline';
22
23 export class DomRendererRowFactory {
24   private _workCell: CellData = new CellData();
25
26   constructor(
27     private _document: Document,
28     private _optionsService: IOptionsService
29   ) {
30   }
31
32   public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number): DocumentFragment {
33     const fragment = this._document.createDocumentFragment();
34
35     // Find the line length first, this prevents the need to output a bunch of
36     // empty cells at the end. This cannot easily be integrated into the main
37     // loop below because of the colCount feature (which can be removed after we
38     // properly support reflow and disallow data to go beyond the right-side of
39     // the viewport).
40     let lineLength = 0;
41     for (let x = Math.min(lineData.length, cols) - 1; x >= 0; x--) {
42       if (lineData.loadCell(x, this._workCell).getCode() !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) {
43         lineLength = x + 1;
44         break;
45       }
46     }
47
48     for (let x = 0; x < lineLength; x++) {
49       lineData.loadCell(x, this._workCell);
50       const width = this._workCell.getWidth();
51
52       // The character to the left is a wide character, drawing is owned by the char at x-1
53       if (width === 0) {
54         continue;
55       }
56
57       const charElement = this._document.createElement('span');
58       if (width > 1) {
59         charElement.style.width = `${cellWidth * width}px`;
60       }
61
62       if (isCursorRow && x === cursorX) {
63         charElement.classList.add(CURSOR_CLASS);
64
65         if (cursorBlink) {
66           charElement.classList.add(CURSOR_BLINK_CLASS);
67         }
68
69         switch (cursorStyle) {
70           case 'bar':
71             charElement.classList.add(CURSOR_STYLE_BAR_CLASS);
72             break;
73           case 'underline':
74             charElement.classList.add(CURSOR_STYLE_UNDERLINE_CLASS);
75             break;
76           default:
77             charElement.classList.add(CURSOR_STYLE_BLOCK_CLASS);
78             break;
79         }
80       }
81
82       if (this._workCell.isBold()) {
83         charElement.classList.add(BOLD_CLASS);
84       }
85
86       if (this._workCell.isItalic()) {
87         charElement.classList.add(ITALIC_CLASS);
88       }
89
90       if (this._workCell.isDim()) {
91         charElement.classList.add(DIM_CLASS);
92       }
93
94       if (this._workCell.isUnderline()) {
95         charElement.classList.add(UNDERLINE_CLASS);
96       }
97
98       charElement.textContent = this._workCell.getChars() || WHITESPACE_CELL_CHAR;
99
100       const swapColor = this._workCell.isInverse();
101
102       // fg
103       if (this._workCell.isFgRGB()) {
104         let style = charElement.getAttribute('style') || '';
105         style += `${swapColor ? 'background-' : ''}color:rgb(${(AttributeData.toColorRGB(this._workCell.getFgColor())).join(',')});`;
106         charElement.setAttribute('style', style);
107       } else if (this._workCell.isFgPalette()) {
108         let fg = this._workCell.getFgColor();
109         if (this._workCell.isBold() && fg < 8 && !swapColor && this._optionsService.options.drawBoldTextInBrightColors) {
110           fg += 8;
111         }
112         charElement.classList.add(`xterm-${swapColor ? 'b' : 'f'}g-${fg}`);
113       } else if (swapColor) {
114         charElement.classList.add(`xterm-bg-${INVERTED_DEFAULT_COLOR}`);
115       }
116
117       // bg
118       if (this._workCell.isBgRGB()) {
119         let style = charElement.getAttribute('style') || '';
120         style += `${swapColor ? '' : 'background-'}color:rgb(${(AttributeData.toColorRGB(this._workCell.getBgColor())).join(',')});`;
121         charElement.setAttribute('style', style);
122       } else if (this._workCell.isBgPalette()) {
123         charElement.classList.add(`xterm-${swapColor ? 'f' : 'b'}g-${this._workCell.getBgColor()}`);
124       } else if (swapColor) {
125         charElement.classList.add(`xterm-fg-${INVERTED_DEFAULT_COLOR}`);
126       }
127
128       fragment.appendChild(charElement);
129     }
130     return fragment;
131   }
132 }