@xterm/xterm 5.4.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +235 -0
  3. package/css/xterm.css +209 -0
  4. package/lib/xterm.js +2 -0
  5. package/lib/xterm.js.map +1 -0
  6. package/package.json +101 -0
  7. package/src/browser/AccessibilityManager.ts +278 -0
  8. package/src/browser/Clipboard.ts +93 -0
  9. package/src/browser/ColorContrastCache.ts +34 -0
  10. package/src/browser/Lifecycle.ts +33 -0
  11. package/src/browser/Linkifier2.ts +416 -0
  12. package/src/browser/LocalizableStrings.ts +12 -0
  13. package/src/browser/OscLinkProvider.ts +128 -0
  14. package/src/browser/RenderDebouncer.ts +83 -0
  15. package/src/browser/Terminal.ts +1317 -0
  16. package/src/browser/TimeBasedDebouncer.ts +86 -0
  17. package/src/browser/Types.d.ts +181 -0
  18. package/src/browser/Viewport.ts +401 -0
  19. package/src/browser/decorations/BufferDecorationRenderer.ts +134 -0
  20. package/src/browser/decorations/ColorZoneStore.ts +117 -0
  21. package/src/browser/decorations/OverviewRulerRenderer.ts +218 -0
  22. package/src/browser/input/CompositionHelper.ts +246 -0
  23. package/src/browser/input/Mouse.ts +54 -0
  24. package/src/browser/input/MoveToCell.ts +249 -0
  25. package/src/browser/public/Terminal.ts +260 -0
  26. package/src/browser/renderer/dom/DomRenderer.ts +509 -0
  27. package/src/browser/renderer/dom/DomRendererRowFactory.ts +526 -0
  28. package/src/browser/renderer/dom/WidthCache.ts +160 -0
  29. package/src/browser/renderer/shared/CellColorResolver.ts +137 -0
  30. package/src/browser/renderer/shared/CharAtlasCache.ts +96 -0
  31. package/src/browser/renderer/shared/CharAtlasUtils.ts +75 -0
  32. package/src/browser/renderer/shared/Constants.ts +14 -0
  33. package/src/browser/renderer/shared/CursorBlinkStateManager.ts +146 -0
  34. package/src/browser/renderer/shared/CustomGlyphs.ts +687 -0
  35. package/src/browser/renderer/shared/DevicePixelObserver.ts +41 -0
  36. package/src/browser/renderer/shared/README.md +1 -0
  37. package/src/browser/renderer/shared/RendererUtils.ts +58 -0
  38. package/src/browser/renderer/shared/SelectionRenderModel.ts +91 -0
  39. package/src/browser/renderer/shared/TextureAtlas.ts +1082 -0
  40. package/src/browser/renderer/shared/Types.d.ts +173 -0
  41. package/src/browser/selection/SelectionModel.ts +144 -0
  42. package/src/browser/selection/Types.d.ts +15 -0
  43. package/src/browser/services/CharSizeService.ts +102 -0
  44. package/src/browser/services/CharacterJoinerService.ts +339 -0
  45. package/src/browser/services/CoreBrowserService.ts +137 -0
  46. package/src/browser/services/MouseService.ts +46 -0
  47. package/src/browser/services/RenderService.ts +279 -0
  48. package/src/browser/services/SelectionService.ts +1031 -0
  49. package/src/browser/services/Services.ts +147 -0
  50. package/src/browser/services/ThemeService.ts +237 -0
  51. package/src/common/CircularList.ts +241 -0
  52. package/src/common/Clone.ts +23 -0
  53. package/src/common/Color.ts +357 -0
  54. package/src/common/CoreTerminal.ts +284 -0
  55. package/src/common/EventEmitter.ts +78 -0
  56. package/src/common/InputHandler.ts +3461 -0
  57. package/src/common/Lifecycle.ts +108 -0
  58. package/src/common/MultiKeyMap.ts +42 -0
  59. package/src/common/Platform.ts +44 -0
  60. package/src/common/SortedList.ts +118 -0
  61. package/src/common/TaskQueue.ts +166 -0
  62. package/src/common/TypedArrayUtils.ts +17 -0
  63. package/src/common/Types.d.ts +553 -0
  64. package/src/common/WindowsMode.ts +27 -0
  65. package/src/common/buffer/AttributeData.ts +196 -0
  66. package/src/common/buffer/Buffer.ts +654 -0
  67. package/src/common/buffer/BufferLine.ts +524 -0
  68. package/src/common/buffer/BufferRange.ts +13 -0
  69. package/src/common/buffer/BufferReflow.ts +223 -0
  70. package/src/common/buffer/BufferSet.ts +134 -0
  71. package/src/common/buffer/CellData.ts +94 -0
  72. package/src/common/buffer/Constants.ts +149 -0
  73. package/src/common/buffer/Marker.ts +43 -0
  74. package/src/common/buffer/Types.d.ts +52 -0
  75. package/src/common/data/Charsets.ts +256 -0
  76. package/src/common/data/EscapeSequences.ts +153 -0
  77. package/src/common/input/Keyboard.ts +398 -0
  78. package/src/common/input/TextDecoder.ts +346 -0
  79. package/src/common/input/UnicodeV6.ts +145 -0
  80. package/src/common/input/WriteBuffer.ts +246 -0
  81. package/src/common/input/XParseColor.ts +80 -0
  82. package/src/common/parser/Constants.ts +58 -0
  83. package/src/common/parser/DcsParser.ts +192 -0
  84. package/src/common/parser/EscapeSequenceParser.ts +792 -0
  85. package/src/common/parser/OscParser.ts +238 -0
  86. package/src/common/parser/Params.ts +229 -0
  87. package/src/common/parser/Types.d.ts +275 -0
  88. package/src/common/public/AddonManager.ts +53 -0
  89. package/src/common/public/BufferApiView.ts +35 -0
  90. package/src/common/public/BufferLineApiView.ts +29 -0
  91. package/src/common/public/BufferNamespaceApi.ts +36 -0
  92. package/src/common/public/ParserApi.ts +37 -0
  93. package/src/common/public/UnicodeApi.ts +27 -0
  94. package/src/common/services/BufferService.ts +151 -0
  95. package/src/common/services/CharsetService.ts +34 -0
  96. package/src/common/services/CoreMouseService.ts +318 -0
  97. package/src/common/services/CoreService.ts +87 -0
  98. package/src/common/services/DecorationService.ts +140 -0
  99. package/src/common/services/InstantiationService.ts +85 -0
  100. package/src/common/services/LogService.ts +124 -0
  101. package/src/common/services/OptionsService.ts +202 -0
  102. package/src/common/services/OscLinkService.ts +115 -0
  103. package/src/common/services/ServiceRegistry.ts +49 -0
  104. package/src/common/services/Services.ts +373 -0
  105. package/src/common/services/UnicodeService.ts +111 -0
  106. package/src/headless/Terminal.ts +136 -0
  107. package/src/headless/public/Terminal.ts +195 -0
  108. package/typings/xterm.d.ts +1857 -0
@@ -0,0 +1,524 @@
1
+ /**
2
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { CharData, IAttributeData, IBufferLine, ICellData, IExtendedAttrs } from 'common/Types';
7
+ import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData';
8
+ import { CellData } from 'common/buffer/CellData';
9
+ import { Attributes, BgFlags, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, Content, NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants';
10
+ import { stringFromCodePoint } from 'common/input/TextDecoder';
11
+
12
+ /**
13
+ * buffer memory layout:
14
+ *
15
+ * | uint32_t | uint32_t | uint32_t |
16
+ * | `content` | `FG` | `BG` |
17
+ * | wcwidth(2) comb(1) codepoint(21) | flags(8) R(8) G(8) B(8) | flags(8) R(8) G(8) B(8) |
18
+ */
19
+
20
+
21
+ /** typed array slots taken by one cell */
22
+ const CELL_SIZE = 3;
23
+
24
+ /**
25
+ * Cell member indices.
26
+ *
27
+ * Direct access:
28
+ * `content = data[column * CELL_SIZE + Cell.CONTENT];`
29
+ * `fg = data[column * CELL_SIZE + Cell.FG];`
30
+ * `bg = data[column * CELL_SIZE + Cell.BG];`
31
+ */
32
+ const enum Cell {
33
+ CONTENT = 0,
34
+ FG = 1, // currently simply holds all known attrs
35
+ BG = 2 // currently unused
36
+ }
37
+
38
+ export const DEFAULT_ATTR_DATA = Object.freeze(new AttributeData());
39
+
40
+ // Work variables to avoid garbage collection
41
+ let $startIndex = 0;
42
+
43
+ /** Factor when to cleanup underlying array buffer after shrinking. */
44
+ const CLEANUP_THRESHOLD = 2;
45
+
46
+ /**
47
+ * Typed array based bufferline implementation.
48
+ *
49
+ * There are 2 ways to insert data into the cell buffer:
50
+ * - `setCellFromCodepoint` + `addCodepointToCell`
51
+ * Use these for data that is already UTF32.
52
+ * Used during normal input in `InputHandler` for faster buffer access.
53
+ * - `setCell`
54
+ * This method takes a CellData object and stores the data in the buffer.
55
+ * Use `CellData.fromCharData` to create the CellData object (e.g. from JS string).
56
+ *
57
+ * To retrieve data from the buffer use either one of the primitive methods
58
+ * (if only one particular value is needed) or `loadCell`. For `loadCell` in a loop
59
+ * memory allocs / GC pressure can be greatly reduced by reusing the CellData object.
60
+ */
61
+ export class BufferLine implements IBufferLine {
62
+ protected _data: Uint32Array;
63
+ protected _combined: {[index: number]: string} = {};
64
+ protected _extendedAttrs: {[index: number]: IExtendedAttrs | undefined} = {};
65
+ public length: number;
66
+
67
+ constructor(cols: number, fillCellData?: ICellData, public isWrapped: boolean = false) {
68
+ this._data = new Uint32Array(cols * CELL_SIZE);
69
+ const cell = fillCellData || CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
70
+ for (let i = 0; i < cols; ++i) {
71
+ this.setCell(i, cell);
72
+ }
73
+ this.length = cols;
74
+ }
75
+
76
+ /**
77
+ * Get cell data CharData.
78
+ * @deprecated
79
+ */
80
+ public get(index: number): CharData {
81
+ const content = this._data[index * CELL_SIZE + Cell.CONTENT];
82
+ const cp = content & Content.CODEPOINT_MASK;
83
+ return [
84
+ this._data[index * CELL_SIZE + Cell.FG],
85
+ (content & Content.IS_COMBINED_MASK)
86
+ ? this._combined[index]
87
+ : (cp) ? stringFromCodePoint(cp) : '',
88
+ content >> Content.WIDTH_SHIFT,
89
+ (content & Content.IS_COMBINED_MASK)
90
+ ? this._combined[index].charCodeAt(this._combined[index].length - 1)
91
+ : cp
92
+ ];
93
+ }
94
+
95
+ /**
96
+ * Set cell data from CharData.
97
+ * @deprecated
98
+ */
99
+ public set(index: number, value: CharData): void {
100
+ this._data[index * CELL_SIZE + Cell.FG] = value[CHAR_DATA_ATTR_INDEX];
101
+ if (value[CHAR_DATA_CHAR_INDEX].length > 1) {
102
+ this._combined[index] = value[1];
103
+ this._data[index * CELL_SIZE + Cell.CONTENT] = index | Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
104
+ } else {
105
+ this._data[index * CELL_SIZE + Cell.CONTENT] = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * primitive getters
111
+ * use these when only one value is needed, otherwise use `loadCell`
112
+ */
113
+ public getWidth(index: number): number {
114
+ return this._data[index * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT;
115
+ }
116
+
117
+ /** Test whether content has width. */
118
+ public hasWidth(index: number): number {
119
+ return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.WIDTH_MASK;
120
+ }
121
+
122
+ /** Get FG cell component. */
123
+ public getFg(index: number): number {
124
+ return this._data[index * CELL_SIZE + Cell.FG];
125
+ }
126
+
127
+ /** Get BG cell component. */
128
+ public getBg(index: number): number {
129
+ return this._data[index * CELL_SIZE + Cell.BG];
130
+ }
131
+
132
+ /**
133
+ * Test whether contains any chars.
134
+ * Basically an empty has no content, but other cells might differ in FG/BG
135
+ * from real empty cells.
136
+ */
137
+ public hasContent(index: number): number {
138
+ return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK;
139
+ }
140
+
141
+ /**
142
+ * Get codepoint of the cell.
143
+ * To be in line with `code` in CharData this either returns
144
+ * a single UTF32 codepoint or the last codepoint of a combined string.
145
+ */
146
+ public getCodePoint(index: number): number {
147
+ const content = this._data[index * CELL_SIZE + Cell.CONTENT];
148
+ if (content & Content.IS_COMBINED_MASK) {
149
+ return this._combined[index].charCodeAt(this._combined[index].length - 1);
150
+ }
151
+ return content & Content.CODEPOINT_MASK;
152
+ }
153
+
154
+ /** Test whether the cell contains a combined string. */
155
+ public isCombined(index: number): number {
156
+ return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.IS_COMBINED_MASK;
157
+ }
158
+
159
+ /** Returns the string content of the cell. */
160
+ public getString(index: number): string {
161
+ const content = this._data[index * CELL_SIZE + Cell.CONTENT];
162
+ if (content & Content.IS_COMBINED_MASK) {
163
+ return this._combined[index];
164
+ }
165
+ if (content & Content.CODEPOINT_MASK) {
166
+ return stringFromCodePoint(content & Content.CODEPOINT_MASK);
167
+ }
168
+ // return empty string for empty cells
169
+ return '';
170
+ }
171
+
172
+ /** Get state of protected flag. */
173
+ public isProtected(index: number): number {
174
+ return this._data[index * CELL_SIZE + Cell.BG] & BgFlags.PROTECTED;
175
+ }
176
+
177
+ /**
178
+ * Load data at `index` into `cell`. This is used to access cells in a way that's more friendly
179
+ * to GC as it significantly reduced the amount of new objects/references needed.
180
+ */
181
+ public loadCell(index: number, cell: ICellData): ICellData {
182
+ $startIndex = index * CELL_SIZE;
183
+ cell.content = this._data[$startIndex + Cell.CONTENT];
184
+ cell.fg = this._data[$startIndex + Cell.FG];
185
+ cell.bg = this._data[$startIndex + Cell.BG];
186
+ if (cell.content & Content.IS_COMBINED_MASK) {
187
+ cell.combinedData = this._combined[index];
188
+ }
189
+ if (cell.bg & BgFlags.HAS_EXTENDED) {
190
+ cell.extended = this._extendedAttrs[index]!;
191
+ }
192
+ return cell;
193
+ }
194
+
195
+ /**
196
+ * Set data at `index` to `cell`.
197
+ */
198
+ public setCell(index: number, cell: ICellData): void {
199
+ if (cell.content & Content.IS_COMBINED_MASK) {
200
+ this._combined[index] = cell.combinedData;
201
+ }
202
+ if (cell.bg & BgFlags.HAS_EXTENDED) {
203
+ this._extendedAttrs[index] = cell.extended;
204
+ }
205
+ this._data[index * CELL_SIZE + Cell.CONTENT] = cell.content;
206
+ this._data[index * CELL_SIZE + Cell.FG] = cell.fg;
207
+ this._data[index * CELL_SIZE + Cell.BG] = cell.bg;
208
+ }
209
+
210
+ /**
211
+ * Set cell data from input handler.
212
+ * Since the input handler see the incoming chars as UTF32 codepoints,
213
+ * it gets an optimized access method.
214
+ */
215
+ public setCellFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number, eAttrs: IExtendedAttrs): void {
216
+ if (bg & BgFlags.HAS_EXTENDED) {
217
+ this._extendedAttrs[index] = eAttrs;
218
+ }
219
+ this._data[index * CELL_SIZE + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT);
220
+ this._data[index * CELL_SIZE + Cell.FG] = fg;
221
+ this._data[index * CELL_SIZE + Cell.BG] = bg;
222
+ }
223
+
224
+ /**
225
+ * Add a codepoint to a cell from input handler.
226
+ * During input stage combining chars with a width of 0 follow and stack
227
+ * onto a leading char. Since we already set the attrs
228
+ * by the previous `setDataFromCodePoint` call, we can omit it here.
229
+ */
230
+ public addCodepointToCell(index: number, codePoint: number, width: number): void {
231
+ let content = this._data[index * CELL_SIZE + Cell.CONTENT];
232
+ if (content & Content.IS_COMBINED_MASK) {
233
+ // we already have a combined string, simply add
234
+ this._combined[index] += stringFromCodePoint(codePoint);
235
+ } else {
236
+ if (content & Content.CODEPOINT_MASK) {
237
+ // normal case for combining chars:
238
+ // - move current leading char + new one into combined string
239
+ // - set combined flag
240
+ this._combined[index] = stringFromCodePoint(content & Content.CODEPOINT_MASK) + stringFromCodePoint(codePoint);
241
+ content &= ~Content.CODEPOINT_MASK; // set codepoint in buffer to 0
242
+ content |= Content.IS_COMBINED_MASK;
243
+ } else {
244
+ // should not happen - we actually have no data in the cell yet
245
+ // simply set the data in the cell buffer with a width of 1
246
+ content = codePoint | (1 << Content.WIDTH_SHIFT);
247
+ }
248
+ }
249
+ if (width) {
250
+ content &= ~Content.WIDTH_MASK;
251
+ content |= width << Content.WIDTH_SHIFT;
252
+ }
253
+ this._data[index * CELL_SIZE + Cell.CONTENT] = content;
254
+ }
255
+
256
+ public insertCells(pos: number, n: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void {
257
+ pos %= this.length;
258
+
259
+ // handle fullwidth at pos: reset cell one to the left if pos is second cell of a wide char
260
+ if (pos && this.getWidth(pos - 1) === 2) {
261
+ this.setCellFromCodePoint(pos - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
262
+ }
263
+
264
+ if (n < this.length - pos) {
265
+ const cell = new CellData();
266
+ for (let i = this.length - pos - n - 1; i >= 0; --i) {
267
+ this.setCell(pos + n + i, this.loadCell(pos + i, cell));
268
+ }
269
+ for (let i = 0; i < n; ++i) {
270
+ this.setCell(pos + i, fillCellData);
271
+ }
272
+ } else {
273
+ for (let i = pos; i < this.length; ++i) {
274
+ this.setCell(i, fillCellData);
275
+ }
276
+ }
277
+
278
+ // handle fullwidth at line end: reset last cell if it is first cell of a wide char
279
+ if (this.getWidth(this.length - 1) === 2) {
280
+ this.setCellFromCodePoint(this.length - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
281
+ }
282
+ }
283
+
284
+ public deleteCells(pos: number, n: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void {
285
+ pos %= this.length;
286
+ if (n < this.length - pos) {
287
+ const cell = new CellData();
288
+ for (let i = 0; i < this.length - pos - n; ++i) {
289
+ this.setCell(pos + i, this.loadCell(pos + n + i, cell));
290
+ }
291
+ for (let i = this.length - n; i < this.length; ++i) {
292
+ this.setCell(i, fillCellData);
293
+ }
294
+ } else {
295
+ for (let i = pos; i < this.length; ++i) {
296
+ this.setCell(i, fillCellData);
297
+ }
298
+ }
299
+
300
+ // handle fullwidth at pos:
301
+ // - reset pos-1 if wide char
302
+ // - reset pos if width==0 (previous second cell of a wide char)
303
+ if (pos && this.getWidth(pos - 1) === 2) {
304
+ this.setCellFromCodePoint(pos - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
305
+ }
306
+ if (this.getWidth(pos) === 0 && !this.hasContent(pos)) {
307
+ this.setCellFromCodePoint(pos, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
308
+ }
309
+ }
310
+
311
+ public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData, respectProtect: boolean = false): void {
312
+ // full branching on respectProtect==true, hopefully getting fast JIT for standard case
313
+ if (respectProtect) {
314
+ if (start && this.getWidth(start - 1) === 2 && !this.isProtected(start - 1)) {
315
+ this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
316
+ }
317
+ if (end < this.length && this.getWidth(end - 1) === 2 && !this.isProtected(end)) {
318
+ this.setCellFromCodePoint(end, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
319
+ }
320
+ while (start < end && start < this.length) {
321
+ if (!this.isProtected(start)) {
322
+ this.setCell(start, fillCellData);
323
+ }
324
+ start++;
325
+ }
326
+ return;
327
+ }
328
+
329
+ // handle fullwidth at start: reset cell one to the left if start is second cell of a wide char
330
+ if (start && this.getWidth(start - 1) === 2) {
331
+ this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
332
+ }
333
+ // handle fullwidth at last cell + 1: reset to empty cell if it is second part of a wide char
334
+ if (end < this.length && this.getWidth(end - 1) === 2) {
335
+ this.setCellFromCodePoint(end, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
336
+ }
337
+
338
+ while (start < end && start < this.length) {
339
+ this.setCell(start++, fillCellData);
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Resize BufferLine to `cols` filling excess cells with `fillCellData`.
345
+ * The underlying array buffer will not change if there is still enough space
346
+ * to hold the new buffer line data.
347
+ * Returns a boolean indicating, whether a `cleanupMemory` call would free
348
+ * excess memory (true after shrinking > CLEANUP_THRESHOLD).
349
+ */
350
+ public resize(cols: number, fillCellData: ICellData): boolean {
351
+ if (cols === this.length) {
352
+ return this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
353
+ }
354
+ const uint32Cells = cols * CELL_SIZE;
355
+ if (cols > this.length) {
356
+ if (this._data.buffer.byteLength >= uint32Cells * 4) {
357
+ // optimization: avoid alloc and data copy if buffer has enough room
358
+ this._data = new Uint32Array(this._data.buffer, 0, uint32Cells);
359
+ } else {
360
+ // slow path: new alloc and full data copy
361
+ const data = new Uint32Array(uint32Cells);
362
+ data.set(this._data);
363
+ this._data = data;
364
+ }
365
+ for (let i = this.length; i < cols; ++i) {
366
+ this.setCell(i, fillCellData);
367
+ }
368
+ } else {
369
+ // optimization: just shrink the view on existing buffer
370
+ this._data = this._data.subarray(0, uint32Cells);
371
+ // Remove any cut off combined data
372
+ const keys = Object.keys(this._combined);
373
+ for (let i = 0; i < keys.length; i++) {
374
+ const key = parseInt(keys[i], 10);
375
+ if (key >= cols) {
376
+ delete this._combined[key];
377
+ }
378
+ }
379
+ // remove any cut off extended attributes
380
+ const extKeys = Object.keys(this._extendedAttrs);
381
+ for (let i = 0; i < extKeys.length; i++) {
382
+ const key = parseInt(extKeys[i], 10);
383
+ if (key >= cols) {
384
+ delete this._extendedAttrs[key];
385
+ }
386
+ }
387
+ }
388
+ this.length = cols;
389
+ return uint32Cells * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
390
+ }
391
+
392
+ /**
393
+ * Cleanup underlying array buffer.
394
+ * A cleanup will be triggered if the array buffer exceeds the actual used
395
+ * memory by a factor of CLEANUP_THRESHOLD.
396
+ * Returns 0 or 1 indicating whether a cleanup happened.
397
+ */
398
+ public cleanupMemory(): number {
399
+ if (this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
400
+ const data = new Uint32Array(this._data.length);
401
+ data.set(this._data);
402
+ this._data = data;
403
+ return 1;
404
+ }
405
+ return 0;
406
+ }
407
+
408
+ /** fill a line with fillCharData */
409
+ public fill(fillCellData: ICellData, respectProtect: boolean = false): void {
410
+ // full branching on respectProtect==true, hopefully getting fast JIT for standard case
411
+ if (respectProtect) {
412
+ for (let i = 0; i < this.length; ++i) {
413
+ if (!this.isProtected(i)) {
414
+ this.setCell(i, fillCellData);
415
+ }
416
+ }
417
+ return;
418
+ }
419
+ this._combined = {};
420
+ this._extendedAttrs = {};
421
+ for (let i = 0; i < this.length; ++i) {
422
+ this.setCell(i, fillCellData);
423
+ }
424
+ }
425
+
426
+ /** alter to a full copy of line */
427
+ public copyFrom(line: BufferLine): void {
428
+ if (this.length !== line.length) {
429
+ this._data = new Uint32Array(line._data);
430
+ } else {
431
+ // use high speed copy if lengths are equal
432
+ this._data.set(line._data);
433
+ }
434
+ this.length = line.length;
435
+ this._combined = {};
436
+ for (const el in line._combined) {
437
+ this._combined[el] = line._combined[el];
438
+ }
439
+ this._extendedAttrs = {};
440
+ for (const el in line._extendedAttrs) {
441
+ this._extendedAttrs[el] = line._extendedAttrs[el];
442
+ }
443
+ this.isWrapped = line.isWrapped;
444
+ }
445
+
446
+ /** create a new clone */
447
+ public clone(): IBufferLine {
448
+ const newLine = new BufferLine(0);
449
+ newLine._data = new Uint32Array(this._data);
450
+ newLine.length = this.length;
451
+ for (const el in this._combined) {
452
+ newLine._combined[el] = this._combined[el];
453
+ }
454
+ for (const el in this._extendedAttrs) {
455
+ newLine._extendedAttrs[el] = this._extendedAttrs[el];
456
+ }
457
+ newLine.isWrapped = this.isWrapped;
458
+ return newLine;
459
+ }
460
+
461
+ public getTrimmedLength(): number {
462
+ for (let i = this.length - 1; i >= 0; --i) {
463
+ if ((this._data[i * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK)) {
464
+ return i + (this._data[i * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT);
465
+ }
466
+ }
467
+ return 0;
468
+ }
469
+
470
+ public getNoBgTrimmedLength(): number {
471
+ for (let i = this.length - 1; i >= 0; --i) {
472
+ if ((this._data[i * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK) || (this._data[i * CELL_SIZE + Cell.BG] & Attributes.CM_MASK)) {
473
+ return i + (this._data[i * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT);
474
+ }
475
+ }
476
+ return 0;
477
+ }
478
+
479
+ public copyCellsFrom(src: BufferLine, srcCol: number, destCol: number, length: number, applyInReverse: boolean): void {
480
+ const srcData = src._data;
481
+ if (applyInReverse) {
482
+ for (let cell = length - 1; cell >= 0; cell--) {
483
+ for (let i = 0; i < CELL_SIZE; i++) {
484
+ this._data[(destCol + cell) * CELL_SIZE + i] = srcData[(srcCol + cell) * CELL_SIZE + i];
485
+ }
486
+ if (srcData[(srcCol + cell) * CELL_SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
487
+ this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
488
+ }
489
+ }
490
+ } else {
491
+ for (let cell = 0; cell < length; cell++) {
492
+ for (let i = 0; i < CELL_SIZE; i++) {
493
+ this._data[(destCol + cell) * CELL_SIZE + i] = srcData[(srcCol + cell) * CELL_SIZE + i];
494
+ }
495
+ if (srcData[(srcCol + cell) * CELL_SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
496
+ this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
497
+ }
498
+ }
499
+ }
500
+
501
+ // Move any combined data over as needed, FIXME: repeat for extended attrs
502
+ const srcCombinedKeys = Object.keys(src._combined);
503
+ for (let i = 0; i < srcCombinedKeys.length; i++) {
504
+ const key = parseInt(srcCombinedKeys[i], 10);
505
+ if (key >= srcCol) {
506
+ this._combined[key - srcCol + destCol] = src._combined[key];
507
+ }
508
+ }
509
+ }
510
+
511
+ public translateToString(trimRight: boolean = false, startCol: number = 0, endCol: number = this.length): string {
512
+ if (trimRight) {
513
+ endCol = Math.min(endCol, this.getTrimmedLength());
514
+ }
515
+ let result = '';
516
+ while (startCol < endCol) {
517
+ const content = this._data[startCol * CELL_SIZE + Cell.CONTENT];
518
+ const cp = content & Content.CODEPOINT_MASK;
519
+ result += (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR;
520
+ startCol += (content >> Content.WIDTH_SHIFT) || 1; // always advance by 1
521
+ }
522
+ return result;
523
+ }
524
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright (c) 2021 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { IBufferRange } from '@xterm/xterm';
7
+
8
+ export function getRangeLength(range: IBufferRange, bufferCols: number): number {
9
+ if (range.start.y > range.end.y) {
10
+ throw new Error(`Buffer range end (${range.end.x}, ${range.end.y}) cannot be before start (${range.start.x}, ${range.start.y})`);
11
+ }
12
+ return bufferCols * (range.end.y - range.start.y) + (range.end.x - range.start.x + 1);
13
+ }