monaco-editor11 1.0.9 → 1.1.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.
- package/dist/index.d.ts +1 -1
- package/dist/monaco-editor11.es.js +12 -16
- package/dist/monaco-editor11.umd.js +1 -1
- package/package.json +2 -2
- package/dist/monaco.d.ts +0 -8
- package/dist/workers/common/initialize.js +0 -16
- package/dist/workers/common/workers.js +0 -141
- package/dist/workers/editor/common/abstractSyntaxTokenBackend.js +0 -128
- package/dist/workers/editor/common/abstractText.js +0 -89
- package/dist/workers/editor/common/ast.js +0 -485
- package/dist/workers/editor/common/autoIndent.js +0 -390
- package/dist/workers/editor/common/beforeEditPositionMapper.js +0 -110
- package/dist/workers/editor/common/bracketPairsImpl.js +0 -717
- package/dist/workers/editor/common/bracketPairsTree.js +0 -343
- package/dist/workers/editor/common/brackets.js +0 -108
- package/dist/workers/editor/common/characterClassifier.js +0 -59
- package/dist/workers/editor/common/characterPair.js +0 -40
- package/dist/workers/editor/common/colorizedBracketPairsDecorationProvider.js +0 -97
- package/dist/workers/editor/common/columnRange.js +0 -35
- package/dist/workers/editor/common/combineTextEditInfos.js +0 -124
- package/dist/workers/editor/common/common.js +0 -20
- package/dist/workers/editor/common/computeMovedLines.js +0 -249
- package/dist/workers/editor/common/concat23Trees.js +0 -192
- package/dist/workers/editor/common/contiguousMultilineTokens.js +0 -32
- package/dist/workers/editor/common/contiguousMultilineTokensBuilder.js +0 -23
- package/dist/workers/editor/common/contiguousTokensEditing.js +0 -128
- package/dist/workers/editor/common/contiguousTokensStore.js +0 -207
- package/dist/workers/editor/common/coordinatesConverter.js +0 -51
- package/dist/workers/editor/common/cursor.js +0 -899
- package/dist/workers/editor/common/cursorAtomicMoveOperations.js +0 -145
- package/dist/workers/editor/common/cursorCollection.js +0 -194
- package/dist/workers/editor/common/cursorColumnSelection.js +0 -93
- package/dist/workers/editor/common/cursorColumns.js +0 -112
- package/dist/workers/editor/common/cursorCommon.js +0 -250
- package/dist/workers/editor/common/cursorContext.js +0 -15
- package/dist/workers/editor/common/cursorDeleteOperations.js +0 -231
- package/dist/workers/editor/common/cursorMoveCommands.js +0 -676
- package/dist/workers/editor/common/cursorMoveOperations.js +0 -290
- package/dist/workers/editor/common/cursorTypeEditOperations.js +0 -968
- package/dist/workers/editor/common/cursorTypeOperations.js +0 -173
- package/dist/workers/editor/common/cursorUtils.js +0 -75
- package/dist/workers/editor/common/cursorWordOperations.js +0 -720
- package/dist/workers/editor/common/defaultDocumentColorsComputer.js +0 -138
- package/dist/workers/editor/common/defaultLinesDiffComputer.js +0 -188
- package/dist/workers/editor/common/diffAlgorithm.js +0 -139
- package/dist/workers/editor/common/diffEditor.js +0 -38
- package/dist/workers/editor/common/dynamicProgrammingDiffing.js +0 -101
- package/dist/workers/editor/common/edit.js +0 -183
- package/dist/workers/editor/common/editOperation.js +0 -36
- package/dist/workers/editor/common/editStack.js +0 -363
- package/dist/workers/editor/common/editorAction.js +0 -26
- package/dist/workers/editor/common/editorBaseApi.js +0 -43
- package/dist/workers/editor/common/editorColorRegistry.js +0 -102
- package/dist/workers/editor/common/editorCommon.js +0 -13
- package/dist/workers/editor/common/editorConfigurationSchema.js +0 -338
- package/dist/workers/editor/common/editorContextKeys.js +0 -84
- package/dist/workers/editor/common/editorFeatures.js +0 -17
- package/dist/workers/editor/common/editorOptions.js +0 -3440
- package/dist/workers/editor/common/editorTheme.js +0 -23
- package/dist/workers/editor/common/editorWebWorker.js +0 -299
- package/dist/workers/editor/common/editorWorker.js +0 -9
- package/dist/workers/editor/common/editorWorkerHost.js +0 -15
- package/dist/workers/editor/common/editorZoom.js +0 -26
- package/dist/workers/editor/common/electricCharacter.js +0 -55
- package/dist/workers/editor/common/encodedTokenAttributes.js +0 -79
- package/dist/workers/editor/common/enterAction.js +0 -53
- package/dist/workers/editor/common/eolCounter.js +0 -44
- package/dist/workers/editor/common/findSectionHeaders.js +0 -128
- package/dist/workers/editor/common/fixBrackets.js +0 -67
- package/dist/workers/editor/common/fixedArray.js +0 -70
- package/dist/workers/editor/common/fontInfo.js +0 -172
- package/dist/workers/editor/common/fontInfoFromSettings.js +0 -29
- package/dist/workers/editor/common/getIconClasses.js +0 -106
- package/dist/workers/editor/common/getPositionOffsetTransformerFromTextModel.js +0 -24
- package/dist/workers/editor/common/glyphLanesModel.js +0 -61
- package/dist/workers/editor/common/guidesTextModelPart.js +0 -405
- package/dist/workers/editor/common/heuristicSequenceOptimizations.js +0 -374
- package/dist/workers/editor/common/indentRules.js +0 -63
- package/dist/workers/editor/common/indentation.js +0 -39
- package/dist/workers/editor/common/indentationGuesser.js +0 -178
- package/dist/workers/editor/common/indentationLineProcessor.js +0 -193
- package/dist/workers/editor/common/inlineDecorations.js +0 -26
- package/dist/workers/editor/common/inplaceReplaceSupport.js +0 -87
- package/dist/workers/editor/common/inputMode.js +0 -22
- package/dist/workers/editor/common/intervalTree.js +0 -1002
- package/dist/workers/editor/common/language.js +0 -9
- package/dist/workers/editor/common/languageBracketsConfiguration.js +0 -133
- package/dist/workers/editor/common/languageConfiguration.js +0 -138
- package/dist/workers/editor/common/languageConfigurationRegistry.js +0 -361
- package/dist/workers/editor/common/languageFeatureDebounce.js +0 -137
- package/dist/workers/editor/common/languageFeatureRegistry.js +0 -180
- package/dist/workers/editor/common/languageFeatures.js +0 -9
- package/dist/workers/editor/common/languageFeaturesService.js +0 -47
- package/dist/workers/editor/common/languageSelector.js +0 -112
- package/dist/workers/editor/common/languageService.js +0 -92
- package/dist/workers/editor/common/languages.js +0 -522
- package/dist/workers/editor/common/languagesAssociations.js +0 -193
- package/dist/workers/editor/common/languagesRegistry.js +0 -237
- package/dist/workers/editor/common/legacyLinesDiffComputer.js +0 -468
- package/dist/workers/editor/common/length.js +0 -129
- package/dist/workers/editor/common/lineDecorations.js +0 -208
- package/dist/workers/editor/common/lineEdit.js +0 -75
- package/dist/workers/editor/common/lineHeights.js +0 -370
- package/dist/workers/editor/common/linePart.js +0 -25
- package/dist/workers/editor/common/lineRange.js +0 -312
- package/dist/workers/editor/common/lineSequence.js +0 -36
- package/dist/workers/editor/common/lineTokens.js +0 -405
- package/dist/workers/editor/common/linesDiffComputer.js +0 -29
- package/dist/workers/editor/common/linesDiffComputers.js +0 -13
- package/dist/workers/editor/common/linesLayout.js +0 -765
- package/dist/workers/editor/common/linesSliceCharSequence.js +0 -205
- package/dist/workers/editor/common/linkComputer.js +0 -269
- package/dist/workers/editor/common/markerDecorations.js +0 -9
- package/dist/workers/editor/common/markerDecorationsService.js +0 -248
- package/dist/workers/editor/common/minimapTokensColorTracker.js +0 -58
- package/dist/workers/editor/common/mirrorTextModel.js +0 -117
- package/dist/workers/editor/common/model.js +0 -9
- package/dist/workers/editor/common/modelLineProjection.js +0 -350
- package/dist/workers/editor/common/modelLineProjectionData.js +0 -297
- package/dist/workers/editor/common/modelService.js +0 -413
- package/dist/workers/editor/common/modesRegistry.js +0 -75
- package/dist/workers/editor/common/monospaceLineBreaksComputer.js +0 -473
- package/dist/workers/editor/common/myersDiffAlgorithm.js +0 -159
- package/dist/workers/editor/common/nodeReader.js +0 -127
- package/dist/workers/editor/common/nullTokenize.js +0 -29
- package/dist/workers/editor/common/offsetRange.js +0 -225
- package/dist/workers/editor/common/onEnter.js +0 -109
- package/dist/workers/editor/common/oneCursor.js +0 -117
- package/dist/workers/editor/common/overviewZoneManager.js +0 -176
- package/dist/workers/editor/common/parser.js +0 -121
- package/dist/workers/editor/common/pieceTreeBase.js +0 -1473
- package/dist/workers/editor/common/pieceTreeTextBuffer.js +0 -461
- package/dist/workers/editor/common/pieceTreeTextBufferBuilder.js +0 -140
- package/dist/workers/editor/common/point.js +0 -50
- package/dist/workers/editor/common/position.js +0 -142
- package/dist/workers/editor/common/positionToOffset.js +0 -17
- package/dist/workers/editor/common/positionToOffsetImpl.js +0 -98
- package/dist/workers/editor/common/prefixSumComputer.js +0 -226
- package/dist/workers/editor/common/range.js +0 -421
- package/dist/workers/editor/common/rangeMapping.js +0 -229
- package/dist/workers/editor/common/rangeSingleLine.js +0 -17
- package/dist/workers/editor/common/rbTreeBase.js +0 -362
- package/dist/workers/editor/common/rect.js +0 -163
- package/dist/workers/editor/common/replaceCommand.js +0 -158
- package/dist/workers/editor/common/resolverService.js +0 -5
- package/dist/workers/editor/common/rgba.js +0 -35
- package/dist/workers/editor/common/richEditBrackets.js +0 -356
- package/dist/workers/editor/common/selection.js +0 -145
- package/dist/workers/editor/common/semanticTokensDto.js +0 -82
- package/dist/workers/editor/common/semanticTokensProviderStyling.js +0 -263
- package/dist/workers/editor/common/semanticTokensStyling.js +0 -9
- package/dist/workers/editor/common/semanticTokensStylingService.js +0 -47
- package/dist/workers/editor/common/shiftCommand.js +0 -241
- package/dist/workers/editor/common/smallImmutableSet.js +0 -108
- package/dist/workers/editor/common/sparseMultilineTokens.js +0 -548
- package/dist/workers/editor/common/sparseTokensStore.js +0 -210
- package/dist/workers/editor/common/standaloneEnums.js +0 -1017
- package/dist/workers/editor/common/standaloneStrings.js +0 -42
- package/dist/workers/editor/common/stringBuilder.js +0 -122
- package/dist/workers/editor/common/stringEdit.js +0 -165
- package/dist/workers/editor/common/supports.js +0 -58
- package/dist/workers/editor/common/surroundSelectionCommand.js +0 -44
- package/dist/workers/editor/common/textChange.js +0 -248
- package/dist/workers/editor/common/textEdit.js +0 -269
- package/dist/workers/editor/common/textLength.js +0 -87
- package/dist/workers/editor/common/textModel.js +0 -2031
- package/dist/workers/editor/common/textModelBracketPairs.js +0 -45
- package/dist/workers/editor/common/textModelDefaults.js +0 -18
- package/dist/workers/editor/common/textModelEditSource.js +0 -166
- package/dist/workers/editor/common/textModelEvents.js +0 -216
- package/dist/workers/editor/common/textModelGuides.js +0 -40
- package/dist/workers/editor/common/textModelPart.js +0 -23
- package/dist/workers/editor/common/textModelSearch.js +0 -455
- package/dist/workers/editor/common/textModelStringEdit.js +0 -11
- package/dist/workers/editor/common/textModelSync.impl.js +0 -307
- package/dist/workers/editor/common/textModelText.js +0 -26
- package/dist/workers/editor/common/textModelTokens.js +0 -436
- package/dist/workers/editor/common/textResourceConfiguration.js +0 -6
- package/dist/workers/editor/common/textToHtmlTokenizer.js +0 -139
- package/dist/workers/editor/common/tokenStore.js +0 -407
- package/dist/workers/editor/common/tokenWithTextArray.js +0 -73
- package/dist/workers/editor/common/tokenization.js +0 -287
- package/dist/workers/editor/common/tokenizationRegistry.js +0 -123
- package/dist/workers/editor/common/tokenizationTextModelPart.js +0 -275
- package/dist/workers/editor/common/tokenizer.js +0 -301
- package/dist/workers/editor/common/tokenizerSyntaxTokenBackend.js +0 -261
- package/dist/workers/editor/common/treeSitterLibraryService.js +0 -9
- package/dist/workers/editor/common/treeSitterSyntaxTokenBackend.js +0 -167
- package/dist/workers/editor/common/treeSitterThemeService.js +0 -9
- package/dist/workers/editor/common/treeSitterTokenizationImpl.js +0 -713
- package/dist/workers/editor/common/treeSitterTree.js +0 -395
- package/dist/workers/editor/common/treeViewsDnd.js +0 -24
- package/dist/workers/editor/common/treeViewsDndService.js +0 -12
- package/dist/workers/editor/common/trimTrailingWhitespaceCommand.js +0 -98
- package/dist/workers/editor/common/unicodeTextModelHighlighter.js +0 -188
- package/dist/workers/editor/common/utils.js +0 -62
- package/dist/workers/editor/common/viewContext.js +0 -22
- package/dist/workers/editor/common/viewEventHandler.js +0 -186
- package/dist/workers/editor/common/viewEvents.js +0 -180
- package/dist/workers/editor/common/viewLayout.js +0 -368
- package/dist/workers/editor/common/viewLineRenderer.js +0 -948
- package/dist/workers/editor/common/viewLinesViewportData.js +0 -30
- package/dist/workers/editor/common/viewModel.js +0 -98
- package/dist/workers/editor/common/viewModelDecoration.js +0 -55
- package/dist/workers/editor/common/viewModelDecorations.js +0 -132
- package/dist/workers/editor/common/viewModelEventDispatcher.js +0 -398
- package/dist/workers/editor/common/viewModelImpl.js +0 -1163
- package/dist/workers/editor/common/viewModelLines.js +0 -938
- package/dist/workers/editor/common/wordCharacterClassifier.js +0 -87
- package/dist/workers/editor/common/wordHelper.js +0 -127
- package/dist/workers/language/cssMode.js +0 -198
- package/dist/workers/language/cssWorker.js +0 -183
- package/dist/workers/language/htmlMode.js +0 -213
- package/dist/workers/language/htmlWorker.js +0 -126
- package/dist/workers/language/jsonMode.js +0 -224
- package/dist/workers/language/jsonWorker.js +0 -187
- package/dist/workers/language/languageFeatures.js +0 -1009
- package/dist/workers/language/lib.index.js +0 -103
- package/dist/workers/language/lib.js +0 -1107
- package/dist/workers/language/lspLanguageFeatures.js +0 -716
- package/dist/workers/language/monaco.contribution.js +0 -144
- package/dist/workers/language/tokenization.js +0 -189
- package/dist/workers/language/tsMode.js +0 -212
- package/dist/workers/language/tsWorker.js +0 -352
- package/dist/workers/language/typescriptServices.js +0 -210154
- package/dist/workers/language/typescriptServicesMetadata.js +0 -3
- package/dist/workers/language/workerManager.js +0 -65
- /package/dist/workers/{language/css.worker.js → css.worker.js} +0 -0
- /package/dist/workers/{editor/editor.worker.js → editor.worker.js} +0 -0
- /package/dist/workers/{language/html.worker.js → html.worker.js} +0 -0
- /package/dist/workers/{language/json.worker.js → json.worker.js} +0 -0
- /package/dist/workers/{language/ts.worker.js → ts.worker.js} +0 -0
|
@@ -1,1473 +0,0 @@
|
|
|
1
|
-
import { Position } from '../../core/position.js';
|
|
2
|
-
import { Range } from '../../core/range.js';
|
|
3
|
-
import { FindMatch } from '../../model.js';
|
|
4
|
-
import { SENTINEL, rbDelete, updateTreeMetadata, TreeNode, leftest, fixInsert, righttest } from './rbTreeBase.js';
|
|
5
|
-
import { createFindMatch, Searcher, isValidMatch } from '../textModelSearch.js';
|
|
6
|
-
|
|
7
|
-
/*---------------------------------------------------------------------------------------------
|
|
8
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
9
|
-
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
10
|
-
*--------------------------------------------------------------------------------------------*/
|
|
11
|
-
// const lfRegex = new RegExp(/\r\n|\r|\n/g);
|
|
12
|
-
const AverageBufferSize = 65535;
|
|
13
|
-
function createUintArray(arr) {
|
|
14
|
-
let r;
|
|
15
|
-
if (arr[arr.length - 1] < 65536) {
|
|
16
|
-
r = new Uint16Array(arr.length);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
r = new Uint32Array(arr.length);
|
|
20
|
-
}
|
|
21
|
-
r.set(arr, 0);
|
|
22
|
-
return r;
|
|
23
|
-
}
|
|
24
|
-
class LineStarts {
|
|
25
|
-
constructor(lineStarts, cr, lf, crlf, isBasicASCII) {
|
|
26
|
-
this.lineStarts = lineStarts;
|
|
27
|
-
this.cr = cr;
|
|
28
|
-
this.lf = lf;
|
|
29
|
-
this.crlf = crlf;
|
|
30
|
-
this.isBasicASCII = isBasicASCII;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function createLineStartsFast(str, readonly = true) {
|
|
34
|
-
const r = [0];
|
|
35
|
-
let rLength = 1;
|
|
36
|
-
for (let i = 0, len = str.length; i < len; i++) {
|
|
37
|
-
const chr = str.charCodeAt(i);
|
|
38
|
-
if (chr === 13 /* CharCode.CarriageReturn */) {
|
|
39
|
-
if (i + 1 < len && str.charCodeAt(i + 1) === 10 /* CharCode.LineFeed */) {
|
|
40
|
-
// \r\n... case
|
|
41
|
-
r[rLength++] = i + 2;
|
|
42
|
-
i++; // skip \n
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
// \r... case
|
|
46
|
-
r[rLength++] = i + 1;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
else if (chr === 10 /* CharCode.LineFeed */) {
|
|
50
|
-
r[rLength++] = i + 1;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (readonly) {
|
|
54
|
-
return createUintArray(r);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
return r;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function createLineStarts(r, str) {
|
|
61
|
-
r.length = 0;
|
|
62
|
-
r[0] = 0;
|
|
63
|
-
let rLength = 1;
|
|
64
|
-
let cr = 0, lf = 0, crlf = 0;
|
|
65
|
-
let isBasicASCII = true;
|
|
66
|
-
for (let i = 0, len = str.length; i < len; i++) {
|
|
67
|
-
const chr = str.charCodeAt(i);
|
|
68
|
-
if (chr === 13 /* CharCode.CarriageReturn */) {
|
|
69
|
-
if (i + 1 < len && str.charCodeAt(i + 1) === 10 /* CharCode.LineFeed */) {
|
|
70
|
-
// \r\n... case
|
|
71
|
-
crlf++;
|
|
72
|
-
r[rLength++] = i + 2;
|
|
73
|
-
i++; // skip \n
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
cr++;
|
|
77
|
-
// \r... case
|
|
78
|
-
r[rLength++] = i + 1;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
else if (chr === 10 /* CharCode.LineFeed */) {
|
|
82
|
-
lf++;
|
|
83
|
-
r[rLength++] = i + 1;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
if (isBasicASCII) {
|
|
87
|
-
if (chr !== 9 /* CharCode.Tab */ && (chr < 32 || chr > 126)) {
|
|
88
|
-
isBasicASCII = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
const result = new LineStarts(createUintArray(r), cr, lf, crlf, isBasicASCII);
|
|
94
|
-
r.length = 0;
|
|
95
|
-
return result;
|
|
96
|
-
}
|
|
97
|
-
class Piece {
|
|
98
|
-
constructor(bufferIndex, start, end, lineFeedCnt, length) {
|
|
99
|
-
this.bufferIndex = bufferIndex;
|
|
100
|
-
this.start = start;
|
|
101
|
-
this.end = end;
|
|
102
|
-
this.lineFeedCnt = lineFeedCnt;
|
|
103
|
-
this.length = length;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
class StringBuffer {
|
|
107
|
-
constructor(buffer, lineStarts) {
|
|
108
|
-
this.buffer = buffer;
|
|
109
|
-
this.lineStarts = lineStarts;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Readonly snapshot for piece tree.
|
|
114
|
-
* In a real multiple thread environment, to make snapshot reading always work correctly, we need to
|
|
115
|
-
* 1. Make TreeNode.piece immutable, then reading and writing can run in parallel.
|
|
116
|
-
* 2. TreeNode/Buffers normalization should not happen during snapshot reading.
|
|
117
|
-
*/
|
|
118
|
-
class PieceTreeSnapshot {
|
|
119
|
-
constructor(tree, BOM) {
|
|
120
|
-
this._pieces = [];
|
|
121
|
-
this._tree = tree;
|
|
122
|
-
this._BOM = BOM;
|
|
123
|
-
this._index = 0;
|
|
124
|
-
if (tree.root !== SENTINEL) {
|
|
125
|
-
tree.iterate(tree.root, node => {
|
|
126
|
-
if (node !== SENTINEL) {
|
|
127
|
-
this._pieces.push(node.piece);
|
|
128
|
-
}
|
|
129
|
-
return true;
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
read() {
|
|
134
|
-
if (this._pieces.length === 0) {
|
|
135
|
-
if (this._index === 0) {
|
|
136
|
-
this._index++;
|
|
137
|
-
return this._BOM;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (this._index > this._pieces.length - 1) {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
if (this._index === 0) {
|
|
147
|
-
return this._BOM + this._tree.getPieceContent(this._pieces[this._index++]);
|
|
148
|
-
}
|
|
149
|
-
return this._tree.getPieceContent(this._pieces[this._index++]);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
class PieceTreeSearchCache {
|
|
153
|
-
constructor(limit) {
|
|
154
|
-
this._limit = limit;
|
|
155
|
-
this._cache = [];
|
|
156
|
-
}
|
|
157
|
-
get(offset) {
|
|
158
|
-
for (let i = this._cache.length - 1; i >= 0; i--) {
|
|
159
|
-
const nodePos = this._cache[i];
|
|
160
|
-
if (nodePos.nodeStartOffset <= offset && nodePos.nodeStartOffset + nodePos.node.piece.length >= offset) {
|
|
161
|
-
return nodePos;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
get2(lineNumber) {
|
|
167
|
-
for (let i = this._cache.length - 1; i >= 0; i--) {
|
|
168
|
-
const nodePos = this._cache[i];
|
|
169
|
-
if (nodePos.nodeStartLineNumber && nodePos.nodeStartLineNumber < lineNumber && nodePos.nodeStartLineNumber + nodePos.node.piece.lineFeedCnt >= lineNumber) {
|
|
170
|
-
return nodePos;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
set(nodePosition) {
|
|
176
|
-
if (this._cache.length >= this._limit) {
|
|
177
|
-
this._cache.shift();
|
|
178
|
-
}
|
|
179
|
-
this._cache.push(nodePosition);
|
|
180
|
-
}
|
|
181
|
-
validate(offset) {
|
|
182
|
-
let hasInvalidVal = false;
|
|
183
|
-
const tmp = this._cache;
|
|
184
|
-
for (let i = 0; i < tmp.length; i++) {
|
|
185
|
-
const nodePos = tmp[i];
|
|
186
|
-
if (nodePos.node.parent === null || nodePos.nodeStartOffset >= offset) {
|
|
187
|
-
tmp[i] = null;
|
|
188
|
-
hasInvalidVal = true;
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
if (hasInvalidVal) {
|
|
193
|
-
const newArr = [];
|
|
194
|
-
for (const entry of tmp) {
|
|
195
|
-
if (entry !== null) {
|
|
196
|
-
newArr.push(entry);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
this._cache = newArr;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
class PieceTreeBase {
|
|
204
|
-
constructor(chunks, eol, eolNormalized) {
|
|
205
|
-
this.create(chunks, eol, eolNormalized);
|
|
206
|
-
}
|
|
207
|
-
create(chunks, eol, eolNormalized) {
|
|
208
|
-
this._buffers = [
|
|
209
|
-
new StringBuffer('', [0])
|
|
210
|
-
];
|
|
211
|
-
this._lastChangeBufferPos = { line: 0, column: 0 };
|
|
212
|
-
this.root = SENTINEL;
|
|
213
|
-
this._lineCnt = 1;
|
|
214
|
-
this._length = 0;
|
|
215
|
-
this._EOL = eol;
|
|
216
|
-
this._EOLLength = eol.length;
|
|
217
|
-
this._EOLNormalized = eolNormalized;
|
|
218
|
-
let lastNode = null;
|
|
219
|
-
for (let i = 0, len = chunks.length; i < len; i++) {
|
|
220
|
-
if (chunks[i].buffer.length > 0) {
|
|
221
|
-
if (!chunks[i].lineStarts) {
|
|
222
|
-
chunks[i].lineStarts = createLineStartsFast(chunks[i].buffer);
|
|
223
|
-
}
|
|
224
|
-
const piece = new Piece(i + 1, { line: 0, column: 0 }, { line: chunks[i].lineStarts.length - 1, column: chunks[i].buffer.length - chunks[i].lineStarts[chunks[i].lineStarts.length - 1] }, chunks[i].lineStarts.length - 1, chunks[i].buffer.length);
|
|
225
|
-
this._buffers.push(chunks[i]);
|
|
226
|
-
lastNode = this.rbInsertRight(lastNode, piece);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
this._searchCache = new PieceTreeSearchCache(1);
|
|
230
|
-
this._lastVisitedLine = { lineNumber: 0, value: '' };
|
|
231
|
-
this.computeBufferMetadata();
|
|
232
|
-
}
|
|
233
|
-
normalizeEOL(eol) {
|
|
234
|
-
const averageBufferSize = AverageBufferSize;
|
|
235
|
-
const min = averageBufferSize - Math.floor(averageBufferSize / 3);
|
|
236
|
-
const max = min * 2;
|
|
237
|
-
let tempChunk = '';
|
|
238
|
-
let tempChunkLen = 0;
|
|
239
|
-
const chunks = [];
|
|
240
|
-
this.iterate(this.root, node => {
|
|
241
|
-
const str = this.getNodeContent(node);
|
|
242
|
-
const len = str.length;
|
|
243
|
-
if (tempChunkLen <= min || tempChunkLen + len < max) {
|
|
244
|
-
tempChunk += str;
|
|
245
|
-
tempChunkLen += len;
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
// flush anyways
|
|
249
|
-
const text = tempChunk.replace(/\r\n|\r|\n/g, eol);
|
|
250
|
-
chunks.push(new StringBuffer(text, createLineStartsFast(text)));
|
|
251
|
-
tempChunk = str;
|
|
252
|
-
tempChunkLen = len;
|
|
253
|
-
return true;
|
|
254
|
-
});
|
|
255
|
-
if (tempChunkLen > 0) {
|
|
256
|
-
const text = tempChunk.replace(/\r\n|\r|\n/g, eol);
|
|
257
|
-
chunks.push(new StringBuffer(text, createLineStartsFast(text)));
|
|
258
|
-
}
|
|
259
|
-
this.create(chunks, eol, true);
|
|
260
|
-
}
|
|
261
|
-
// #region Buffer API
|
|
262
|
-
getEOL() {
|
|
263
|
-
return this._EOL;
|
|
264
|
-
}
|
|
265
|
-
setEOL(newEOL) {
|
|
266
|
-
this._EOL = newEOL;
|
|
267
|
-
this._EOLLength = this._EOL.length;
|
|
268
|
-
this.normalizeEOL(newEOL);
|
|
269
|
-
}
|
|
270
|
-
createSnapshot(BOM) {
|
|
271
|
-
return new PieceTreeSnapshot(this, BOM);
|
|
272
|
-
}
|
|
273
|
-
getOffsetAt(lineNumber, column) {
|
|
274
|
-
let leftLen = 0; // inorder
|
|
275
|
-
let x = this.root;
|
|
276
|
-
while (x !== SENTINEL) {
|
|
277
|
-
if (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) {
|
|
278
|
-
x = x.left;
|
|
279
|
-
}
|
|
280
|
-
else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) {
|
|
281
|
-
leftLen += x.size_left;
|
|
282
|
-
// lineNumber >= 2
|
|
283
|
-
const accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
|
|
284
|
-
return leftLen += accumualtedValInCurrentIndex + column - 1;
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
lineNumber -= x.lf_left + x.piece.lineFeedCnt;
|
|
288
|
-
leftLen += x.size_left + x.piece.length;
|
|
289
|
-
x = x.right;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return leftLen;
|
|
293
|
-
}
|
|
294
|
-
getPositionAt(offset) {
|
|
295
|
-
offset = Math.floor(offset);
|
|
296
|
-
offset = Math.max(0, offset);
|
|
297
|
-
let x = this.root;
|
|
298
|
-
let lfCnt = 0;
|
|
299
|
-
const originalOffset = offset;
|
|
300
|
-
while (x !== SENTINEL) {
|
|
301
|
-
if (x.size_left !== 0 && x.size_left >= offset) {
|
|
302
|
-
x = x.left;
|
|
303
|
-
}
|
|
304
|
-
else if (x.size_left + x.piece.length >= offset) {
|
|
305
|
-
const out = this.getIndexOf(x, offset - x.size_left);
|
|
306
|
-
lfCnt += x.lf_left + out.index;
|
|
307
|
-
if (out.index === 0) {
|
|
308
|
-
const lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);
|
|
309
|
-
const column = originalOffset - lineStartOffset;
|
|
310
|
-
return new Position(lfCnt + 1, column + 1);
|
|
311
|
-
}
|
|
312
|
-
return new Position(lfCnt + 1, out.remainder + 1);
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
offset -= x.size_left + x.piece.length;
|
|
316
|
-
lfCnt += x.lf_left + x.piece.lineFeedCnt;
|
|
317
|
-
if (x.right === SENTINEL) {
|
|
318
|
-
// last node
|
|
319
|
-
const lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);
|
|
320
|
-
const column = originalOffset - offset - lineStartOffset;
|
|
321
|
-
return new Position(lfCnt + 1, column + 1);
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
x = x.right;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return new Position(1, 1);
|
|
329
|
-
}
|
|
330
|
-
getValueInRange(range, eol) {
|
|
331
|
-
if (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {
|
|
332
|
-
return '';
|
|
333
|
-
}
|
|
334
|
-
const startPosition = this.nodeAt2(range.startLineNumber, range.startColumn);
|
|
335
|
-
const endPosition = this.nodeAt2(range.endLineNumber, range.endColumn);
|
|
336
|
-
const value = this.getValueInRange2(startPosition, endPosition);
|
|
337
|
-
if (eol) {
|
|
338
|
-
if (eol !== this._EOL || !this._EOLNormalized) {
|
|
339
|
-
return value.replace(/\r\n|\r|\n/g, eol);
|
|
340
|
-
}
|
|
341
|
-
if (eol === this.getEOL() && this._EOLNormalized) {
|
|
342
|
-
return value;
|
|
343
|
-
}
|
|
344
|
-
return value.replace(/\r\n|\r|\n/g, eol);
|
|
345
|
-
}
|
|
346
|
-
return value;
|
|
347
|
-
}
|
|
348
|
-
getValueInRange2(startPosition, endPosition) {
|
|
349
|
-
if (startPosition.node === endPosition.node) {
|
|
350
|
-
const node = startPosition.node;
|
|
351
|
-
const buffer = this._buffers[node.piece.bufferIndex].buffer;
|
|
352
|
-
const startOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);
|
|
353
|
-
return buffer.substring(startOffset + startPosition.remainder, startOffset + endPosition.remainder);
|
|
354
|
-
}
|
|
355
|
-
let x = startPosition.node;
|
|
356
|
-
const buffer = this._buffers[x.piece.bufferIndex].buffer;
|
|
357
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
358
|
-
let ret = buffer.substring(startOffset + startPosition.remainder, startOffset + x.piece.length);
|
|
359
|
-
x = x.next();
|
|
360
|
-
while (x !== SENTINEL) {
|
|
361
|
-
const buffer = this._buffers[x.piece.bufferIndex].buffer;
|
|
362
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
363
|
-
if (x === endPosition.node) {
|
|
364
|
-
ret += buffer.substring(startOffset, startOffset + endPosition.remainder);
|
|
365
|
-
break;
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
ret += buffer.substr(startOffset, x.piece.length);
|
|
369
|
-
}
|
|
370
|
-
x = x.next();
|
|
371
|
-
}
|
|
372
|
-
return ret;
|
|
373
|
-
}
|
|
374
|
-
getLinesContent() {
|
|
375
|
-
const lines = [];
|
|
376
|
-
let linesLength = 0;
|
|
377
|
-
let currentLine = '';
|
|
378
|
-
let danglingCR = false;
|
|
379
|
-
this.iterate(this.root, node => {
|
|
380
|
-
if (node === SENTINEL) {
|
|
381
|
-
return true;
|
|
382
|
-
}
|
|
383
|
-
const piece = node.piece;
|
|
384
|
-
let pieceLength = piece.length;
|
|
385
|
-
if (pieceLength === 0) {
|
|
386
|
-
return true;
|
|
387
|
-
}
|
|
388
|
-
const buffer = this._buffers[piece.bufferIndex].buffer;
|
|
389
|
-
const lineStarts = this._buffers[piece.bufferIndex].lineStarts;
|
|
390
|
-
const pieceStartLine = piece.start.line;
|
|
391
|
-
const pieceEndLine = piece.end.line;
|
|
392
|
-
let pieceStartOffset = lineStarts[pieceStartLine] + piece.start.column;
|
|
393
|
-
if (danglingCR) {
|
|
394
|
-
if (buffer.charCodeAt(pieceStartOffset) === 10 /* CharCode.LineFeed */) {
|
|
395
|
-
// pretend the \n was in the previous piece..
|
|
396
|
-
pieceStartOffset++;
|
|
397
|
-
pieceLength--;
|
|
398
|
-
}
|
|
399
|
-
lines[linesLength++] = currentLine;
|
|
400
|
-
currentLine = '';
|
|
401
|
-
danglingCR = false;
|
|
402
|
-
if (pieceLength === 0) {
|
|
403
|
-
return true;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (pieceStartLine === pieceEndLine) {
|
|
407
|
-
// this piece has no new lines
|
|
408
|
-
if (!this._EOLNormalized && buffer.charCodeAt(pieceStartOffset + pieceLength - 1) === 13 /* CharCode.CarriageReturn */) {
|
|
409
|
-
danglingCR = true;
|
|
410
|
-
currentLine += buffer.substr(pieceStartOffset, pieceLength - 1);
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
currentLine += buffer.substr(pieceStartOffset, pieceLength);
|
|
414
|
-
}
|
|
415
|
-
return true;
|
|
416
|
-
}
|
|
417
|
-
// add the text before the first line start in this piece
|
|
418
|
-
currentLine += (this._EOLNormalized
|
|
419
|
-
? buffer.substring(pieceStartOffset, Math.max(pieceStartOffset, lineStarts[pieceStartLine + 1] - this._EOLLength))
|
|
420
|
-
: buffer.substring(pieceStartOffset, lineStarts[pieceStartLine + 1]).replace(/(\r\n|\r|\n)$/, ''));
|
|
421
|
-
lines[linesLength++] = currentLine;
|
|
422
|
-
for (let line = pieceStartLine + 1; line < pieceEndLine; line++) {
|
|
423
|
-
currentLine = (this._EOLNormalized
|
|
424
|
-
? buffer.substring(lineStarts[line], lineStarts[line + 1] - this._EOLLength)
|
|
425
|
-
: buffer.substring(lineStarts[line], lineStarts[line + 1]).replace(/(\r\n|\r|\n)$/, ''));
|
|
426
|
-
lines[linesLength++] = currentLine;
|
|
427
|
-
}
|
|
428
|
-
if (!this._EOLNormalized && buffer.charCodeAt(lineStarts[pieceEndLine] + piece.end.column - 1) === 13 /* CharCode.CarriageReturn */) {
|
|
429
|
-
danglingCR = true;
|
|
430
|
-
if (piece.end.column === 0) {
|
|
431
|
-
// The last line ended with a \r, let's undo the push, it will be pushed by next iteration
|
|
432
|
-
linesLength--;
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
currentLine = buffer.substr(lineStarts[pieceEndLine], piece.end.column - 1);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
currentLine = buffer.substr(lineStarts[pieceEndLine], piece.end.column);
|
|
440
|
-
}
|
|
441
|
-
return true;
|
|
442
|
-
});
|
|
443
|
-
if (danglingCR) {
|
|
444
|
-
lines[linesLength++] = currentLine;
|
|
445
|
-
currentLine = '';
|
|
446
|
-
}
|
|
447
|
-
lines[linesLength++] = currentLine;
|
|
448
|
-
return lines;
|
|
449
|
-
}
|
|
450
|
-
getLength() {
|
|
451
|
-
return this._length;
|
|
452
|
-
}
|
|
453
|
-
getLineCount() {
|
|
454
|
-
return this._lineCnt;
|
|
455
|
-
}
|
|
456
|
-
getLineContent(lineNumber) {
|
|
457
|
-
if (this._lastVisitedLine.lineNumber === lineNumber) {
|
|
458
|
-
return this._lastVisitedLine.value;
|
|
459
|
-
}
|
|
460
|
-
this._lastVisitedLine.lineNumber = lineNumber;
|
|
461
|
-
if (lineNumber === this._lineCnt) {
|
|
462
|
-
this._lastVisitedLine.value = this.getLineRawContent(lineNumber);
|
|
463
|
-
}
|
|
464
|
-
else if (this._EOLNormalized) {
|
|
465
|
-
this._lastVisitedLine.value = this.getLineRawContent(lineNumber, this._EOLLength);
|
|
466
|
-
}
|
|
467
|
-
else {
|
|
468
|
-
this._lastVisitedLine.value = this.getLineRawContent(lineNumber).replace(/(\r\n|\r|\n)$/, '');
|
|
469
|
-
}
|
|
470
|
-
return this._lastVisitedLine.value;
|
|
471
|
-
}
|
|
472
|
-
_getCharCode(nodePos) {
|
|
473
|
-
if (nodePos.remainder === nodePos.node.piece.length) {
|
|
474
|
-
// the char we want to fetch is at the head of next node.
|
|
475
|
-
const matchingNode = nodePos.node.next();
|
|
476
|
-
if (!matchingNode) {
|
|
477
|
-
return 0;
|
|
478
|
-
}
|
|
479
|
-
const buffer = this._buffers[matchingNode.piece.bufferIndex];
|
|
480
|
-
const startOffset = this.offsetInBuffer(matchingNode.piece.bufferIndex, matchingNode.piece.start);
|
|
481
|
-
return buffer.buffer.charCodeAt(startOffset);
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
const buffer = this._buffers[nodePos.node.piece.bufferIndex];
|
|
485
|
-
const startOffset = this.offsetInBuffer(nodePos.node.piece.bufferIndex, nodePos.node.piece.start);
|
|
486
|
-
const targetOffset = startOffset + nodePos.remainder;
|
|
487
|
-
return buffer.buffer.charCodeAt(targetOffset);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
getLineCharCode(lineNumber, index) {
|
|
491
|
-
const nodePos = this.nodeAt2(lineNumber, index + 1);
|
|
492
|
-
return this._getCharCode(nodePos);
|
|
493
|
-
}
|
|
494
|
-
getLineLength(lineNumber) {
|
|
495
|
-
if (lineNumber === this.getLineCount()) {
|
|
496
|
-
const startOffset = this.getOffsetAt(lineNumber, 1);
|
|
497
|
-
return this.getLength() - startOffset;
|
|
498
|
-
}
|
|
499
|
-
return this.getOffsetAt(lineNumber + 1, 1) - this.getOffsetAt(lineNumber, 1) - this._EOLLength;
|
|
500
|
-
}
|
|
501
|
-
getNearestChunk(offset) {
|
|
502
|
-
const nodePos = this.nodeAt(offset);
|
|
503
|
-
if (nodePos.remainder === nodePos.node.piece.length) {
|
|
504
|
-
// the offset is at the head of next node.
|
|
505
|
-
const matchingNode = nodePos.node.next();
|
|
506
|
-
if (!matchingNode || matchingNode === SENTINEL) {
|
|
507
|
-
return '';
|
|
508
|
-
}
|
|
509
|
-
const buffer = this._buffers[matchingNode.piece.bufferIndex];
|
|
510
|
-
const startOffset = this.offsetInBuffer(matchingNode.piece.bufferIndex, matchingNode.piece.start);
|
|
511
|
-
return buffer.buffer.substring(startOffset, startOffset + matchingNode.piece.length);
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
const buffer = this._buffers[nodePos.node.piece.bufferIndex];
|
|
515
|
-
const startOffset = this.offsetInBuffer(nodePos.node.piece.bufferIndex, nodePos.node.piece.start);
|
|
516
|
-
const targetOffset = startOffset + nodePos.remainder;
|
|
517
|
-
const targetEnd = startOffset + nodePos.node.piece.length;
|
|
518
|
-
return buffer.buffer.substring(targetOffset, targetEnd);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
findMatchesInNode(node, searcher, startLineNumber, startColumn, startCursor, endCursor, searchData, captureMatches, limitResultCount, resultLen, result) {
|
|
522
|
-
const buffer = this._buffers[node.piece.bufferIndex];
|
|
523
|
-
const startOffsetInBuffer = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);
|
|
524
|
-
const start = this.offsetInBuffer(node.piece.bufferIndex, startCursor);
|
|
525
|
-
const end = this.offsetInBuffer(node.piece.bufferIndex, endCursor);
|
|
526
|
-
let m;
|
|
527
|
-
// Reset regex to search from the beginning
|
|
528
|
-
const ret = { line: 0, column: 0 };
|
|
529
|
-
let searchText;
|
|
530
|
-
let offsetInBuffer;
|
|
531
|
-
if (searcher._wordSeparators) {
|
|
532
|
-
searchText = buffer.buffer.substring(start, end);
|
|
533
|
-
offsetInBuffer = (offset) => offset + start;
|
|
534
|
-
searcher.reset(0);
|
|
535
|
-
}
|
|
536
|
-
else {
|
|
537
|
-
searchText = buffer.buffer;
|
|
538
|
-
offsetInBuffer = (offset) => offset;
|
|
539
|
-
searcher.reset(start);
|
|
540
|
-
}
|
|
541
|
-
do {
|
|
542
|
-
m = searcher.next(searchText);
|
|
543
|
-
if (m) {
|
|
544
|
-
if (offsetInBuffer(m.index) >= end) {
|
|
545
|
-
return resultLen;
|
|
546
|
-
}
|
|
547
|
-
this.positionInBuffer(node, offsetInBuffer(m.index) - startOffsetInBuffer, ret);
|
|
548
|
-
const lineFeedCnt = this.getLineFeedCnt(node.piece.bufferIndex, startCursor, ret);
|
|
549
|
-
const retStartColumn = ret.line === startCursor.line ? ret.column - startCursor.column + startColumn : ret.column + 1;
|
|
550
|
-
const retEndColumn = retStartColumn + m[0].length;
|
|
551
|
-
result[resultLen++] = createFindMatch(new Range(startLineNumber + lineFeedCnt, retStartColumn, startLineNumber + lineFeedCnt, retEndColumn), m, captureMatches);
|
|
552
|
-
if (offsetInBuffer(m.index) + m[0].length >= end) {
|
|
553
|
-
return resultLen;
|
|
554
|
-
}
|
|
555
|
-
if (resultLen >= limitResultCount) {
|
|
556
|
-
return resultLen;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
} while (m);
|
|
560
|
-
return resultLen;
|
|
561
|
-
}
|
|
562
|
-
findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount) {
|
|
563
|
-
const result = [];
|
|
564
|
-
let resultLen = 0;
|
|
565
|
-
const searcher = new Searcher(searchData.wordSeparators, searchData.regex);
|
|
566
|
-
let startPosition = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn);
|
|
567
|
-
if (startPosition === null) {
|
|
568
|
-
return [];
|
|
569
|
-
}
|
|
570
|
-
const endPosition = this.nodeAt2(searchRange.endLineNumber, searchRange.endColumn);
|
|
571
|
-
if (endPosition === null) {
|
|
572
|
-
return [];
|
|
573
|
-
}
|
|
574
|
-
let start = this.positionInBuffer(startPosition.node, startPosition.remainder);
|
|
575
|
-
const end = this.positionInBuffer(endPosition.node, endPosition.remainder);
|
|
576
|
-
if (startPosition.node === endPosition.node) {
|
|
577
|
-
this.findMatchesInNode(startPosition.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);
|
|
578
|
-
return result;
|
|
579
|
-
}
|
|
580
|
-
let startLineNumber = searchRange.startLineNumber;
|
|
581
|
-
let currentNode = startPosition.node;
|
|
582
|
-
while (currentNode !== endPosition.node) {
|
|
583
|
-
const lineBreakCnt = this.getLineFeedCnt(currentNode.piece.bufferIndex, start, currentNode.piece.end);
|
|
584
|
-
if (lineBreakCnt >= 1) {
|
|
585
|
-
// last line break position
|
|
586
|
-
const lineStarts = this._buffers[currentNode.piece.bufferIndex].lineStarts;
|
|
587
|
-
const startOffsetInBuffer = this.offsetInBuffer(currentNode.piece.bufferIndex, currentNode.piece.start);
|
|
588
|
-
const nextLineStartOffset = lineStarts[start.line + lineBreakCnt];
|
|
589
|
-
const startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn : 1;
|
|
590
|
-
resultLen = this.findMatchesInNode(currentNode, searcher, startLineNumber, startColumn, start, this.positionInBuffer(currentNode, nextLineStartOffset - startOffsetInBuffer), searchData, captureMatches, limitResultCount, resultLen, result);
|
|
591
|
-
if (resultLen >= limitResultCount) {
|
|
592
|
-
return result;
|
|
593
|
-
}
|
|
594
|
-
startLineNumber += lineBreakCnt;
|
|
595
|
-
}
|
|
596
|
-
const startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn - 1 : 0;
|
|
597
|
-
// search for the remaining content
|
|
598
|
-
if (startLineNumber === searchRange.endLineNumber) {
|
|
599
|
-
const text = this.getLineContent(startLineNumber).substring(startColumn, searchRange.endColumn - 1);
|
|
600
|
-
resultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);
|
|
601
|
-
return result;
|
|
602
|
-
}
|
|
603
|
-
resultLen = this._findMatchesInLine(searchData, searcher, this.getLineContent(startLineNumber).substr(startColumn), startLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);
|
|
604
|
-
if (resultLen >= limitResultCount) {
|
|
605
|
-
return result;
|
|
606
|
-
}
|
|
607
|
-
startLineNumber++;
|
|
608
|
-
startPosition = this.nodeAt2(startLineNumber, 1);
|
|
609
|
-
currentNode = startPosition.node;
|
|
610
|
-
start = this.positionInBuffer(startPosition.node, startPosition.remainder);
|
|
611
|
-
}
|
|
612
|
-
if (startLineNumber === searchRange.endLineNumber) {
|
|
613
|
-
const startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn - 1 : 0;
|
|
614
|
-
const text = this.getLineContent(startLineNumber).substring(startColumn, searchRange.endColumn - 1);
|
|
615
|
-
resultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);
|
|
616
|
-
return result;
|
|
617
|
-
}
|
|
618
|
-
const startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn : 1;
|
|
619
|
-
resultLen = this.findMatchesInNode(endPosition.node, searcher, startLineNumber, startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);
|
|
620
|
-
return result;
|
|
621
|
-
}
|
|
622
|
-
_findMatchesInLine(searchData, searcher, text, lineNumber, deltaOffset, resultLen, result, captureMatches, limitResultCount) {
|
|
623
|
-
const wordSeparators = searchData.wordSeparators;
|
|
624
|
-
if (!captureMatches && searchData.simpleSearch) {
|
|
625
|
-
const searchString = searchData.simpleSearch;
|
|
626
|
-
const searchStringLen = searchString.length;
|
|
627
|
-
const textLength = text.length;
|
|
628
|
-
let lastMatchIndex = -searchStringLen;
|
|
629
|
-
while ((lastMatchIndex = text.indexOf(searchString, lastMatchIndex + searchStringLen)) !== -1) {
|
|
630
|
-
if (!wordSeparators || isValidMatch(wordSeparators, text, textLength, lastMatchIndex, searchStringLen)) {
|
|
631
|
-
result[resultLen++] = new FindMatch(new Range(lineNumber, lastMatchIndex + 1 + deltaOffset, lineNumber, lastMatchIndex + 1 + searchStringLen + deltaOffset), null);
|
|
632
|
-
if (resultLen >= limitResultCount) {
|
|
633
|
-
return resultLen;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
return resultLen;
|
|
638
|
-
}
|
|
639
|
-
let m;
|
|
640
|
-
// Reset regex to search from the beginning
|
|
641
|
-
searcher.reset(0);
|
|
642
|
-
do {
|
|
643
|
-
m = searcher.next(text);
|
|
644
|
-
if (m) {
|
|
645
|
-
result[resultLen++] = createFindMatch(new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset), m, captureMatches);
|
|
646
|
-
if (resultLen >= limitResultCount) {
|
|
647
|
-
return resultLen;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
} while (m);
|
|
651
|
-
return resultLen;
|
|
652
|
-
}
|
|
653
|
-
// #endregion
|
|
654
|
-
// #region Piece Table
|
|
655
|
-
insert(offset, value, eolNormalized = false) {
|
|
656
|
-
this._EOLNormalized = this._EOLNormalized && eolNormalized;
|
|
657
|
-
this._lastVisitedLine.lineNumber = 0;
|
|
658
|
-
this._lastVisitedLine.value = '';
|
|
659
|
-
if (this.root !== SENTINEL) {
|
|
660
|
-
const { node, remainder, nodeStartOffset } = this.nodeAt(offset);
|
|
661
|
-
const piece = node.piece;
|
|
662
|
-
const bufferIndex = piece.bufferIndex;
|
|
663
|
-
const insertPosInBuffer = this.positionInBuffer(node, remainder);
|
|
664
|
-
if (node.piece.bufferIndex === 0 &&
|
|
665
|
-
piece.end.line === this._lastChangeBufferPos.line &&
|
|
666
|
-
piece.end.column === this._lastChangeBufferPos.column &&
|
|
667
|
-
(nodeStartOffset + piece.length === offset) &&
|
|
668
|
-
value.length < AverageBufferSize) {
|
|
669
|
-
// changed buffer
|
|
670
|
-
this.appendToNode(node, value);
|
|
671
|
-
this.computeBufferMetadata();
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
if (nodeStartOffset === offset) {
|
|
675
|
-
this.insertContentToNodeLeft(value, node);
|
|
676
|
-
this._searchCache.validate(offset);
|
|
677
|
-
}
|
|
678
|
-
else if (nodeStartOffset + node.piece.length > offset) {
|
|
679
|
-
// we are inserting into the middle of a node.
|
|
680
|
-
const nodesToDel = [];
|
|
681
|
-
let newRightPiece = new Piece(piece.bufferIndex, insertPosInBuffer, piece.end, this.getLineFeedCnt(piece.bufferIndex, insertPosInBuffer, piece.end), this.offsetInBuffer(bufferIndex, piece.end) - this.offsetInBuffer(bufferIndex, insertPosInBuffer));
|
|
682
|
-
if (this.shouldCheckCRLF() && this.endWithCR(value)) {
|
|
683
|
-
const headOfRight = this.nodeCharCodeAt(node, remainder);
|
|
684
|
-
if (headOfRight === 10 /** \n */) {
|
|
685
|
-
const newStart = { line: newRightPiece.start.line + 1, column: 0 };
|
|
686
|
-
newRightPiece = new Piece(newRightPiece.bufferIndex, newStart, newRightPiece.end, this.getLineFeedCnt(newRightPiece.bufferIndex, newStart, newRightPiece.end), newRightPiece.length - 1);
|
|
687
|
-
value += '\n';
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
// reuse node for content before insertion point.
|
|
691
|
-
if (this.shouldCheckCRLF() && this.startWithLF(value)) {
|
|
692
|
-
const tailOfLeft = this.nodeCharCodeAt(node, remainder - 1);
|
|
693
|
-
if (tailOfLeft === 13 /** \r */) {
|
|
694
|
-
const previousPos = this.positionInBuffer(node, remainder - 1);
|
|
695
|
-
this.deleteNodeTail(node, previousPos);
|
|
696
|
-
value = '\r' + value;
|
|
697
|
-
if (node.piece.length === 0) {
|
|
698
|
-
nodesToDel.push(node);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
else {
|
|
702
|
-
this.deleteNodeTail(node, insertPosInBuffer);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
else {
|
|
706
|
-
this.deleteNodeTail(node, insertPosInBuffer);
|
|
707
|
-
}
|
|
708
|
-
const newPieces = this.createNewPieces(value);
|
|
709
|
-
if (newRightPiece.length > 0) {
|
|
710
|
-
this.rbInsertRight(node, newRightPiece);
|
|
711
|
-
}
|
|
712
|
-
let tmpNode = node;
|
|
713
|
-
for (let k = 0; k < newPieces.length; k++) {
|
|
714
|
-
tmpNode = this.rbInsertRight(tmpNode, newPieces[k]);
|
|
715
|
-
}
|
|
716
|
-
this.deleteNodes(nodesToDel);
|
|
717
|
-
}
|
|
718
|
-
else {
|
|
719
|
-
this.insertContentToNodeRight(value, node);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
else {
|
|
723
|
-
// insert new node
|
|
724
|
-
const pieces = this.createNewPieces(value);
|
|
725
|
-
let node = this.rbInsertLeft(null, pieces[0]);
|
|
726
|
-
for (let k = 1; k < pieces.length; k++) {
|
|
727
|
-
node = this.rbInsertRight(node, pieces[k]);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
// todo, this is too brutal. Total line feed count should be updated the same way as lf_left.
|
|
731
|
-
this.computeBufferMetadata();
|
|
732
|
-
}
|
|
733
|
-
delete(offset, cnt) {
|
|
734
|
-
this._lastVisitedLine.lineNumber = 0;
|
|
735
|
-
this._lastVisitedLine.value = '';
|
|
736
|
-
if (cnt <= 0 || this.root === SENTINEL) {
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
const startPosition = this.nodeAt(offset);
|
|
740
|
-
const endPosition = this.nodeAt(offset + cnt);
|
|
741
|
-
const startNode = startPosition.node;
|
|
742
|
-
const endNode = endPosition.node;
|
|
743
|
-
if (startNode === endNode) {
|
|
744
|
-
const startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);
|
|
745
|
-
const endSplitPosInBuffer = this.positionInBuffer(startNode, endPosition.remainder);
|
|
746
|
-
if (startPosition.nodeStartOffset === offset) {
|
|
747
|
-
if (cnt === startNode.piece.length) { // delete node
|
|
748
|
-
const next = startNode.next();
|
|
749
|
-
rbDelete(this, startNode);
|
|
750
|
-
this.validateCRLFWithPrevNode(next);
|
|
751
|
-
this.computeBufferMetadata();
|
|
752
|
-
return;
|
|
753
|
-
}
|
|
754
|
-
this.deleteNodeHead(startNode, endSplitPosInBuffer);
|
|
755
|
-
this._searchCache.validate(offset);
|
|
756
|
-
this.validateCRLFWithPrevNode(startNode);
|
|
757
|
-
this.computeBufferMetadata();
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
if (startPosition.nodeStartOffset + startNode.piece.length === offset + cnt) {
|
|
761
|
-
this.deleteNodeTail(startNode, startSplitPosInBuffer);
|
|
762
|
-
this.validateCRLFWithNextNode(startNode);
|
|
763
|
-
this.computeBufferMetadata();
|
|
764
|
-
return;
|
|
765
|
-
}
|
|
766
|
-
// delete content in the middle, this node will be splitted to nodes
|
|
767
|
-
this.shrinkNode(startNode, startSplitPosInBuffer, endSplitPosInBuffer);
|
|
768
|
-
this.computeBufferMetadata();
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
const nodesToDel = [];
|
|
772
|
-
const startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);
|
|
773
|
-
this.deleteNodeTail(startNode, startSplitPosInBuffer);
|
|
774
|
-
this._searchCache.validate(offset);
|
|
775
|
-
if (startNode.piece.length === 0) {
|
|
776
|
-
nodesToDel.push(startNode);
|
|
777
|
-
}
|
|
778
|
-
// update last touched node
|
|
779
|
-
const endSplitPosInBuffer = this.positionInBuffer(endNode, endPosition.remainder);
|
|
780
|
-
this.deleteNodeHead(endNode, endSplitPosInBuffer);
|
|
781
|
-
if (endNode.piece.length === 0) {
|
|
782
|
-
nodesToDel.push(endNode);
|
|
783
|
-
}
|
|
784
|
-
// delete nodes in between
|
|
785
|
-
const secondNode = startNode.next();
|
|
786
|
-
for (let node = secondNode; node !== SENTINEL && node !== endNode; node = node.next()) {
|
|
787
|
-
nodesToDel.push(node);
|
|
788
|
-
}
|
|
789
|
-
const prev = startNode.piece.length === 0 ? startNode.prev() : startNode;
|
|
790
|
-
this.deleteNodes(nodesToDel);
|
|
791
|
-
this.validateCRLFWithNextNode(prev);
|
|
792
|
-
this.computeBufferMetadata();
|
|
793
|
-
}
|
|
794
|
-
insertContentToNodeLeft(value, node) {
|
|
795
|
-
// we are inserting content to the beginning of node
|
|
796
|
-
const nodesToDel = [];
|
|
797
|
-
if (this.shouldCheckCRLF() && this.endWithCR(value) && this.startWithLF(node)) {
|
|
798
|
-
// move `\n` to new node.
|
|
799
|
-
const piece = node.piece;
|
|
800
|
-
const newStart = { line: piece.start.line + 1, column: 0 };
|
|
801
|
-
const nPiece = new Piece(piece.bufferIndex, newStart, piece.end, this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end), piece.length - 1);
|
|
802
|
-
node.piece = nPiece;
|
|
803
|
-
value += '\n';
|
|
804
|
-
updateTreeMetadata(this, node, -1, -1);
|
|
805
|
-
if (node.piece.length === 0) {
|
|
806
|
-
nodesToDel.push(node);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
const newPieces = this.createNewPieces(value);
|
|
810
|
-
let newNode = this.rbInsertLeft(node, newPieces[newPieces.length - 1]);
|
|
811
|
-
for (let k = newPieces.length - 2; k >= 0; k--) {
|
|
812
|
-
newNode = this.rbInsertLeft(newNode, newPieces[k]);
|
|
813
|
-
}
|
|
814
|
-
this.validateCRLFWithPrevNode(newNode);
|
|
815
|
-
this.deleteNodes(nodesToDel);
|
|
816
|
-
}
|
|
817
|
-
insertContentToNodeRight(value, node) {
|
|
818
|
-
// we are inserting to the right of this node.
|
|
819
|
-
if (this.adjustCarriageReturnFromNext(value, node)) {
|
|
820
|
-
// move \n to the new node.
|
|
821
|
-
value += '\n';
|
|
822
|
-
}
|
|
823
|
-
const newPieces = this.createNewPieces(value);
|
|
824
|
-
const newNode = this.rbInsertRight(node, newPieces[0]);
|
|
825
|
-
let tmpNode = newNode;
|
|
826
|
-
for (let k = 1; k < newPieces.length; k++) {
|
|
827
|
-
tmpNode = this.rbInsertRight(tmpNode, newPieces[k]);
|
|
828
|
-
}
|
|
829
|
-
this.validateCRLFWithPrevNode(newNode);
|
|
830
|
-
}
|
|
831
|
-
positionInBuffer(node, remainder, ret) {
|
|
832
|
-
const piece = node.piece;
|
|
833
|
-
const bufferIndex = node.piece.bufferIndex;
|
|
834
|
-
const lineStarts = this._buffers[bufferIndex].lineStarts;
|
|
835
|
-
const startOffset = lineStarts[piece.start.line] + piece.start.column;
|
|
836
|
-
const offset = startOffset + remainder;
|
|
837
|
-
// binary search offset between startOffset and endOffset
|
|
838
|
-
let low = piece.start.line;
|
|
839
|
-
let high = piece.end.line;
|
|
840
|
-
let mid = 0;
|
|
841
|
-
let midStop = 0;
|
|
842
|
-
let midStart = 0;
|
|
843
|
-
while (low <= high) {
|
|
844
|
-
mid = low + ((high - low) / 2) | 0;
|
|
845
|
-
midStart = lineStarts[mid];
|
|
846
|
-
if (mid === high) {
|
|
847
|
-
break;
|
|
848
|
-
}
|
|
849
|
-
midStop = lineStarts[mid + 1];
|
|
850
|
-
if (offset < midStart) {
|
|
851
|
-
high = mid - 1;
|
|
852
|
-
}
|
|
853
|
-
else if (offset >= midStop) {
|
|
854
|
-
low = mid + 1;
|
|
855
|
-
}
|
|
856
|
-
else {
|
|
857
|
-
break;
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
if (ret) {
|
|
861
|
-
ret.line = mid;
|
|
862
|
-
ret.column = offset - midStart;
|
|
863
|
-
return null;
|
|
864
|
-
}
|
|
865
|
-
return {
|
|
866
|
-
line: mid,
|
|
867
|
-
column: offset - midStart
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
getLineFeedCnt(bufferIndex, start, end) {
|
|
871
|
-
// we don't need to worry about start: abc\r|\n, or abc|\r, or abc|\n, or abc|\r\n doesn't change the fact that, there is one line break after start.
|
|
872
|
-
// now let's take care of end: abc\r|\n, if end is in between \r and \n, we need to add line feed count by 1
|
|
873
|
-
if (end.column === 0) {
|
|
874
|
-
return end.line - start.line;
|
|
875
|
-
}
|
|
876
|
-
const lineStarts = this._buffers[bufferIndex].lineStarts;
|
|
877
|
-
if (end.line === lineStarts.length - 1) { // it means, there is no \n after end, otherwise, there will be one more lineStart.
|
|
878
|
-
return end.line - start.line;
|
|
879
|
-
}
|
|
880
|
-
const nextLineStartOffset = lineStarts[end.line + 1];
|
|
881
|
-
const endOffset = lineStarts[end.line] + end.column;
|
|
882
|
-
if (nextLineStartOffset > endOffset + 1) { // there are more than 1 character after end, which means it can't be \n
|
|
883
|
-
return end.line - start.line;
|
|
884
|
-
}
|
|
885
|
-
// endOffset + 1 === nextLineStartOffset
|
|
886
|
-
// character at endOffset is \n, so we check the character before first
|
|
887
|
-
// if character at endOffset is \r, end.column is 0 and we can't get here.
|
|
888
|
-
const previousCharOffset = endOffset - 1; // end.column > 0 so it's okay.
|
|
889
|
-
const buffer = this._buffers[bufferIndex].buffer;
|
|
890
|
-
if (buffer.charCodeAt(previousCharOffset) === 13) {
|
|
891
|
-
return end.line - start.line + 1;
|
|
892
|
-
}
|
|
893
|
-
else {
|
|
894
|
-
return end.line - start.line;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
offsetInBuffer(bufferIndex, cursor) {
|
|
898
|
-
const lineStarts = this._buffers[bufferIndex].lineStarts;
|
|
899
|
-
return lineStarts[cursor.line] + cursor.column;
|
|
900
|
-
}
|
|
901
|
-
deleteNodes(nodes) {
|
|
902
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
903
|
-
rbDelete(this, nodes[i]);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
createNewPieces(text) {
|
|
907
|
-
if (text.length > AverageBufferSize) {
|
|
908
|
-
// the content is large, operations like substring, charCode becomes slow
|
|
909
|
-
// so here we split it into smaller chunks, just like what we did for CR/LF normalization
|
|
910
|
-
const newPieces = [];
|
|
911
|
-
while (text.length > AverageBufferSize) {
|
|
912
|
-
const lastChar = text.charCodeAt(AverageBufferSize - 1);
|
|
913
|
-
let splitText;
|
|
914
|
-
if (lastChar === 13 /* CharCode.CarriageReturn */ || (lastChar >= 0xD800 && lastChar <= 0xDBFF)) {
|
|
915
|
-
// last character is \r or a high surrogate => keep it back
|
|
916
|
-
splitText = text.substring(0, AverageBufferSize - 1);
|
|
917
|
-
text = text.substring(AverageBufferSize - 1);
|
|
918
|
-
}
|
|
919
|
-
else {
|
|
920
|
-
splitText = text.substring(0, AverageBufferSize);
|
|
921
|
-
text = text.substring(AverageBufferSize);
|
|
922
|
-
}
|
|
923
|
-
const lineStarts = createLineStartsFast(splitText);
|
|
924
|
-
newPieces.push(new Piece(this._buffers.length, /* buffer index */ { line: 0, column: 0 }, { line: lineStarts.length - 1, column: splitText.length - lineStarts[lineStarts.length - 1] }, lineStarts.length - 1, splitText.length));
|
|
925
|
-
this._buffers.push(new StringBuffer(splitText, lineStarts));
|
|
926
|
-
}
|
|
927
|
-
const lineStarts = createLineStartsFast(text);
|
|
928
|
-
newPieces.push(new Piece(this._buffers.length, /* buffer index */ { line: 0, column: 0 }, { line: lineStarts.length - 1, column: text.length - lineStarts[lineStarts.length - 1] }, lineStarts.length - 1, text.length));
|
|
929
|
-
this._buffers.push(new StringBuffer(text, lineStarts));
|
|
930
|
-
return newPieces;
|
|
931
|
-
}
|
|
932
|
-
let startOffset = this._buffers[0].buffer.length;
|
|
933
|
-
const lineStarts = createLineStartsFast(text, false);
|
|
934
|
-
let start = this._lastChangeBufferPos;
|
|
935
|
-
if (this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 1] === startOffset
|
|
936
|
-
&& startOffset !== 0
|
|
937
|
-
&& this.startWithLF(text)
|
|
938
|
-
&& this.endWithCR(this._buffers[0].buffer) // todo, we can check this._lastChangeBufferPos's column as it's the last one
|
|
939
|
-
) {
|
|
940
|
-
this._lastChangeBufferPos = { line: this._lastChangeBufferPos.line, column: this._lastChangeBufferPos.column + 1 };
|
|
941
|
-
start = this._lastChangeBufferPos;
|
|
942
|
-
for (let i = 0; i < lineStarts.length; i++) {
|
|
943
|
-
lineStarts[i] += startOffset + 1;
|
|
944
|
-
}
|
|
945
|
-
this._buffers[0].lineStarts = this._buffers[0].lineStarts.concat(lineStarts.slice(1));
|
|
946
|
-
this._buffers[0].buffer += '_' + text;
|
|
947
|
-
startOffset += 1;
|
|
948
|
-
}
|
|
949
|
-
else {
|
|
950
|
-
if (startOffset !== 0) {
|
|
951
|
-
for (let i = 0; i < lineStarts.length; i++) {
|
|
952
|
-
lineStarts[i] += startOffset;
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
this._buffers[0].lineStarts = this._buffers[0].lineStarts.concat(lineStarts.slice(1));
|
|
956
|
-
this._buffers[0].buffer += text;
|
|
957
|
-
}
|
|
958
|
-
const endOffset = this._buffers[0].buffer.length;
|
|
959
|
-
const endIndex = this._buffers[0].lineStarts.length - 1;
|
|
960
|
-
const endColumn = endOffset - this._buffers[0].lineStarts[endIndex];
|
|
961
|
-
const endPos = { line: endIndex, column: endColumn };
|
|
962
|
-
const newPiece = new Piece(0, /** todo@peng */ start, endPos, this.getLineFeedCnt(0, start, endPos), endOffset - startOffset);
|
|
963
|
-
this._lastChangeBufferPos = endPos;
|
|
964
|
-
return [newPiece];
|
|
965
|
-
}
|
|
966
|
-
getLineRawContent(lineNumber, endOffset = 0) {
|
|
967
|
-
let x = this.root;
|
|
968
|
-
let ret = '';
|
|
969
|
-
const cache = this._searchCache.get2(lineNumber);
|
|
970
|
-
if (cache) {
|
|
971
|
-
x = cache.node;
|
|
972
|
-
const prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber - 1);
|
|
973
|
-
const buffer = this._buffers[x.piece.bufferIndex].buffer;
|
|
974
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
975
|
-
if (cache.nodeStartLineNumber + x.piece.lineFeedCnt === lineNumber) {
|
|
976
|
-
ret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);
|
|
977
|
-
}
|
|
978
|
-
else {
|
|
979
|
-
const accumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber);
|
|
980
|
-
return buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
else {
|
|
984
|
-
let nodeStartOffset = 0;
|
|
985
|
-
const originalLineNumber = lineNumber;
|
|
986
|
-
while (x !== SENTINEL) {
|
|
987
|
-
if (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {
|
|
988
|
-
x = x.left;
|
|
989
|
-
}
|
|
990
|
-
else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {
|
|
991
|
-
const prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
|
|
992
|
-
const accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
|
|
993
|
-
const buffer = this._buffers[x.piece.bufferIndex].buffer;
|
|
994
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
995
|
-
nodeStartOffset += x.size_left;
|
|
996
|
-
this._searchCache.set({
|
|
997
|
-
node: x,
|
|
998
|
-
nodeStartOffset,
|
|
999
|
-
nodeStartLineNumber: originalLineNumber - (lineNumber - 1 - x.lf_left)
|
|
1000
|
-
});
|
|
1001
|
-
return buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);
|
|
1002
|
-
}
|
|
1003
|
-
else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {
|
|
1004
|
-
const prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
|
|
1005
|
-
const buffer = this._buffers[x.piece.bufferIndex].buffer;
|
|
1006
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
1007
|
-
ret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);
|
|
1008
|
-
break;
|
|
1009
|
-
}
|
|
1010
|
-
else {
|
|
1011
|
-
lineNumber -= x.lf_left + x.piece.lineFeedCnt;
|
|
1012
|
-
nodeStartOffset += x.size_left + x.piece.length;
|
|
1013
|
-
x = x.right;
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
// search in order, to find the node contains end column
|
|
1018
|
-
x = x.next();
|
|
1019
|
-
while (x !== SENTINEL) {
|
|
1020
|
-
const buffer = this._buffers[x.piece.bufferIndex].buffer;
|
|
1021
|
-
if (x.piece.lineFeedCnt > 0) {
|
|
1022
|
-
const accumulatedValue = this.getAccumulatedValue(x, 0);
|
|
1023
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
1024
|
-
ret += buffer.substring(startOffset, startOffset + accumulatedValue - endOffset);
|
|
1025
|
-
return ret;
|
|
1026
|
-
}
|
|
1027
|
-
else {
|
|
1028
|
-
const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
|
|
1029
|
-
ret += buffer.substr(startOffset, x.piece.length);
|
|
1030
|
-
}
|
|
1031
|
-
x = x.next();
|
|
1032
|
-
}
|
|
1033
|
-
return ret;
|
|
1034
|
-
}
|
|
1035
|
-
computeBufferMetadata() {
|
|
1036
|
-
let x = this.root;
|
|
1037
|
-
let lfCnt = 1;
|
|
1038
|
-
let len = 0;
|
|
1039
|
-
while (x !== SENTINEL) {
|
|
1040
|
-
lfCnt += x.lf_left + x.piece.lineFeedCnt;
|
|
1041
|
-
len += x.size_left + x.piece.length;
|
|
1042
|
-
x = x.right;
|
|
1043
|
-
}
|
|
1044
|
-
this._lineCnt = lfCnt;
|
|
1045
|
-
this._length = len;
|
|
1046
|
-
this._searchCache.validate(this._length);
|
|
1047
|
-
}
|
|
1048
|
-
// #region node operations
|
|
1049
|
-
getIndexOf(node, accumulatedValue) {
|
|
1050
|
-
const piece = node.piece;
|
|
1051
|
-
const pos = this.positionInBuffer(node, accumulatedValue);
|
|
1052
|
-
const lineCnt = pos.line - piece.start.line;
|
|
1053
|
-
if (this.offsetInBuffer(piece.bufferIndex, piece.end) - this.offsetInBuffer(piece.bufferIndex, piece.start) === accumulatedValue) {
|
|
1054
|
-
// we are checking the end of this node, so a CRLF check is necessary.
|
|
1055
|
-
const realLineCnt = this.getLineFeedCnt(node.piece.bufferIndex, piece.start, pos);
|
|
1056
|
-
if (realLineCnt !== lineCnt) {
|
|
1057
|
-
// aha yes, CRLF
|
|
1058
|
-
return { index: realLineCnt, remainder: 0 };
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
return { index: lineCnt, remainder: pos.column };
|
|
1062
|
-
}
|
|
1063
|
-
getAccumulatedValue(node, index) {
|
|
1064
|
-
if (index < 0) {
|
|
1065
|
-
return 0;
|
|
1066
|
-
}
|
|
1067
|
-
const piece = node.piece;
|
|
1068
|
-
const lineStarts = this._buffers[piece.bufferIndex].lineStarts;
|
|
1069
|
-
const expectedLineStartIndex = piece.start.line + index + 1;
|
|
1070
|
-
if (expectedLineStartIndex > piece.end.line) {
|
|
1071
|
-
return lineStarts[piece.end.line] + piece.end.column - lineStarts[piece.start.line] - piece.start.column;
|
|
1072
|
-
}
|
|
1073
|
-
else {
|
|
1074
|
-
return lineStarts[expectedLineStartIndex] - lineStarts[piece.start.line] - piece.start.column;
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
deleteNodeTail(node, pos) {
|
|
1078
|
-
const piece = node.piece;
|
|
1079
|
-
const originalLFCnt = piece.lineFeedCnt;
|
|
1080
|
-
const originalEndOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);
|
|
1081
|
-
const newEnd = pos;
|
|
1082
|
-
const newEndOffset = this.offsetInBuffer(piece.bufferIndex, newEnd);
|
|
1083
|
-
const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);
|
|
1084
|
-
const lf_delta = newLineFeedCnt - originalLFCnt;
|
|
1085
|
-
const size_delta = newEndOffset - originalEndOffset;
|
|
1086
|
-
const newLength = piece.length + size_delta;
|
|
1087
|
-
node.piece = new Piece(piece.bufferIndex, piece.start, newEnd, newLineFeedCnt, newLength);
|
|
1088
|
-
updateTreeMetadata(this, node, size_delta, lf_delta);
|
|
1089
|
-
}
|
|
1090
|
-
deleteNodeHead(node, pos) {
|
|
1091
|
-
const piece = node.piece;
|
|
1092
|
-
const originalLFCnt = piece.lineFeedCnt;
|
|
1093
|
-
const originalStartOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);
|
|
1094
|
-
const newStart = pos;
|
|
1095
|
-
const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);
|
|
1096
|
-
const newStartOffset = this.offsetInBuffer(piece.bufferIndex, newStart);
|
|
1097
|
-
const lf_delta = newLineFeedCnt - originalLFCnt;
|
|
1098
|
-
const size_delta = originalStartOffset - newStartOffset;
|
|
1099
|
-
const newLength = piece.length + size_delta;
|
|
1100
|
-
node.piece = new Piece(piece.bufferIndex, newStart, piece.end, newLineFeedCnt, newLength);
|
|
1101
|
-
updateTreeMetadata(this, node, size_delta, lf_delta);
|
|
1102
|
-
}
|
|
1103
|
-
shrinkNode(node, start, end) {
|
|
1104
|
-
const piece = node.piece;
|
|
1105
|
-
const originalStartPos = piece.start;
|
|
1106
|
-
const originalEndPos = piece.end;
|
|
1107
|
-
// old piece, originalStartPos, start
|
|
1108
|
-
const oldLength = piece.length;
|
|
1109
|
-
const oldLFCnt = piece.lineFeedCnt;
|
|
1110
|
-
const newEnd = start;
|
|
1111
|
-
const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);
|
|
1112
|
-
const newLength = this.offsetInBuffer(piece.bufferIndex, start) - this.offsetInBuffer(piece.bufferIndex, originalStartPos);
|
|
1113
|
-
node.piece = new Piece(piece.bufferIndex, piece.start, newEnd, newLineFeedCnt, newLength);
|
|
1114
|
-
updateTreeMetadata(this, node, newLength - oldLength, newLineFeedCnt - oldLFCnt);
|
|
1115
|
-
// new right piece, end, originalEndPos
|
|
1116
|
-
const newPiece = new Piece(piece.bufferIndex, end, originalEndPos, this.getLineFeedCnt(piece.bufferIndex, end, originalEndPos), this.offsetInBuffer(piece.bufferIndex, originalEndPos) - this.offsetInBuffer(piece.bufferIndex, end));
|
|
1117
|
-
const newNode = this.rbInsertRight(node, newPiece);
|
|
1118
|
-
this.validateCRLFWithPrevNode(newNode);
|
|
1119
|
-
}
|
|
1120
|
-
appendToNode(node, value) {
|
|
1121
|
-
if (this.adjustCarriageReturnFromNext(value, node)) {
|
|
1122
|
-
value += '\n';
|
|
1123
|
-
}
|
|
1124
|
-
const hitCRLF = this.shouldCheckCRLF() && this.startWithLF(value) && this.endWithCR(node);
|
|
1125
|
-
const startOffset = this._buffers[0].buffer.length;
|
|
1126
|
-
this._buffers[0].buffer += value;
|
|
1127
|
-
const lineStarts = createLineStartsFast(value, false);
|
|
1128
|
-
for (let i = 0; i < lineStarts.length; i++) {
|
|
1129
|
-
lineStarts[i] += startOffset;
|
|
1130
|
-
}
|
|
1131
|
-
if (hitCRLF) {
|
|
1132
|
-
const prevStartOffset = this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 2];
|
|
1133
|
-
this._buffers[0].lineStarts.pop();
|
|
1134
|
-
// _lastChangeBufferPos is already wrong
|
|
1135
|
-
this._lastChangeBufferPos = { line: this._lastChangeBufferPos.line - 1, column: startOffset - prevStartOffset };
|
|
1136
|
-
}
|
|
1137
|
-
this._buffers[0].lineStarts = this._buffers[0].lineStarts.concat(lineStarts.slice(1));
|
|
1138
|
-
const endIndex = this._buffers[0].lineStarts.length - 1;
|
|
1139
|
-
const endColumn = this._buffers[0].buffer.length - this._buffers[0].lineStarts[endIndex];
|
|
1140
|
-
const newEnd = { line: endIndex, column: endColumn };
|
|
1141
|
-
const newLength = node.piece.length + value.length;
|
|
1142
|
-
const oldLineFeedCnt = node.piece.lineFeedCnt;
|
|
1143
|
-
const newLineFeedCnt = this.getLineFeedCnt(0, node.piece.start, newEnd);
|
|
1144
|
-
const lf_delta = newLineFeedCnt - oldLineFeedCnt;
|
|
1145
|
-
node.piece = new Piece(node.piece.bufferIndex, node.piece.start, newEnd, newLineFeedCnt, newLength);
|
|
1146
|
-
this._lastChangeBufferPos = newEnd;
|
|
1147
|
-
updateTreeMetadata(this, node, value.length, lf_delta);
|
|
1148
|
-
}
|
|
1149
|
-
nodeAt(offset) {
|
|
1150
|
-
let x = this.root;
|
|
1151
|
-
const cache = this._searchCache.get(offset);
|
|
1152
|
-
if (cache) {
|
|
1153
|
-
return {
|
|
1154
|
-
node: cache.node,
|
|
1155
|
-
nodeStartOffset: cache.nodeStartOffset,
|
|
1156
|
-
remainder: offset - cache.nodeStartOffset
|
|
1157
|
-
};
|
|
1158
|
-
}
|
|
1159
|
-
let nodeStartOffset = 0;
|
|
1160
|
-
while (x !== SENTINEL) {
|
|
1161
|
-
if (x.size_left > offset) {
|
|
1162
|
-
x = x.left;
|
|
1163
|
-
}
|
|
1164
|
-
else if (x.size_left + x.piece.length >= offset) {
|
|
1165
|
-
nodeStartOffset += x.size_left;
|
|
1166
|
-
const ret = {
|
|
1167
|
-
node: x,
|
|
1168
|
-
remainder: offset - x.size_left,
|
|
1169
|
-
nodeStartOffset
|
|
1170
|
-
};
|
|
1171
|
-
this._searchCache.set(ret);
|
|
1172
|
-
return ret;
|
|
1173
|
-
}
|
|
1174
|
-
else {
|
|
1175
|
-
offset -= x.size_left + x.piece.length;
|
|
1176
|
-
nodeStartOffset += x.size_left + x.piece.length;
|
|
1177
|
-
x = x.right;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
return null;
|
|
1181
|
-
}
|
|
1182
|
-
nodeAt2(lineNumber, column) {
|
|
1183
|
-
let x = this.root;
|
|
1184
|
-
let nodeStartOffset = 0;
|
|
1185
|
-
while (x !== SENTINEL) {
|
|
1186
|
-
if (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {
|
|
1187
|
-
x = x.left;
|
|
1188
|
-
}
|
|
1189
|
-
else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {
|
|
1190
|
-
const prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
|
|
1191
|
-
const accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
|
|
1192
|
-
nodeStartOffset += x.size_left;
|
|
1193
|
-
return {
|
|
1194
|
-
node: x,
|
|
1195
|
-
remainder: Math.min(prevAccumualtedValue + column - 1, accumulatedValue),
|
|
1196
|
-
nodeStartOffset
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {
|
|
1200
|
-
const prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
|
|
1201
|
-
if (prevAccumualtedValue + column - 1 <= x.piece.length) {
|
|
1202
|
-
return {
|
|
1203
|
-
node: x,
|
|
1204
|
-
remainder: prevAccumualtedValue + column - 1,
|
|
1205
|
-
nodeStartOffset
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
else {
|
|
1209
|
-
column -= x.piece.length - prevAccumualtedValue;
|
|
1210
|
-
break;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
else {
|
|
1214
|
-
lineNumber -= x.lf_left + x.piece.lineFeedCnt;
|
|
1215
|
-
nodeStartOffset += x.size_left + x.piece.length;
|
|
1216
|
-
x = x.right;
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
// search in order, to find the node contains position.column
|
|
1220
|
-
x = x.next();
|
|
1221
|
-
while (x !== SENTINEL) {
|
|
1222
|
-
if (x.piece.lineFeedCnt > 0) {
|
|
1223
|
-
const accumulatedValue = this.getAccumulatedValue(x, 0);
|
|
1224
|
-
const nodeStartOffset = this.offsetOfNode(x);
|
|
1225
|
-
return {
|
|
1226
|
-
node: x,
|
|
1227
|
-
remainder: Math.min(column - 1, accumulatedValue),
|
|
1228
|
-
nodeStartOffset
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
else {
|
|
1232
|
-
if (x.piece.length >= column - 1) {
|
|
1233
|
-
const nodeStartOffset = this.offsetOfNode(x);
|
|
1234
|
-
return {
|
|
1235
|
-
node: x,
|
|
1236
|
-
remainder: column - 1,
|
|
1237
|
-
nodeStartOffset
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
else {
|
|
1241
|
-
column -= x.piece.length;
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
x = x.next();
|
|
1245
|
-
}
|
|
1246
|
-
return null;
|
|
1247
|
-
}
|
|
1248
|
-
nodeCharCodeAt(node, offset) {
|
|
1249
|
-
if (node.piece.lineFeedCnt < 1) {
|
|
1250
|
-
return -1;
|
|
1251
|
-
}
|
|
1252
|
-
const buffer = this._buffers[node.piece.bufferIndex];
|
|
1253
|
-
const newOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start) + offset;
|
|
1254
|
-
return buffer.buffer.charCodeAt(newOffset);
|
|
1255
|
-
}
|
|
1256
|
-
offsetOfNode(node) {
|
|
1257
|
-
if (!node) {
|
|
1258
|
-
return 0;
|
|
1259
|
-
}
|
|
1260
|
-
let pos = node.size_left;
|
|
1261
|
-
while (node !== this.root) {
|
|
1262
|
-
if (node.parent.right === node) {
|
|
1263
|
-
pos += node.parent.size_left + node.parent.piece.length;
|
|
1264
|
-
}
|
|
1265
|
-
node = node.parent;
|
|
1266
|
-
}
|
|
1267
|
-
return pos;
|
|
1268
|
-
}
|
|
1269
|
-
// #endregion
|
|
1270
|
-
// #region CRLF
|
|
1271
|
-
shouldCheckCRLF() {
|
|
1272
|
-
return !(this._EOLNormalized && this._EOL === '\n');
|
|
1273
|
-
}
|
|
1274
|
-
startWithLF(val) {
|
|
1275
|
-
if (typeof val === 'string') {
|
|
1276
|
-
return val.charCodeAt(0) === 10;
|
|
1277
|
-
}
|
|
1278
|
-
if (val === SENTINEL || val.piece.lineFeedCnt === 0) {
|
|
1279
|
-
return false;
|
|
1280
|
-
}
|
|
1281
|
-
const piece = val.piece;
|
|
1282
|
-
const lineStarts = this._buffers[piece.bufferIndex].lineStarts;
|
|
1283
|
-
const line = piece.start.line;
|
|
1284
|
-
const startOffset = lineStarts[line] + piece.start.column;
|
|
1285
|
-
if (line === lineStarts.length - 1) {
|
|
1286
|
-
// last line, so there is no line feed at the end of this line
|
|
1287
|
-
return false;
|
|
1288
|
-
}
|
|
1289
|
-
const nextLineOffset = lineStarts[line + 1];
|
|
1290
|
-
if (nextLineOffset > startOffset + 1) {
|
|
1291
|
-
return false;
|
|
1292
|
-
}
|
|
1293
|
-
return this._buffers[piece.bufferIndex].buffer.charCodeAt(startOffset) === 10;
|
|
1294
|
-
}
|
|
1295
|
-
endWithCR(val) {
|
|
1296
|
-
if (typeof val === 'string') {
|
|
1297
|
-
return val.charCodeAt(val.length - 1) === 13;
|
|
1298
|
-
}
|
|
1299
|
-
if (val === SENTINEL || val.piece.lineFeedCnt === 0) {
|
|
1300
|
-
return false;
|
|
1301
|
-
}
|
|
1302
|
-
return this.nodeCharCodeAt(val, val.piece.length - 1) === 13;
|
|
1303
|
-
}
|
|
1304
|
-
validateCRLFWithPrevNode(nextNode) {
|
|
1305
|
-
if (this.shouldCheckCRLF() && this.startWithLF(nextNode)) {
|
|
1306
|
-
const node = nextNode.prev();
|
|
1307
|
-
if (this.endWithCR(node)) {
|
|
1308
|
-
this.fixCRLF(node, nextNode);
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
validateCRLFWithNextNode(node) {
|
|
1313
|
-
if (this.shouldCheckCRLF() && this.endWithCR(node)) {
|
|
1314
|
-
const nextNode = node.next();
|
|
1315
|
-
if (this.startWithLF(nextNode)) {
|
|
1316
|
-
this.fixCRLF(node, nextNode);
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
fixCRLF(prev, next) {
|
|
1321
|
-
const nodesToDel = [];
|
|
1322
|
-
// update node
|
|
1323
|
-
const lineStarts = this._buffers[prev.piece.bufferIndex].lineStarts;
|
|
1324
|
-
let newEnd;
|
|
1325
|
-
if (prev.piece.end.column === 0) {
|
|
1326
|
-
// it means, last line ends with \r, not \r\n
|
|
1327
|
-
newEnd = { line: prev.piece.end.line - 1, column: lineStarts[prev.piece.end.line] - lineStarts[prev.piece.end.line - 1] - 1 };
|
|
1328
|
-
}
|
|
1329
|
-
else {
|
|
1330
|
-
// \r\n
|
|
1331
|
-
newEnd = { line: prev.piece.end.line, column: prev.piece.end.column - 1 };
|
|
1332
|
-
}
|
|
1333
|
-
const prevNewLength = prev.piece.length - 1;
|
|
1334
|
-
const prevNewLFCnt = prev.piece.lineFeedCnt - 1;
|
|
1335
|
-
prev.piece = new Piece(prev.piece.bufferIndex, prev.piece.start, newEnd, prevNewLFCnt, prevNewLength);
|
|
1336
|
-
updateTreeMetadata(this, prev, -1, -1);
|
|
1337
|
-
if (prev.piece.length === 0) {
|
|
1338
|
-
nodesToDel.push(prev);
|
|
1339
|
-
}
|
|
1340
|
-
// update nextNode
|
|
1341
|
-
const newStart = { line: next.piece.start.line + 1, column: 0 };
|
|
1342
|
-
const newLength = next.piece.length - 1;
|
|
1343
|
-
const newLineFeedCnt = this.getLineFeedCnt(next.piece.bufferIndex, newStart, next.piece.end);
|
|
1344
|
-
next.piece = new Piece(next.piece.bufferIndex, newStart, next.piece.end, newLineFeedCnt, newLength);
|
|
1345
|
-
updateTreeMetadata(this, next, -1, -1);
|
|
1346
|
-
if (next.piece.length === 0) {
|
|
1347
|
-
nodesToDel.push(next);
|
|
1348
|
-
}
|
|
1349
|
-
// create new piece which contains \r\n
|
|
1350
|
-
const pieces = this.createNewPieces('\r\n');
|
|
1351
|
-
this.rbInsertRight(prev, pieces[0]);
|
|
1352
|
-
// delete empty nodes
|
|
1353
|
-
for (let i = 0; i < nodesToDel.length; i++) {
|
|
1354
|
-
rbDelete(this, nodesToDel[i]);
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
adjustCarriageReturnFromNext(value, node) {
|
|
1358
|
-
if (this.shouldCheckCRLF() && this.endWithCR(value)) {
|
|
1359
|
-
const nextNode = node.next();
|
|
1360
|
-
if (this.startWithLF(nextNode)) {
|
|
1361
|
-
// move `\n` forward
|
|
1362
|
-
value += '\n';
|
|
1363
|
-
if (nextNode.piece.length === 1) {
|
|
1364
|
-
rbDelete(this, nextNode);
|
|
1365
|
-
}
|
|
1366
|
-
else {
|
|
1367
|
-
const piece = nextNode.piece;
|
|
1368
|
-
const newStart = { line: piece.start.line + 1, column: 0 };
|
|
1369
|
-
const newLength = piece.length - 1;
|
|
1370
|
-
const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);
|
|
1371
|
-
nextNode.piece = new Piece(piece.bufferIndex, newStart, piece.end, newLineFeedCnt, newLength);
|
|
1372
|
-
updateTreeMetadata(this, nextNode, -1, -1);
|
|
1373
|
-
}
|
|
1374
|
-
return true;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
return false;
|
|
1378
|
-
}
|
|
1379
|
-
// #endregion
|
|
1380
|
-
// #endregion
|
|
1381
|
-
// #region Tree operations
|
|
1382
|
-
iterate(node, callback) {
|
|
1383
|
-
if (node === SENTINEL) {
|
|
1384
|
-
return callback(SENTINEL);
|
|
1385
|
-
}
|
|
1386
|
-
const leftRet = this.iterate(node.left, callback);
|
|
1387
|
-
if (!leftRet) {
|
|
1388
|
-
return leftRet;
|
|
1389
|
-
}
|
|
1390
|
-
return callback(node) && this.iterate(node.right, callback);
|
|
1391
|
-
}
|
|
1392
|
-
getNodeContent(node) {
|
|
1393
|
-
if (node === SENTINEL) {
|
|
1394
|
-
return '';
|
|
1395
|
-
}
|
|
1396
|
-
const buffer = this._buffers[node.piece.bufferIndex];
|
|
1397
|
-
const piece = node.piece;
|
|
1398
|
-
const startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);
|
|
1399
|
-
const endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);
|
|
1400
|
-
const currentContent = buffer.buffer.substring(startOffset, endOffset);
|
|
1401
|
-
return currentContent;
|
|
1402
|
-
}
|
|
1403
|
-
getPieceContent(piece) {
|
|
1404
|
-
const buffer = this._buffers[piece.bufferIndex];
|
|
1405
|
-
const startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);
|
|
1406
|
-
const endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);
|
|
1407
|
-
const currentContent = buffer.buffer.substring(startOffset, endOffset);
|
|
1408
|
-
return currentContent;
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* node node
|
|
1412
|
-
* / \ / \
|
|
1413
|
-
* a b <---- a b
|
|
1414
|
-
* /
|
|
1415
|
-
* z
|
|
1416
|
-
*/
|
|
1417
|
-
rbInsertRight(node, p) {
|
|
1418
|
-
const z = new TreeNode(p, 1 /* NodeColor.Red */);
|
|
1419
|
-
z.left = SENTINEL;
|
|
1420
|
-
z.right = SENTINEL;
|
|
1421
|
-
z.parent = SENTINEL;
|
|
1422
|
-
z.size_left = 0;
|
|
1423
|
-
z.lf_left = 0;
|
|
1424
|
-
const x = this.root;
|
|
1425
|
-
if (x === SENTINEL) {
|
|
1426
|
-
this.root = z;
|
|
1427
|
-
z.color = 0 /* NodeColor.Black */;
|
|
1428
|
-
}
|
|
1429
|
-
else if (node.right === SENTINEL) {
|
|
1430
|
-
node.right = z;
|
|
1431
|
-
z.parent = node;
|
|
1432
|
-
}
|
|
1433
|
-
else {
|
|
1434
|
-
const nextNode = leftest(node.right);
|
|
1435
|
-
nextNode.left = z;
|
|
1436
|
-
z.parent = nextNode;
|
|
1437
|
-
}
|
|
1438
|
-
fixInsert(this, z);
|
|
1439
|
-
return z;
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* node node
|
|
1443
|
-
* / \ / \
|
|
1444
|
-
* a b ----> a b
|
|
1445
|
-
* \
|
|
1446
|
-
* z
|
|
1447
|
-
*/
|
|
1448
|
-
rbInsertLeft(node, p) {
|
|
1449
|
-
const z = new TreeNode(p, 1 /* NodeColor.Red */);
|
|
1450
|
-
z.left = SENTINEL;
|
|
1451
|
-
z.right = SENTINEL;
|
|
1452
|
-
z.parent = SENTINEL;
|
|
1453
|
-
z.size_left = 0;
|
|
1454
|
-
z.lf_left = 0;
|
|
1455
|
-
if (this.root === SENTINEL) {
|
|
1456
|
-
this.root = z;
|
|
1457
|
-
z.color = 0 /* NodeColor.Black */;
|
|
1458
|
-
}
|
|
1459
|
-
else if (node.left === SENTINEL) {
|
|
1460
|
-
node.left = z;
|
|
1461
|
-
z.parent = node;
|
|
1462
|
-
}
|
|
1463
|
-
else {
|
|
1464
|
-
const prevNode = righttest(node.left); // a
|
|
1465
|
-
prevNode.right = z;
|
|
1466
|
-
z.parent = prevNode;
|
|
1467
|
-
}
|
|
1468
|
-
fixInsert(this, z);
|
|
1469
|
-
return z;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
export { Piece, PieceTreeBase, StringBuffer, createLineStarts, createLineStartsFast };
|