@xterm/xterm 6.1.0-beta.25 → 6.1.0-beta.250
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.
- package/README.md +62 -38
- package/css/xterm.css +29 -22
- package/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/lib/xterm.mjs +8 -34
- package/lib/xterm.mjs.map +4 -4
- package/package.json +25 -22
- package/src/browser/AccessibilityManager.ts +11 -6
- package/src/browser/Clipboard.ts +6 -3
- package/src/browser/CoreBrowserTerminal.ts +149 -319
- package/src/browser/Dom.ts +178 -0
- package/src/browser/Linkifier.ts +11 -11
- package/src/browser/OscLinkProvider.ts +82 -14
- package/src/browser/RenderDebouncer.ts +2 -2
- package/src/browser/TimeBasedDebouncer.ts +2 -2
- package/src/browser/Types.ts +12 -11
- package/src/browser/Viewport.ts +55 -20
- package/src/browser/decorations/BufferDecorationRenderer.ts +1 -1
- package/src/browser/decorations/OverviewRulerRenderer.ts +33 -17
- package/src/browser/input/CompositionHelper.ts +44 -8
- package/src/browser/public/Terminal.ts +25 -28
- package/src/browser/renderer/dom/DomRenderer.ts +242 -76
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +19 -13
- package/src/browser/renderer/dom/WidthCache.ts +54 -52
- package/src/browser/renderer/shared/Constants.ts +7 -0
- package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
- package/src/browser/renderer/shared/Types.ts +8 -2
- package/src/browser/scrollable/abstractScrollbar.ts +300 -0
- package/src/browser/scrollable/fastDomNode.ts +126 -0
- package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
- package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
- package/src/browser/scrollable/mouseEvent.ts +292 -0
- package/src/browser/scrollable/scrollable.ts +486 -0
- package/src/browser/scrollable/scrollableElement.ts +581 -0
- package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
- package/src/browser/scrollable/scrollbarArrow.ts +110 -0
- package/src/browser/scrollable/scrollbarState.ts +246 -0
- package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
- package/src/browser/scrollable/touch.ts +485 -0
- package/src/browser/scrollable/verticalScrollbar.ts +143 -0
- package/src/browser/scrollable/widget.ts +23 -0
- package/src/browser/services/CharSizeService.ts +2 -2
- package/src/browser/services/CoreBrowserService.ts +7 -5
- package/src/browser/services/KeyboardService.ts +67 -0
- package/src/browser/services/LinkProviderService.ts +1 -1
- package/src/browser/services/MouseCoordsService.ts +47 -0
- package/src/browser/services/MouseService.ts +518 -25
- package/src/browser/services/RenderService.ts +28 -16
- package/src/browser/services/SelectionService.ts +45 -39
- package/src/browser/services/Services.ts +40 -17
- package/src/browser/services/ThemeService.ts +2 -2
- package/src/common/Async.ts +141 -0
- package/src/common/CircularList.ts +2 -2
- package/src/common/Color.ts +8 -0
- package/src/common/CoreTerminal.ts +32 -22
- package/src/common/Event.ts +118 -0
- package/src/common/InputHandler.ts +286 -87
- package/src/common/Lifecycle.ts +113 -0
- package/src/common/Platform.ts +13 -3
- package/src/common/SortedList.ts +7 -3
- package/src/common/StringBuilder.ts +67 -0
- package/src/common/TaskQueue.ts +14 -5
- package/src/common/Types.ts +51 -31
- package/src/common/Version.ts +9 -0
- package/src/common/buffer/Buffer.ts +34 -19
- package/src/common/buffer/BufferLine.ts +140 -68
- package/src/common/buffer/BufferLineStringCache.ts +69 -0
- package/src/common/buffer/BufferReflow.ts +4 -1
- package/src/common/buffer/BufferSet.ts +11 -6
- package/src/common/buffer/CellData.ts +57 -0
- package/src/common/buffer/Marker.ts +2 -2
- package/src/common/buffer/Types.ts +6 -2
- package/src/common/data/EscapeSequences.ts +71 -70
- package/src/common/input/Keyboard.ts +14 -7
- package/src/common/input/KittyKeyboard.ts +526 -0
- package/src/common/input/Win32InputMode.ts +297 -0
- package/src/common/input/WriteBuffer.ts +107 -38
- package/src/common/input/XParseColor.ts +2 -2
- package/src/common/parser/ApcParser.ts +196 -0
- package/src/common/parser/Constants.ts +14 -4
- package/src/common/parser/DcsParser.ts +11 -12
- package/src/common/parser/EscapeSequenceParser.ts +205 -63
- package/src/common/parser/OscParser.ts +11 -12
- package/src/common/parser/Params.ts +27 -8
- package/src/common/parser/Types.ts +36 -2
- package/src/common/public/BufferLineApiView.ts +2 -2
- package/src/common/public/BufferNamespaceApi.ts +3 -3
- package/src/common/public/ParserApi.ts +3 -0
- package/src/common/services/BufferService.ts +14 -9
- package/src/common/services/CharsetService.ts +4 -0
- package/src/common/services/CoreService.ts +22 -9
- package/src/common/services/DecorationService.ts +255 -8
- package/src/common/services/LogService.ts +1 -31
- package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +21 -132
- package/src/common/services/OptionsService.ts +13 -4
- package/src/common/services/ServiceRegistry.ts +9 -7
- package/src/common/services/Services.ts +49 -40
- package/src/common/services/UnicodeService.ts +1 -1
- package/typings/xterm.d.ts +318 -34
- package/src/common/Clone.ts +0 -23
- package/src/common/TypedArrayUtils.ts +0 -17
- package/src/vs/base/browser/browser.ts +0 -141
- package/src/vs/base/browser/canIUse.ts +0 -49
- package/src/vs/base/browser/dom.ts +0 -2369
- package/src/vs/base/browser/fastDomNode.ts +0 -316
- package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
- package/src/vs/base/browser/iframe.ts +0 -135
- package/src/vs/base/browser/keyboardEvent.ts +0 -213
- package/src/vs/base/browser/mouseEvent.ts +0 -229
- package/src/vs/base/browser/touch.ts +0 -372
- package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
- package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
- package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
- package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
- package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
- package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
- package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
- package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
- package/src/vs/base/browser/ui/widget.ts +0 -57
- package/src/vs/base/browser/window.ts +0 -14
- package/src/vs/base/common/arrays.ts +0 -887
- package/src/vs/base/common/arraysFind.ts +0 -202
- package/src/vs/base/common/assert.ts +0 -71
- package/src/vs/base/common/async.ts +0 -1992
- package/src/vs/base/common/cancellation.ts +0 -148
- package/src/vs/base/common/charCode.ts +0 -450
- package/src/vs/base/common/collections.ts +0 -140
- package/src/vs/base/common/decorators.ts +0 -130
- package/src/vs/base/common/equals.ts +0 -146
- package/src/vs/base/common/errors.ts +0 -303
- package/src/vs/base/common/event.ts +0 -1778
- package/src/vs/base/common/functional.ts +0 -32
- package/src/vs/base/common/hash.ts +0 -316
- package/src/vs/base/common/iterator.ts +0 -159
- package/src/vs/base/common/keyCodes.ts +0 -526
- package/src/vs/base/common/keybindings.ts +0 -284
- package/src/vs/base/common/lazy.ts +0 -47
- package/src/vs/base/common/lifecycle.ts +0 -801
- package/src/vs/base/common/linkedList.ts +0 -142
- package/src/vs/base/common/map.ts +0 -202
- package/src/vs/base/common/numbers.ts +0 -98
- package/src/vs/base/common/observable.ts +0 -76
- package/src/vs/base/common/observableInternal/api.ts +0 -31
- package/src/vs/base/common/observableInternal/autorun.ts +0 -281
- package/src/vs/base/common/observableInternal/base.ts +0 -489
- package/src/vs/base/common/observableInternal/debugName.ts +0 -145
- package/src/vs/base/common/observableInternal/derived.ts +0 -428
- package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
- package/src/vs/base/common/observableInternal/logging.ts +0 -328
- package/src/vs/base/common/observableInternal/promise.ts +0 -209
- package/src/vs/base/common/observableInternal/utils.ts +0 -610
- package/src/vs/base/common/platform.ts +0 -281
- package/src/vs/base/common/scrollable.ts +0 -522
- package/src/vs/base/common/sequence.ts +0 -34
- package/src/vs/base/common/stopwatch.ts +0 -43
- package/src/vs/base/common/strings.ts +0 -557
- package/src/vs/base/common/symbols.ts +0 -9
- package/src/vs/base/common/uint.ts +0 -59
- package/src/vs/patches/nls.ts +0 -90
- package/src/vs/typings/base-common.d.ts +0 -20
- package/src/vs/typings/require.d.ts +0 -42
- package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
- package/src/vs/typings/vscode-globals-product.d.ts +0 -33
|
@@ -4,17 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { CircularList, IInsertEvent } from 'common/CircularList';
|
|
7
|
+
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
7
8
|
import { IdleTaskQueue } from 'common/TaskQueue';
|
|
8
9
|
import { IAttributeData, IBufferLine, ICellData, ICharset } from 'common/Types';
|
|
9
10
|
import { ExtendedAttrs } from 'common/buffer/AttributeData';
|
|
10
11
|
import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
|
|
12
|
+
import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache';
|
|
11
13
|
import { getWrappedLineTrimmedLength, reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths } from 'common/buffer/BufferReflow';
|
|
12
14
|
import { CellData } from 'common/buffer/CellData';
|
|
13
15
|
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE, WHITESPACE_CELL_WIDTH } from 'common/buffer/Constants';
|
|
14
16
|
import { Marker } from 'common/buffer/Marker';
|
|
15
17
|
import { IBuffer } from 'common/buffer/Types';
|
|
16
18
|
import { DEFAULT_CHARSET } from 'common/data/Charsets';
|
|
17
|
-
import { IBufferService, IOptionsService } from 'common/services/Services';
|
|
19
|
+
import { IBufferService, ILogService, IOptionsService } from 'common/services/Services';
|
|
18
20
|
|
|
19
21
|
export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
|
|
20
22
|
|
|
@@ -25,7 +27,7 @@ export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
|
|
|
25
27
|
* - cursor position
|
|
26
28
|
* - scroll position
|
|
27
29
|
*/
|
|
28
|
-
export class Buffer implements IBuffer {
|
|
30
|
+
export class Buffer extends Disposable implements IBuffer {
|
|
29
31
|
public lines: CircularList<IBufferLine>;
|
|
30
32
|
public ydisp: number = 0;
|
|
31
33
|
public ybase: number = 0;
|
|
@@ -38,24 +40,37 @@ export class Buffer implements IBuffer {
|
|
|
38
40
|
public savedX: number = 0;
|
|
39
41
|
public savedCurAttrData = DEFAULT_ATTR_DATA.clone();
|
|
40
42
|
public savedCharset: ICharset | undefined = DEFAULT_CHARSET;
|
|
43
|
+
public savedCharsets: (ICharset | undefined)[] = [];
|
|
44
|
+
public savedGlevel: number = 0;
|
|
45
|
+
public savedOriginMode: boolean = false;
|
|
46
|
+
public savedWraparoundMode: boolean = true;
|
|
41
47
|
public markers: Marker[] = [];
|
|
42
48
|
private _nullCell: ICellData = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
|
43
49
|
private _whitespaceCell: ICellData = CellData.fromCharData([0, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE]);
|
|
44
50
|
private _cols: number;
|
|
45
51
|
private _rows: number;
|
|
46
52
|
private _isClearing: boolean = false;
|
|
53
|
+
private _memoryCleanupQueue: InstanceType<typeof IdleTaskQueue>;
|
|
54
|
+
private _memoryCleanupPosition = 0;
|
|
55
|
+
private readonly _stringCache: BufferLineStringCache;
|
|
47
56
|
|
|
48
57
|
constructor(
|
|
49
58
|
private _hasScrollback: boolean,
|
|
50
59
|
private _optionsService: IOptionsService,
|
|
51
|
-
private _bufferService: IBufferService
|
|
60
|
+
private _bufferService: IBufferService,
|
|
61
|
+
private readonly _logService: ILogService
|
|
52
62
|
) {
|
|
63
|
+
super();
|
|
53
64
|
this._cols = this._bufferService.cols;
|
|
54
65
|
this._rows = this._bufferService.rows;
|
|
55
66
|
this.lines = new CircularList<IBufferLine>(this._getCorrectBufferLength(this._rows));
|
|
56
67
|
this.scrollTop = 0;
|
|
57
68
|
this.scrollBottom = this._rows - 1;
|
|
58
69
|
this.setupTabStops();
|
|
70
|
+
this._memoryCleanupQueue = new IdleTaskQueue(this._logService);
|
|
71
|
+
this._register(toDisposable(() => this._memoryCleanupQueue.clear()));
|
|
72
|
+
this._register(toDisposable(() => this.clearAllMarkers()));
|
|
73
|
+
this._stringCache = this._register(new BufferLineStringCache());
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
public getNullCell(attr?: IAttributeData): ICellData {
|
|
@@ -85,7 +100,7 @@ export class Buffer implements IBuffer {
|
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
public getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine {
|
|
88
|
-
return new BufferLine(this._bufferService.cols, this.getNullCell(attr), isWrapped);
|
|
103
|
+
return new BufferLine(this._stringCache, this._bufferService.cols, this.getNullCell(attr), isWrapped);
|
|
89
104
|
}
|
|
90
105
|
|
|
91
106
|
public get hasScrollback(): boolean {
|
|
@@ -118,9 +133,7 @@ export class Buffer implements IBuffer {
|
|
|
118
133
|
*/
|
|
119
134
|
public fillViewportRows(fillAttr?: IAttributeData): void {
|
|
120
135
|
if (this.lines.length === 0) {
|
|
121
|
-
|
|
122
|
-
fillAttr = DEFAULT_ATTR_DATA;
|
|
123
|
-
}
|
|
136
|
+
fillAttr ??= DEFAULT_ATTR_DATA;
|
|
124
137
|
let i = this._rows;
|
|
125
138
|
while (i--) {
|
|
126
139
|
this.lines.push(this.getBlankLine(fillAttr));
|
|
@@ -132,6 +145,7 @@ export class Buffer implements IBuffer {
|
|
|
132
145
|
* Clears the buffer to it's initial state, discarding all previous data.
|
|
133
146
|
*/
|
|
134
147
|
public clear(): void {
|
|
148
|
+
this._stringCache.clear();
|
|
135
149
|
this.ydisp = 0;
|
|
136
150
|
this.ybase = 0;
|
|
137
151
|
this.y = 0;
|
|
@@ -150,6 +164,7 @@ export class Buffer implements IBuffer {
|
|
|
150
164
|
public resize(newCols: number, newRows: number): void {
|
|
151
165
|
// store reference to null cell with default attrs
|
|
152
166
|
const nullCell = this.getNullCell(DEFAULT_ATTR_DATA);
|
|
167
|
+
this._stringCache.clear();
|
|
153
168
|
|
|
154
169
|
// count bufferlines with overly big memory to be cleaned afterwards
|
|
155
170
|
let dirtyMemoryLines = 0;
|
|
@@ -184,7 +199,7 @@ export class Buffer implements IBuffer {
|
|
|
184
199
|
if (this._optionsService.rawOptions.windowsPty.backend !== undefined || this._optionsService.rawOptions.windowsPty.buildNumber !== undefined) {
|
|
185
200
|
// Just add the new missing rows on Windows as conpty reprints the screen with it's
|
|
186
201
|
// view of the world. Once a line enters scrollback for conpty it remains there
|
|
187
|
-
this.lines.push(new BufferLine(newCols, nullCell));
|
|
202
|
+
this.lines.push(new BufferLine(this._stringCache, newCols, nullCell, false));
|
|
188
203
|
} else {
|
|
189
204
|
if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
|
|
190
205
|
// There is room above the buffer and there are no empty elements below the line,
|
|
@@ -198,7 +213,7 @@ export class Buffer implements IBuffer {
|
|
|
198
213
|
} else {
|
|
199
214
|
// Add a blank line if there is no buffer left at the top to scroll to, or if there
|
|
200
215
|
// are blank lines after the cursor
|
|
201
|
-
this.lines.push(new BufferLine(newCols, nullCell));
|
|
216
|
+
this.lines.push(new BufferLine(this._stringCache, newCols, nullCell, false));
|
|
202
217
|
}
|
|
203
218
|
}
|
|
204
219
|
}
|
|
@@ -260,6 +275,13 @@ export class Buffer implements IBuffer {
|
|
|
260
275
|
this._cols = newCols;
|
|
261
276
|
this._rows = newRows;
|
|
262
277
|
|
|
278
|
+
// Ensure the cursor position invariant: ybase + y must be within buffer bounds
|
|
279
|
+
// This can be violated during reflow or when shrinking rows
|
|
280
|
+
if (this.lines.length > 0) {
|
|
281
|
+
const maxY = Math.max(0, this.lines.length - this.ybase - 1);
|
|
282
|
+
this.y = Math.min(this.y, maxY);
|
|
283
|
+
}
|
|
284
|
+
|
|
263
285
|
this._memoryCleanupQueue.clear();
|
|
264
286
|
// schedule memory cleanup only, if more than 10% of the lines are affected
|
|
265
287
|
if (dirtyMemoryLines > 0.1 * this.lines.length) {
|
|
@@ -268,9 +290,6 @@ export class Buffer implements IBuffer {
|
|
|
268
290
|
}
|
|
269
291
|
}
|
|
270
292
|
|
|
271
|
-
private _memoryCleanupQueue = new IdleTaskQueue();
|
|
272
|
-
private _memoryCleanupPosition = 0;
|
|
273
|
-
|
|
274
293
|
private _batchedMemoryCleanup(): boolean {
|
|
275
294
|
let normalRun = true;
|
|
276
295
|
if (this._memoryCleanupPosition >= this.lines.length) {
|
|
@@ -335,7 +354,7 @@ export class Buffer implements IBuffer {
|
|
|
335
354
|
}
|
|
336
355
|
if (this.lines.length < newRows) {
|
|
337
356
|
// Add an extra row at the bottom of the viewport
|
|
338
|
-
this.lines.push(new BufferLine(newCols, nullCell));
|
|
357
|
+
this.lines.push(new BufferLine(this._stringCache, newCols, nullCell, false));
|
|
339
358
|
}
|
|
340
359
|
} else {
|
|
341
360
|
if (this.ydisp === this.ybase) {
|
|
@@ -578,9 +597,7 @@ export class Buffer implements IBuffer {
|
|
|
578
597
|
* @param x The position to move the cursor to the previous tab stop.
|
|
579
598
|
*/
|
|
580
599
|
public prevStop(x?: number): number {
|
|
581
|
-
|
|
582
|
-
x = this.x;
|
|
583
|
-
}
|
|
600
|
+
x ??= this.x;
|
|
584
601
|
while (!this.tabs[--x] && x > 0);
|
|
585
602
|
return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x;
|
|
586
603
|
}
|
|
@@ -590,9 +607,7 @@ export class Buffer implements IBuffer {
|
|
|
590
607
|
* @param x The position to move the cursor one tab stop forward.
|
|
591
608
|
*/
|
|
592
609
|
public nextStop(x?: number): number {
|
|
593
|
-
|
|
594
|
-
x = this.x;
|
|
595
|
-
}
|
|
610
|
+
x ??= this.x;
|
|
596
611
|
while (!this.tabs[++x] && x < this._cols);
|
|
597
612
|
return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x;
|
|
598
613
|
}
|
|
@@ -8,26 +8,28 @@ import { AttributeData } from 'common/buffer/AttributeData';
|
|
|
8
8
|
import { CellData } from 'common/buffer/CellData';
|
|
9
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
10
|
import { stringFromCodePoint } from 'common/input/TextDecoder';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
import { StringBuilder } from 'common/StringBuilder';
|
|
12
|
+
|
|
13
|
+
// Buffer memory layout:
|
|
14
|
+
//
|
|
15
|
+
// [0]: content `uint32_t` - wcwidth(2) comb(1) codepoint(21)
|
|
16
|
+
// [1]: fg `uint32_t` - flags(8) r(8) g(8) b(8)
|
|
17
|
+
// [2]: bg `uint32_t` - flags(8) r(8) g(8) b(8)
|
|
18
|
+
|
|
19
|
+
const enum Constants {
|
|
20
|
+
/** The number of 32 bit array indices taken by one cell. */
|
|
21
|
+
CELL_INDICIES = 3,
|
|
22
|
+
/** Factor when to cleanup underlying array buffer after shrinking. */
|
|
23
|
+
CLEANUP_THRESHOLD = 2
|
|
24
|
+
}
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* Cell member indices.
|
|
26
28
|
*
|
|
27
29
|
* Direct access:
|
|
28
|
-
* `content = data[column *
|
|
29
|
-
* `fg = data[column *
|
|
30
|
-
* `bg = data[column *
|
|
30
|
+
* `content = data[column * Constants.CELL_INDICIES + Cell.CONTENT];`
|
|
31
|
+
* `fg = data[column * Constants.CELL_INDICIES + Cell.FG];`
|
|
32
|
+
* `bg = data[column * Constants.CELL_INDICIES + Cell.BG];`
|
|
31
33
|
*/
|
|
32
34
|
const enum Cell {
|
|
33
35
|
CONTENT = 0,
|
|
@@ -39,9 +41,20 @@ export const DEFAULT_ATTR_DATA = Object.freeze(new AttributeData());
|
|
|
39
41
|
|
|
40
42
|
// Work variables to avoid garbage collection
|
|
41
43
|
let $startIndex = 0;
|
|
44
|
+
const $workCell = new CellData();
|
|
45
|
+
const $translateToStringBuilder = new StringBuilder();
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
export interface IBufferLineStringCacheEntry {
|
|
48
|
+
value: string | undefined;
|
|
49
|
+
isTrimmed: boolean;
|
|
50
|
+
generation: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IBufferLineStringCache {
|
|
54
|
+
generation: number;
|
|
55
|
+
allocateEntry(): IBufferLineStringCacheEntry;
|
|
56
|
+
touch?(): void;
|
|
57
|
+
}
|
|
45
58
|
|
|
46
59
|
/**
|
|
47
60
|
* Typed array based bufferline implementation.
|
|
@@ -62,11 +75,17 @@ export class BufferLine implements IBufferLine {
|
|
|
62
75
|
protected _data: Uint32Array;
|
|
63
76
|
protected _combined: {[index: number]: string} = {};
|
|
64
77
|
protected _extendedAttrs: {[index: number]: IExtendedAttrs | undefined} = {};
|
|
78
|
+
protected _stringCacheEntryRef: WeakRef<IBufferLineStringCacheEntry> | undefined;
|
|
65
79
|
public length: number;
|
|
66
80
|
|
|
67
|
-
constructor(
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
constructor(
|
|
82
|
+
protected readonly _stringCache: IBufferLineStringCache,
|
|
83
|
+
cols: number,
|
|
84
|
+
fillCellData?: ICellData,
|
|
85
|
+
public isWrapped: boolean = false
|
|
86
|
+
) {
|
|
87
|
+
this._data = new Uint32Array(cols * Constants.CELL_INDICIES);
|
|
88
|
+
const cell = fillCellData ?? CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
|
70
89
|
for (let i = 0; i < cols; ++i) {
|
|
71
90
|
this.setCell(i, cell);
|
|
72
91
|
}
|
|
@@ -78,10 +97,10 @@ export class BufferLine implements IBufferLine {
|
|
|
78
97
|
* @deprecated
|
|
79
98
|
*/
|
|
80
99
|
public get(index: number): CharData {
|
|
81
|
-
const content = this._data[index *
|
|
100
|
+
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
82
101
|
const cp = content & Content.CODEPOINT_MASK;
|
|
83
102
|
return [
|
|
84
|
-
this._data[index *
|
|
103
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG],
|
|
85
104
|
(content & Content.IS_COMBINED_MASK)
|
|
86
105
|
? this._combined[index]
|
|
87
106
|
: (cp) ? stringFromCodePoint(cp) : '',
|
|
@@ -97,12 +116,13 @@ export class BufferLine implements IBufferLine {
|
|
|
97
116
|
* @deprecated
|
|
98
117
|
*/
|
|
99
118
|
public set(index: number, value: CharData): void {
|
|
100
|
-
this.
|
|
119
|
+
this._invalidateStringCache();
|
|
120
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG] = value[CHAR_DATA_ATTR_INDEX];
|
|
101
121
|
if (value[CHAR_DATA_CHAR_INDEX].length > 1) {
|
|
102
122
|
this._combined[index] = value[1];
|
|
103
|
-
this._data[index *
|
|
123
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = index | Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
104
124
|
} else {
|
|
105
|
-
this._data[index *
|
|
125
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
106
126
|
}
|
|
107
127
|
}
|
|
108
128
|
|
|
@@ -111,22 +131,22 @@ export class BufferLine implements IBufferLine {
|
|
|
111
131
|
* use these when only one value is needed, otherwise use `loadCell`
|
|
112
132
|
*/
|
|
113
133
|
public getWidth(index: number): number {
|
|
114
|
-
return this._data[index *
|
|
134
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT;
|
|
115
135
|
}
|
|
116
136
|
|
|
117
137
|
/** Test whether content has width. */
|
|
118
138
|
public hasWidth(index: number): number {
|
|
119
|
-
return this._data[index *
|
|
139
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.WIDTH_MASK;
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
/** Get FG cell component. */
|
|
123
143
|
public getFg(index: number): number {
|
|
124
|
-
return this._data[index *
|
|
144
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.FG];
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
/** Get BG cell component. */
|
|
128
148
|
public getBg(index: number): number {
|
|
129
|
-
return this._data[index *
|
|
149
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.BG];
|
|
130
150
|
}
|
|
131
151
|
|
|
132
152
|
/**
|
|
@@ -135,7 +155,7 @@ export class BufferLine implements IBufferLine {
|
|
|
135
155
|
* from real empty cells.
|
|
136
156
|
*/
|
|
137
157
|
public hasContent(index: number): number {
|
|
138
|
-
return this._data[index *
|
|
158
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK;
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
/**
|
|
@@ -144,7 +164,7 @@ export class BufferLine implements IBufferLine {
|
|
|
144
164
|
* a single UTF32 codepoint or the last codepoint of a combined string.
|
|
145
165
|
*/
|
|
146
166
|
public getCodePoint(index: number): number {
|
|
147
|
-
const content = this._data[index *
|
|
167
|
+
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
148
168
|
if (content & Content.IS_COMBINED_MASK) {
|
|
149
169
|
return this._combined[index].charCodeAt(this._combined[index].length - 1);
|
|
150
170
|
}
|
|
@@ -153,12 +173,12 @@ export class BufferLine implements IBufferLine {
|
|
|
153
173
|
|
|
154
174
|
/** Test whether the cell contains a combined string. */
|
|
155
175
|
public isCombined(index: number): number {
|
|
156
|
-
return this._data[index *
|
|
176
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.IS_COMBINED_MASK;
|
|
157
177
|
}
|
|
158
178
|
|
|
159
179
|
/** Returns the string content of the cell. */
|
|
160
180
|
public getString(index: number): string {
|
|
161
|
-
const content = this._data[index *
|
|
181
|
+
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
162
182
|
if (content & Content.IS_COMBINED_MASK) {
|
|
163
183
|
return this._combined[index];
|
|
164
184
|
}
|
|
@@ -171,7 +191,7 @@ export class BufferLine implements IBufferLine {
|
|
|
171
191
|
|
|
172
192
|
/** Get state of protected flag. */
|
|
173
193
|
public isProtected(index: number): number {
|
|
174
|
-
return this._data[index *
|
|
194
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.BG] & BgFlags.PROTECTED;
|
|
175
195
|
}
|
|
176
196
|
|
|
177
197
|
/**
|
|
@@ -179,7 +199,7 @@ export class BufferLine implements IBufferLine {
|
|
|
179
199
|
* to GC as it significantly reduced the amount of new objects/references needed.
|
|
180
200
|
*/
|
|
181
201
|
public loadCell(index: number, cell: ICellData): ICellData {
|
|
182
|
-
$startIndex = index *
|
|
202
|
+
$startIndex = index * Constants.CELL_INDICIES;
|
|
183
203
|
cell.content = this._data[$startIndex + Cell.CONTENT];
|
|
184
204
|
cell.fg = this._data[$startIndex + Cell.FG];
|
|
185
205
|
cell.bg = this._data[$startIndex + Cell.BG];
|
|
@@ -196,15 +216,16 @@ export class BufferLine implements IBufferLine {
|
|
|
196
216
|
* Set data at `index` to `cell`.
|
|
197
217
|
*/
|
|
198
218
|
public setCell(index: number, cell: ICellData): void {
|
|
219
|
+
this._invalidateStringCache();
|
|
199
220
|
if (cell.content & Content.IS_COMBINED_MASK) {
|
|
200
221
|
this._combined[index] = cell.combinedData;
|
|
201
222
|
}
|
|
202
223
|
if (cell.bg & BgFlags.HAS_EXTENDED) {
|
|
203
224
|
this._extendedAttrs[index] = cell.extended;
|
|
204
225
|
}
|
|
205
|
-
this._data[index *
|
|
206
|
-
this._data[index *
|
|
207
|
-
this._data[index *
|
|
226
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = cell.content;
|
|
227
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG] = cell.fg;
|
|
228
|
+
this._data[index * Constants.CELL_INDICIES + Cell.BG] = cell.bg;
|
|
208
229
|
}
|
|
209
230
|
|
|
210
231
|
/**
|
|
@@ -213,12 +234,13 @@ export class BufferLine implements IBufferLine {
|
|
|
213
234
|
* it gets an optimized access method.
|
|
214
235
|
*/
|
|
215
236
|
public setCellFromCodepoint(index: number, codePoint: number, width: number, attrs: IAttributeData): void {
|
|
237
|
+
this._invalidateStringCache();
|
|
216
238
|
if (attrs.bg & BgFlags.HAS_EXTENDED) {
|
|
217
239
|
this._extendedAttrs[index] = attrs.extended;
|
|
218
240
|
}
|
|
219
|
-
this._data[index *
|
|
220
|
-
this._data[index *
|
|
221
|
-
this._data[index *
|
|
241
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT);
|
|
242
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG] = attrs.fg;
|
|
243
|
+
this._data[index * Constants.CELL_INDICIES + Cell.BG] = attrs.bg;
|
|
222
244
|
}
|
|
223
245
|
|
|
224
246
|
/**
|
|
@@ -228,7 +250,8 @@ export class BufferLine implements IBufferLine {
|
|
|
228
250
|
* by the previous `setDataFromCodePoint` call, we can omit it here.
|
|
229
251
|
*/
|
|
230
252
|
public addCodepointToCell(index: number, codePoint: number, width: number): void {
|
|
231
|
-
|
|
253
|
+
this._invalidateStringCache();
|
|
254
|
+
let content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
232
255
|
if (content & Content.IS_COMBINED_MASK) {
|
|
233
256
|
// we already have a combined string, simply add
|
|
234
257
|
this._combined[index] += stringFromCodePoint(codePoint);
|
|
@@ -250,10 +273,11 @@ export class BufferLine implements IBufferLine {
|
|
|
250
273
|
content &= ~Content.WIDTH_MASK;
|
|
251
274
|
content |= width << Content.WIDTH_SHIFT;
|
|
252
275
|
}
|
|
253
|
-
this._data[index *
|
|
276
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = content;
|
|
254
277
|
}
|
|
255
278
|
|
|
256
279
|
public insertCells(pos: number, n: number, fillCellData: ICellData): void {
|
|
280
|
+
this._invalidateStringCache();
|
|
257
281
|
pos %= this.length;
|
|
258
282
|
|
|
259
283
|
// handle fullwidth at pos: reset cell one to the left if pos is second cell of a wide char
|
|
@@ -262,9 +286,8 @@ export class BufferLine implements IBufferLine {
|
|
|
262
286
|
}
|
|
263
287
|
|
|
264
288
|
if (n < this.length - pos) {
|
|
265
|
-
const cell = new CellData();
|
|
266
289
|
for (let i = this.length - pos - n - 1; i >= 0; --i) {
|
|
267
|
-
this.setCell(pos + n + i, this.loadCell(pos + i,
|
|
290
|
+
this.setCell(pos + n + i, this.loadCell(pos + i, $workCell));
|
|
268
291
|
}
|
|
269
292
|
for (let i = 0; i < n; ++i) {
|
|
270
293
|
this.setCell(pos + i, fillCellData);
|
|
@@ -282,11 +305,11 @@ export class BufferLine implements IBufferLine {
|
|
|
282
305
|
}
|
|
283
306
|
|
|
284
307
|
public deleteCells(pos: number, n: number, fillCellData: ICellData): void {
|
|
308
|
+
this._invalidateStringCache();
|
|
285
309
|
pos %= this.length;
|
|
286
310
|
if (n < this.length - pos) {
|
|
287
|
-
const cell = new CellData();
|
|
288
311
|
for (let i = 0; i < this.length - pos - n; ++i) {
|
|
289
|
-
this.setCell(pos + i, this.loadCell(pos + n + i,
|
|
312
|
+
this.setCell(pos + i, this.loadCell(pos + n + i, $workCell));
|
|
290
313
|
}
|
|
291
314
|
for (let i = this.length - n; i < this.length; ++i) {
|
|
292
315
|
this.setCell(i, fillCellData);
|
|
@@ -309,6 +332,7 @@ export class BufferLine implements IBufferLine {
|
|
|
309
332
|
}
|
|
310
333
|
|
|
311
334
|
public replaceCells(start: number, end: number, fillCellData: ICellData, respectProtect: boolean = false): void {
|
|
335
|
+
this._invalidateStringCache();
|
|
312
336
|
// full branching on respectProtect==true, hopefully getting fast JIT for standard case
|
|
313
337
|
if (respectProtect) {
|
|
314
338
|
if (start && this.getWidth(start - 1) === 2 && !this.isProtected(start - 1)) {
|
|
@@ -345,13 +369,14 @@ export class BufferLine implements IBufferLine {
|
|
|
345
369
|
* The underlying array buffer will not change if there is still enough space
|
|
346
370
|
* to hold the new buffer line data.
|
|
347
371
|
* Returns a boolean indicating, whether a `cleanupMemory` call would free
|
|
348
|
-
* excess memory (true after shrinking > CLEANUP_THRESHOLD).
|
|
372
|
+
* excess memory (true after shrinking > Constants.CLEANUP_THRESHOLD).
|
|
349
373
|
*/
|
|
350
374
|
public resize(cols: number, fillCellData: ICellData): boolean {
|
|
375
|
+
this._invalidateStringCache();
|
|
351
376
|
if (cols === this.length) {
|
|
352
|
-
return this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
377
|
+
return this._data.length * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
353
378
|
}
|
|
354
|
-
const uint32Cells = cols *
|
|
379
|
+
const uint32Cells = cols * Constants.CELL_INDICIES;
|
|
355
380
|
if (cols > this.length) {
|
|
356
381
|
if (this._data.buffer.byteLength >= uint32Cells * 4) {
|
|
357
382
|
// optimization: avoid alloc and data copy if buffer has enough room
|
|
@@ -386,17 +411,17 @@ export class BufferLine implements IBufferLine {
|
|
|
386
411
|
}
|
|
387
412
|
}
|
|
388
413
|
this.length = cols;
|
|
389
|
-
return uint32Cells * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
414
|
+
return uint32Cells * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
390
415
|
}
|
|
391
416
|
|
|
392
417
|
/**
|
|
393
418
|
* Cleanup underlying array buffer.
|
|
394
419
|
* A cleanup will be triggered if the array buffer exceeds the actual used
|
|
395
|
-
* memory by a factor of CLEANUP_THRESHOLD.
|
|
420
|
+
* memory by a factor of Constants.CLEANUP_THRESHOLD.
|
|
396
421
|
* Returns 0 or 1 indicating whether a cleanup happened.
|
|
397
422
|
*/
|
|
398
423
|
public cleanupMemory(): number {
|
|
399
|
-
if (this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
|
|
424
|
+
if (this._data.length * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
|
|
400
425
|
const data = new Uint32Array(this._data.length);
|
|
401
426
|
data.set(this._data);
|
|
402
427
|
this._data = data;
|
|
@@ -407,6 +432,7 @@ export class BufferLine implements IBufferLine {
|
|
|
407
432
|
|
|
408
433
|
/** fill a line with fillCharData */
|
|
409
434
|
public fill(fillCellData: ICellData, respectProtect: boolean = false): void {
|
|
435
|
+
this._invalidateStringCache();
|
|
410
436
|
// full branching on respectProtect==true, hopefully getting fast JIT for standard case
|
|
411
437
|
if (respectProtect) {
|
|
412
438
|
for (let i = 0; i < this.length; ++i) {
|
|
@@ -425,6 +451,7 @@ export class BufferLine implements IBufferLine {
|
|
|
425
451
|
|
|
426
452
|
/** alter to a full copy of line */
|
|
427
453
|
public copyFrom(line: BufferLine): void {
|
|
454
|
+
this._invalidateStringCache();
|
|
428
455
|
if (this.length !== line.length) {
|
|
429
456
|
this._data = new Uint32Array(line._data);
|
|
430
457
|
} else {
|
|
@@ -445,7 +472,7 @@ export class BufferLine implements IBufferLine {
|
|
|
445
472
|
|
|
446
473
|
/** create a new clone */
|
|
447
474
|
public clone(): IBufferLine {
|
|
448
|
-
const newLine = new BufferLine(0);
|
|
475
|
+
const newLine = new BufferLine(this._stringCache, 0, undefined, false);
|
|
449
476
|
newLine._data = new Uint32Array(this._data);
|
|
450
477
|
newLine.length = this.length;
|
|
451
478
|
for (const el in this._combined) {
|
|
@@ -460,8 +487,8 @@ export class BufferLine implements IBufferLine {
|
|
|
460
487
|
|
|
461
488
|
public getTrimmedLength(): number {
|
|
462
489
|
for (let i = this.length - 1; i >= 0; --i) {
|
|
463
|
-
if ((this._data[i *
|
|
464
|
-
return i + (this._data[i *
|
|
490
|
+
if ((this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK)) {
|
|
491
|
+
return i + (this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT);
|
|
465
492
|
}
|
|
466
493
|
}
|
|
467
494
|
return 0;
|
|
@@ -469,30 +496,31 @@ export class BufferLine implements IBufferLine {
|
|
|
469
496
|
|
|
470
497
|
public getNoBgTrimmedLength(): number {
|
|
471
498
|
for (let i = this.length - 1; i >= 0; --i) {
|
|
472
|
-
if ((this._data[i *
|
|
473
|
-
return i + (this._data[i *
|
|
499
|
+
if ((this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK) || (this._data[i * Constants.CELL_INDICIES + Cell.BG] & Attributes.CM_MASK)) {
|
|
500
|
+
return i + (this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT);
|
|
474
501
|
}
|
|
475
502
|
}
|
|
476
503
|
return 0;
|
|
477
504
|
}
|
|
478
505
|
|
|
479
506
|
public copyCellsFrom(src: BufferLine, srcCol: number, destCol: number, length: number, applyInReverse: boolean): void {
|
|
507
|
+
this._invalidateStringCache();
|
|
480
508
|
const srcData = src._data;
|
|
481
509
|
if (applyInReverse) {
|
|
482
510
|
for (let cell = length - 1; cell >= 0; cell--) {
|
|
483
|
-
for (let i = 0; i <
|
|
484
|
-
this._data[(destCol + cell) *
|
|
511
|
+
for (let i = 0; i < Constants.CELL_INDICIES; i++) {
|
|
512
|
+
this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i];
|
|
485
513
|
}
|
|
486
|
-
if (srcData[(srcCol + cell) *
|
|
514
|
+
if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
|
487
515
|
this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
|
|
488
516
|
}
|
|
489
517
|
}
|
|
490
518
|
} else {
|
|
491
519
|
for (let cell = 0; cell < length; cell++) {
|
|
492
|
-
for (let i = 0; i <
|
|
493
|
-
this._data[(destCol + cell) *
|
|
520
|
+
for (let i = 0; i < Constants.CELL_INDICIES; i++) {
|
|
521
|
+
this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i];
|
|
494
522
|
}
|
|
495
|
-
if (srcData[(srcCol + cell) *
|
|
523
|
+
if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
|
496
524
|
this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
|
|
497
525
|
}
|
|
498
526
|
}
|
|
@@ -509,7 +537,8 @@ export class BufferLine implements IBufferLine {
|
|
|
509
537
|
}
|
|
510
538
|
|
|
511
539
|
/**
|
|
512
|
-
* Translates the buffer line to a string.
|
|
540
|
+
* Translates the buffer line to a string. Caching only applies to canonical full-line translation
|
|
541
|
+
* requests (regardless of `trimRight` value).
|
|
513
542
|
*
|
|
514
543
|
* @param trimRight Whether to trim any empty cells on the right.
|
|
515
544
|
* @param startCol The column to start the string (0-based inclusive).
|
|
@@ -522,6 +551,19 @@ export class BufferLine implements IBufferLine {
|
|
|
522
551
|
* returned string, the corresponding entries in `outColumns` will have the same column number.
|
|
523
552
|
*/
|
|
524
553
|
public translateToString(trimRight?: boolean, startCol?: number, endCol?: number, outColumns?: number[]): string {
|
|
554
|
+
const isCanonicalRequest = (startCol === undefined || startCol === 0) && endCol === undefined && outColumns === undefined;
|
|
555
|
+
if (isCanonicalRequest) {
|
|
556
|
+
this._stringCache.touch?.();
|
|
557
|
+
}
|
|
558
|
+
const stringCacheEntry = isCanonicalRequest ? this._getStringCacheEntry(false) : undefined;
|
|
559
|
+
if (isCanonicalRequest && stringCacheEntry?.value !== undefined) {
|
|
560
|
+
if (trimRight) {
|
|
561
|
+
return stringCacheEntry.isTrimmed ? stringCacheEntry.value : stringCacheEntry.value.trimEnd();
|
|
562
|
+
}
|
|
563
|
+
if (!stringCacheEntry.isTrimmed) {
|
|
564
|
+
return stringCacheEntry.value;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
525
567
|
startCol = startCol ?? 0;
|
|
526
568
|
endCol = endCol ?? this.length;
|
|
527
569
|
if (trimRight) {
|
|
@@ -530,12 +572,12 @@ export class BufferLine implements IBufferLine {
|
|
|
530
572
|
if (outColumns) {
|
|
531
573
|
outColumns.length = 0;
|
|
532
574
|
}
|
|
533
|
-
|
|
575
|
+
$translateToStringBuilder.reset();
|
|
534
576
|
while (startCol < endCol) {
|
|
535
|
-
const content = this._data[startCol *
|
|
577
|
+
const content = this._data[startCol * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
536
578
|
const cp = content & Content.CODEPOINT_MASK;
|
|
537
579
|
const chars = (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR;
|
|
538
|
-
|
|
580
|
+
$translateToStringBuilder.append(chars);
|
|
539
581
|
if (outColumns) {
|
|
540
582
|
for (let i = 0; i < chars.length; ++i) {
|
|
541
583
|
outColumns.push(startCol);
|
|
@@ -546,6 +588,36 @@ export class BufferLine implements IBufferLine {
|
|
|
546
588
|
if (outColumns) {
|
|
547
589
|
outColumns.push(startCol);
|
|
548
590
|
}
|
|
591
|
+
const result = $translateToStringBuilder.toString();
|
|
592
|
+
$translateToStringBuilder.reset();
|
|
593
|
+
if (isCanonicalRequest) {
|
|
594
|
+
const cacheEntry = this._getStringCacheEntry(true)!;
|
|
595
|
+
cacheEntry.value = result;
|
|
596
|
+
cacheEntry.isTrimmed = !!trimRight;
|
|
597
|
+
}
|
|
549
598
|
return result;
|
|
550
599
|
}
|
|
600
|
+
|
|
601
|
+
protected _getStringCacheEntry(createIfNeeded: boolean): IBufferLineStringCacheEntry | undefined {
|
|
602
|
+
const cachedEntry = this._stringCacheEntryRef?.deref();
|
|
603
|
+
if (cachedEntry) {
|
|
604
|
+
if (cachedEntry.generation === this._stringCache.generation) {
|
|
605
|
+
return cachedEntry;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (!createIfNeeded) {
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
611
|
+
const cacheEntry = this._stringCache.allocateEntry();
|
|
612
|
+
this._stringCacheEntryRef = new WeakRef(cacheEntry);
|
|
613
|
+
return cacheEntry;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
private _invalidateStringCache(): void {
|
|
617
|
+
const cacheEntry = this._getStringCacheEntry(false);
|
|
618
|
+
if (cacheEntry) {
|
|
619
|
+
cacheEntry.value = undefined;
|
|
620
|
+
cacheEntry.isTrimmed = false;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
551
623
|
}
|