@xterm/xterm 6.1.0-beta.24 → 6.1.0-beta.241
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 +31 -21
- package/src/common/Event.ts +118 -0
- package/src/common/InputHandler.ts +283 -85
- 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 +133 -65
- 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 +69 -32
- 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 +258 -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
|
}
|
|
@@ -9,25 +9,26 @@ 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
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
|
|
12
|
+
// Buffer memory layout:
|
|
13
|
+
//
|
|
14
|
+
// [0]: content `uint32_t` - wcwidth(2) comb(1) codepoint(21)
|
|
15
|
+
// [1]: fg `uint32_t` - flags(8) r(8) g(8) b(8)
|
|
16
|
+
// [2]: bg `uint32_t` - flags(8) r(8) g(8) b(8)
|
|
17
|
+
|
|
18
|
+
const enum Constants {
|
|
19
|
+
/** The number of 32 bit array indices taken by one cell. */
|
|
20
|
+
CELL_INDICIES = 3,
|
|
21
|
+
/** Factor when to cleanup underlying array buffer after shrinking. */
|
|
22
|
+
CLEANUP_THRESHOLD = 2
|
|
23
|
+
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Cell member indices.
|
|
26
27
|
*
|
|
27
28
|
* Direct access:
|
|
28
|
-
* `content = data[column *
|
|
29
|
-
* `fg = data[column *
|
|
30
|
-
* `bg = data[column *
|
|
29
|
+
* `content = data[column * Constants.CELL_INDICIES + Cell.CONTENT];`
|
|
30
|
+
* `fg = data[column * Constants.CELL_INDICIES + Cell.FG];`
|
|
31
|
+
* `bg = data[column * Constants.CELL_INDICIES + Cell.BG];`
|
|
31
32
|
*/
|
|
32
33
|
const enum Cell {
|
|
33
34
|
CONTENT = 0,
|
|
@@ -39,9 +40,19 @@ export const DEFAULT_ATTR_DATA = Object.freeze(new AttributeData());
|
|
|
39
40
|
|
|
40
41
|
// Work variables to avoid garbage collection
|
|
41
42
|
let $startIndex = 0;
|
|
43
|
+
const $workCell = new CellData();
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
export interface IBufferLineStringCacheEntry {
|
|
46
|
+
value: string | undefined;
|
|
47
|
+
isTrimmed: boolean;
|
|
48
|
+
generation: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface IBufferLineStringCache {
|
|
52
|
+
generation: number;
|
|
53
|
+
allocateEntry(): IBufferLineStringCacheEntry;
|
|
54
|
+
touch?(): void;
|
|
55
|
+
}
|
|
45
56
|
|
|
46
57
|
/**
|
|
47
58
|
* Typed array based bufferline implementation.
|
|
@@ -62,11 +73,17 @@ export class BufferLine implements IBufferLine {
|
|
|
62
73
|
protected _data: Uint32Array;
|
|
63
74
|
protected _combined: {[index: number]: string} = {};
|
|
64
75
|
protected _extendedAttrs: {[index: number]: IExtendedAttrs | undefined} = {};
|
|
76
|
+
protected _stringCacheEntryRef: WeakRef<IBufferLineStringCacheEntry> | undefined;
|
|
65
77
|
public length: number;
|
|
66
78
|
|
|
67
|
-
constructor(
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
constructor(
|
|
80
|
+
protected readonly _stringCache: IBufferLineStringCache,
|
|
81
|
+
cols: number,
|
|
82
|
+
fillCellData?: ICellData,
|
|
83
|
+
public isWrapped: boolean = false
|
|
84
|
+
) {
|
|
85
|
+
this._data = new Uint32Array(cols * Constants.CELL_INDICIES);
|
|
86
|
+
const cell = fillCellData ?? CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
|
70
87
|
for (let i = 0; i < cols; ++i) {
|
|
71
88
|
this.setCell(i, cell);
|
|
72
89
|
}
|
|
@@ -78,10 +95,10 @@ export class BufferLine implements IBufferLine {
|
|
|
78
95
|
* @deprecated
|
|
79
96
|
*/
|
|
80
97
|
public get(index: number): CharData {
|
|
81
|
-
const content = this._data[index *
|
|
98
|
+
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
82
99
|
const cp = content & Content.CODEPOINT_MASK;
|
|
83
100
|
return [
|
|
84
|
-
this._data[index *
|
|
101
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG],
|
|
85
102
|
(content & Content.IS_COMBINED_MASK)
|
|
86
103
|
? this._combined[index]
|
|
87
104
|
: (cp) ? stringFromCodePoint(cp) : '',
|
|
@@ -97,12 +114,13 @@ export class BufferLine implements IBufferLine {
|
|
|
97
114
|
* @deprecated
|
|
98
115
|
*/
|
|
99
116
|
public set(index: number, value: CharData): void {
|
|
100
|
-
this.
|
|
117
|
+
this._invalidateStringCache();
|
|
118
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG] = value[CHAR_DATA_ATTR_INDEX];
|
|
101
119
|
if (value[CHAR_DATA_CHAR_INDEX].length > 1) {
|
|
102
120
|
this._combined[index] = value[1];
|
|
103
|
-
this._data[index *
|
|
121
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = index | Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
104
122
|
} else {
|
|
105
|
-
this._data[index *
|
|
123
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
106
124
|
}
|
|
107
125
|
}
|
|
108
126
|
|
|
@@ -111,22 +129,22 @@ export class BufferLine implements IBufferLine {
|
|
|
111
129
|
* use these when only one value is needed, otherwise use `loadCell`
|
|
112
130
|
*/
|
|
113
131
|
public getWidth(index: number): number {
|
|
114
|
-
return this._data[index *
|
|
132
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT;
|
|
115
133
|
}
|
|
116
134
|
|
|
117
135
|
/** Test whether content has width. */
|
|
118
136
|
public hasWidth(index: number): number {
|
|
119
|
-
return this._data[index *
|
|
137
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.WIDTH_MASK;
|
|
120
138
|
}
|
|
121
139
|
|
|
122
140
|
/** Get FG cell component. */
|
|
123
141
|
public getFg(index: number): number {
|
|
124
|
-
return this._data[index *
|
|
142
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.FG];
|
|
125
143
|
}
|
|
126
144
|
|
|
127
145
|
/** Get BG cell component. */
|
|
128
146
|
public getBg(index: number): number {
|
|
129
|
-
return this._data[index *
|
|
147
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.BG];
|
|
130
148
|
}
|
|
131
149
|
|
|
132
150
|
/**
|
|
@@ -135,7 +153,7 @@ export class BufferLine implements IBufferLine {
|
|
|
135
153
|
* from real empty cells.
|
|
136
154
|
*/
|
|
137
155
|
public hasContent(index: number): number {
|
|
138
|
-
return this._data[index *
|
|
156
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK;
|
|
139
157
|
}
|
|
140
158
|
|
|
141
159
|
/**
|
|
@@ -144,7 +162,7 @@ export class BufferLine implements IBufferLine {
|
|
|
144
162
|
* a single UTF32 codepoint or the last codepoint of a combined string.
|
|
145
163
|
*/
|
|
146
164
|
public getCodePoint(index: number): number {
|
|
147
|
-
const content = this._data[index *
|
|
165
|
+
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
148
166
|
if (content & Content.IS_COMBINED_MASK) {
|
|
149
167
|
return this._combined[index].charCodeAt(this._combined[index].length - 1);
|
|
150
168
|
}
|
|
@@ -153,12 +171,12 @@ export class BufferLine implements IBufferLine {
|
|
|
153
171
|
|
|
154
172
|
/** Test whether the cell contains a combined string. */
|
|
155
173
|
public isCombined(index: number): number {
|
|
156
|
-
return this._data[index *
|
|
174
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.IS_COMBINED_MASK;
|
|
157
175
|
}
|
|
158
176
|
|
|
159
177
|
/** Returns the string content of the cell. */
|
|
160
178
|
public getString(index: number): string {
|
|
161
|
-
const content = this._data[index *
|
|
179
|
+
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
162
180
|
if (content & Content.IS_COMBINED_MASK) {
|
|
163
181
|
return this._combined[index];
|
|
164
182
|
}
|
|
@@ -171,7 +189,7 @@ export class BufferLine implements IBufferLine {
|
|
|
171
189
|
|
|
172
190
|
/** Get state of protected flag. */
|
|
173
191
|
public isProtected(index: number): number {
|
|
174
|
-
return this._data[index *
|
|
192
|
+
return this._data[index * Constants.CELL_INDICIES + Cell.BG] & BgFlags.PROTECTED;
|
|
175
193
|
}
|
|
176
194
|
|
|
177
195
|
/**
|
|
@@ -179,7 +197,7 @@ export class BufferLine implements IBufferLine {
|
|
|
179
197
|
* to GC as it significantly reduced the amount of new objects/references needed.
|
|
180
198
|
*/
|
|
181
199
|
public loadCell(index: number, cell: ICellData): ICellData {
|
|
182
|
-
$startIndex = index *
|
|
200
|
+
$startIndex = index * Constants.CELL_INDICIES;
|
|
183
201
|
cell.content = this._data[$startIndex + Cell.CONTENT];
|
|
184
202
|
cell.fg = this._data[$startIndex + Cell.FG];
|
|
185
203
|
cell.bg = this._data[$startIndex + Cell.BG];
|
|
@@ -196,15 +214,16 @@ export class BufferLine implements IBufferLine {
|
|
|
196
214
|
* Set data at `index` to `cell`.
|
|
197
215
|
*/
|
|
198
216
|
public setCell(index: number, cell: ICellData): void {
|
|
217
|
+
this._invalidateStringCache();
|
|
199
218
|
if (cell.content & Content.IS_COMBINED_MASK) {
|
|
200
219
|
this._combined[index] = cell.combinedData;
|
|
201
220
|
}
|
|
202
221
|
if (cell.bg & BgFlags.HAS_EXTENDED) {
|
|
203
222
|
this._extendedAttrs[index] = cell.extended;
|
|
204
223
|
}
|
|
205
|
-
this._data[index *
|
|
206
|
-
this._data[index *
|
|
207
|
-
this._data[index *
|
|
224
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = cell.content;
|
|
225
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG] = cell.fg;
|
|
226
|
+
this._data[index * Constants.CELL_INDICIES + Cell.BG] = cell.bg;
|
|
208
227
|
}
|
|
209
228
|
|
|
210
229
|
/**
|
|
@@ -213,12 +232,13 @@ export class BufferLine implements IBufferLine {
|
|
|
213
232
|
* it gets an optimized access method.
|
|
214
233
|
*/
|
|
215
234
|
public setCellFromCodepoint(index: number, codePoint: number, width: number, attrs: IAttributeData): void {
|
|
235
|
+
this._invalidateStringCache();
|
|
216
236
|
if (attrs.bg & BgFlags.HAS_EXTENDED) {
|
|
217
237
|
this._extendedAttrs[index] = attrs.extended;
|
|
218
238
|
}
|
|
219
|
-
this._data[index *
|
|
220
|
-
this._data[index *
|
|
221
|
-
this._data[index *
|
|
239
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT);
|
|
240
|
+
this._data[index * Constants.CELL_INDICIES + Cell.FG] = attrs.fg;
|
|
241
|
+
this._data[index * Constants.CELL_INDICIES + Cell.BG] = attrs.bg;
|
|
222
242
|
}
|
|
223
243
|
|
|
224
244
|
/**
|
|
@@ -228,7 +248,8 @@ export class BufferLine implements IBufferLine {
|
|
|
228
248
|
* by the previous `setDataFromCodePoint` call, we can omit it here.
|
|
229
249
|
*/
|
|
230
250
|
public addCodepointToCell(index: number, codePoint: number, width: number): void {
|
|
231
|
-
|
|
251
|
+
this._invalidateStringCache();
|
|
252
|
+
let content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
232
253
|
if (content & Content.IS_COMBINED_MASK) {
|
|
233
254
|
// we already have a combined string, simply add
|
|
234
255
|
this._combined[index] += stringFromCodePoint(codePoint);
|
|
@@ -250,10 +271,11 @@ export class BufferLine implements IBufferLine {
|
|
|
250
271
|
content &= ~Content.WIDTH_MASK;
|
|
251
272
|
content |= width << Content.WIDTH_SHIFT;
|
|
252
273
|
}
|
|
253
|
-
this._data[index *
|
|
274
|
+
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = content;
|
|
254
275
|
}
|
|
255
276
|
|
|
256
277
|
public insertCells(pos: number, n: number, fillCellData: ICellData): void {
|
|
278
|
+
this._invalidateStringCache();
|
|
257
279
|
pos %= this.length;
|
|
258
280
|
|
|
259
281
|
// handle fullwidth at pos: reset cell one to the left if pos is second cell of a wide char
|
|
@@ -262,9 +284,8 @@ export class BufferLine implements IBufferLine {
|
|
|
262
284
|
}
|
|
263
285
|
|
|
264
286
|
if (n < this.length - pos) {
|
|
265
|
-
const cell = new CellData();
|
|
266
287
|
for (let i = this.length - pos - n - 1; i >= 0; --i) {
|
|
267
|
-
this.setCell(pos + n + i, this.loadCell(pos + i,
|
|
288
|
+
this.setCell(pos + n + i, this.loadCell(pos + i, $workCell));
|
|
268
289
|
}
|
|
269
290
|
for (let i = 0; i < n; ++i) {
|
|
270
291
|
this.setCell(pos + i, fillCellData);
|
|
@@ -282,11 +303,11 @@ export class BufferLine implements IBufferLine {
|
|
|
282
303
|
}
|
|
283
304
|
|
|
284
305
|
public deleteCells(pos: number, n: number, fillCellData: ICellData): void {
|
|
306
|
+
this._invalidateStringCache();
|
|
285
307
|
pos %= this.length;
|
|
286
308
|
if (n < this.length - pos) {
|
|
287
|
-
const cell = new CellData();
|
|
288
309
|
for (let i = 0; i < this.length - pos - n; ++i) {
|
|
289
|
-
this.setCell(pos + i, this.loadCell(pos + n + i,
|
|
310
|
+
this.setCell(pos + i, this.loadCell(pos + n + i, $workCell));
|
|
290
311
|
}
|
|
291
312
|
for (let i = this.length - n; i < this.length; ++i) {
|
|
292
313
|
this.setCell(i, fillCellData);
|
|
@@ -309,6 +330,7 @@ export class BufferLine implements IBufferLine {
|
|
|
309
330
|
}
|
|
310
331
|
|
|
311
332
|
public replaceCells(start: number, end: number, fillCellData: ICellData, respectProtect: boolean = false): void {
|
|
333
|
+
this._invalidateStringCache();
|
|
312
334
|
// full branching on respectProtect==true, hopefully getting fast JIT for standard case
|
|
313
335
|
if (respectProtect) {
|
|
314
336
|
if (start && this.getWidth(start - 1) === 2 && !this.isProtected(start - 1)) {
|
|
@@ -345,13 +367,14 @@ export class BufferLine implements IBufferLine {
|
|
|
345
367
|
* The underlying array buffer will not change if there is still enough space
|
|
346
368
|
* to hold the new buffer line data.
|
|
347
369
|
* Returns a boolean indicating, whether a `cleanupMemory` call would free
|
|
348
|
-
* excess memory (true after shrinking > CLEANUP_THRESHOLD).
|
|
370
|
+
* excess memory (true after shrinking > Constants.CLEANUP_THRESHOLD).
|
|
349
371
|
*/
|
|
350
372
|
public resize(cols: number, fillCellData: ICellData): boolean {
|
|
373
|
+
this._invalidateStringCache();
|
|
351
374
|
if (cols === this.length) {
|
|
352
|
-
return this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
375
|
+
return this._data.length * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
353
376
|
}
|
|
354
|
-
const uint32Cells = cols *
|
|
377
|
+
const uint32Cells = cols * Constants.CELL_INDICIES;
|
|
355
378
|
if (cols > this.length) {
|
|
356
379
|
if (this._data.buffer.byteLength >= uint32Cells * 4) {
|
|
357
380
|
// optimization: avoid alloc and data copy if buffer has enough room
|
|
@@ -386,17 +409,17 @@ export class BufferLine implements IBufferLine {
|
|
|
386
409
|
}
|
|
387
410
|
}
|
|
388
411
|
this.length = cols;
|
|
389
|
-
return uint32Cells * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
412
|
+
return uint32Cells * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength;
|
|
390
413
|
}
|
|
391
414
|
|
|
392
415
|
/**
|
|
393
416
|
* Cleanup underlying array buffer.
|
|
394
417
|
* A cleanup will be triggered if the array buffer exceeds the actual used
|
|
395
|
-
* memory by a factor of CLEANUP_THRESHOLD.
|
|
418
|
+
* memory by a factor of Constants.CLEANUP_THRESHOLD.
|
|
396
419
|
* Returns 0 or 1 indicating whether a cleanup happened.
|
|
397
420
|
*/
|
|
398
421
|
public cleanupMemory(): number {
|
|
399
|
-
if (this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
|
|
422
|
+
if (this._data.length * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
|
|
400
423
|
const data = new Uint32Array(this._data.length);
|
|
401
424
|
data.set(this._data);
|
|
402
425
|
this._data = data;
|
|
@@ -407,6 +430,7 @@ export class BufferLine implements IBufferLine {
|
|
|
407
430
|
|
|
408
431
|
/** fill a line with fillCharData */
|
|
409
432
|
public fill(fillCellData: ICellData, respectProtect: boolean = false): void {
|
|
433
|
+
this._invalidateStringCache();
|
|
410
434
|
// full branching on respectProtect==true, hopefully getting fast JIT for standard case
|
|
411
435
|
if (respectProtect) {
|
|
412
436
|
for (let i = 0; i < this.length; ++i) {
|
|
@@ -425,6 +449,7 @@ export class BufferLine implements IBufferLine {
|
|
|
425
449
|
|
|
426
450
|
/** alter to a full copy of line */
|
|
427
451
|
public copyFrom(line: BufferLine): void {
|
|
452
|
+
this._invalidateStringCache();
|
|
428
453
|
if (this.length !== line.length) {
|
|
429
454
|
this._data = new Uint32Array(line._data);
|
|
430
455
|
} else {
|
|
@@ -445,7 +470,7 @@ export class BufferLine implements IBufferLine {
|
|
|
445
470
|
|
|
446
471
|
/** create a new clone */
|
|
447
472
|
public clone(): IBufferLine {
|
|
448
|
-
const newLine = new BufferLine(0);
|
|
473
|
+
const newLine = new BufferLine(this._stringCache, 0, undefined, false);
|
|
449
474
|
newLine._data = new Uint32Array(this._data);
|
|
450
475
|
newLine.length = this.length;
|
|
451
476
|
for (const el in this._combined) {
|
|
@@ -460,8 +485,8 @@ export class BufferLine implements IBufferLine {
|
|
|
460
485
|
|
|
461
486
|
public getTrimmedLength(): number {
|
|
462
487
|
for (let i = this.length - 1; i >= 0; --i) {
|
|
463
|
-
if ((this._data[i *
|
|
464
|
-
return i + (this._data[i *
|
|
488
|
+
if ((this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK)) {
|
|
489
|
+
return i + (this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT);
|
|
465
490
|
}
|
|
466
491
|
}
|
|
467
492
|
return 0;
|
|
@@ -469,30 +494,31 @@ export class BufferLine implements IBufferLine {
|
|
|
469
494
|
|
|
470
495
|
public getNoBgTrimmedLength(): number {
|
|
471
496
|
for (let i = this.length - 1; i >= 0; --i) {
|
|
472
|
-
if ((this._data[i *
|
|
473
|
-
return i + (this._data[i *
|
|
497
|
+
if ((this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK) || (this._data[i * Constants.CELL_INDICIES + Cell.BG] & Attributes.CM_MASK)) {
|
|
498
|
+
return i + (this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT);
|
|
474
499
|
}
|
|
475
500
|
}
|
|
476
501
|
return 0;
|
|
477
502
|
}
|
|
478
503
|
|
|
479
504
|
public copyCellsFrom(src: BufferLine, srcCol: number, destCol: number, length: number, applyInReverse: boolean): void {
|
|
505
|
+
this._invalidateStringCache();
|
|
480
506
|
const srcData = src._data;
|
|
481
507
|
if (applyInReverse) {
|
|
482
508
|
for (let cell = length - 1; cell >= 0; cell--) {
|
|
483
|
-
for (let i = 0; i <
|
|
484
|
-
this._data[(destCol + cell) *
|
|
509
|
+
for (let i = 0; i < Constants.CELL_INDICIES; i++) {
|
|
510
|
+
this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i];
|
|
485
511
|
}
|
|
486
|
-
if (srcData[(srcCol + cell) *
|
|
512
|
+
if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
|
487
513
|
this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
|
|
488
514
|
}
|
|
489
515
|
}
|
|
490
516
|
} else {
|
|
491
517
|
for (let cell = 0; cell < length; cell++) {
|
|
492
|
-
for (let i = 0; i <
|
|
493
|
-
this._data[(destCol + cell) *
|
|
518
|
+
for (let i = 0; i < Constants.CELL_INDICIES; i++) {
|
|
519
|
+
this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i];
|
|
494
520
|
}
|
|
495
|
-
if (srcData[(srcCol + cell) *
|
|
521
|
+
if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
|
496
522
|
this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
|
|
497
523
|
}
|
|
498
524
|
}
|
|
@@ -509,7 +535,8 @@ export class BufferLine implements IBufferLine {
|
|
|
509
535
|
}
|
|
510
536
|
|
|
511
537
|
/**
|
|
512
|
-
* Translates the buffer line to a string.
|
|
538
|
+
* Translates the buffer line to a string. Caching only applies to canonical full-line translation
|
|
539
|
+
* requests (regardless of `trimRight` value).
|
|
513
540
|
*
|
|
514
541
|
* @param trimRight Whether to trim any empty cells on the right.
|
|
515
542
|
* @param startCol The column to start the string (0-based inclusive).
|
|
@@ -522,6 +549,19 @@ export class BufferLine implements IBufferLine {
|
|
|
522
549
|
* returned string, the corresponding entries in `outColumns` will have the same column number.
|
|
523
550
|
*/
|
|
524
551
|
public translateToString(trimRight?: boolean, startCol?: number, endCol?: number, outColumns?: number[]): string {
|
|
552
|
+
const isCanonicalRequest = (startCol === undefined || startCol === 0) && endCol === undefined && outColumns === undefined;
|
|
553
|
+
if (isCanonicalRequest) {
|
|
554
|
+
this._stringCache.touch?.();
|
|
555
|
+
}
|
|
556
|
+
const stringCacheEntry = isCanonicalRequest ? this._getStringCacheEntry(false) : undefined;
|
|
557
|
+
if (isCanonicalRequest && stringCacheEntry?.value !== undefined) {
|
|
558
|
+
if (trimRight) {
|
|
559
|
+
return stringCacheEntry.isTrimmed ? stringCacheEntry.value : stringCacheEntry.value.trimEnd();
|
|
560
|
+
}
|
|
561
|
+
if (!stringCacheEntry.isTrimmed) {
|
|
562
|
+
return stringCacheEntry.value;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
525
565
|
startCol = startCol ?? 0;
|
|
526
566
|
endCol = endCol ?? this.length;
|
|
527
567
|
if (trimRight) {
|
|
@@ -532,7 +572,7 @@ export class BufferLine implements IBufferLine {
|
|
|
532
572
|
}
|
|
533
573
|
let result = '';
|
|
534
574
|
while (startCol < endCol) {
|
|
535
|
-
const content = this._data[startCol *
|
|
575
|
+
const content = this._data[startCol * Constants.CELL_INDICIES + Cell.CONTENT];
|
|
536
576
|
const cp = content & Content.CODEPOINT_MASK;
|
|
537
577
|
const chars = (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR;
|
|
538
578
|
result += chars;
|
|
@@ -546,6 +586,34 @@ export class BufferLine implements IBufferLine {
|
|
|
546
586
|
if (outColumns) {
|
|
547
587
|
outColumns.push(startCol);
|
|
548
588
|
}
|
|
589
|
+
if (isCanonicalRequest) {
|
|
590
|
+
const cacheEntry = this._getStringCacheEntry(true)!;
|
|
591
|
+
cacheEntry.value = result;
|
|
592
|
+
cacheEntry.isTrimmed = !!trimRight;
|
|
593
|
+
}
|
|
549
594
|
return result;
|
|
550
595
|
}
|
|
596
|
+
|
|
597
|
+
protected _getStringCacheEntry(createIfNeeded: boolean): IBufferLineStringCacheEntry | undefined {
|
|
598
|
+
const cachedEntry = this._stringCacheEntryRef?.deref();
|
|
599
|
+
if (cachedEntry) {
|
|
600
|
+
if (cachedEntry.generation === this._stringCache.generation) {
|
|
601
|
+
return cachedEntry;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (!createIfNeeded) {
|
|
605
|
+
return undefined;
|
|
606
|
+
}
|
|
607
|
+
const cacheEntry = this._stringCache.allocateEntry();
|
|
608
|
+
this._stringCacheEntryRef = new WeakRef(cacheEntry);
|
|
609
|
+
return cacheEntry;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
private _invalidateStringCache(): void {
|
|
613
|
+
const cacheEntry = this._getStringCacheEntry(false);
|
|
614
|
+
if (cacheEntry) {
|
|
615
|
+
cacheEntry.value = undefined;
|
|
616
|
+
cacheEntry.isTrimmed = false;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
551
619
|
}
|