src/vs/editor/common/tokens/sparseMultilineTokens.ts

617 LOC · 549 covered · 68 uncovered · 135 ranges · 61 concepts · 33 introducers · 20 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/editor/common/model/tokens/tokenizationTextModelPart.ts · 389 LOCtokens/tokenizationTextM…src/vs/editor/common/services/semanticTokensProviderStyling.ts · 328 LOCservices/semanticTokensP…src/vs/editor/common/tokens/common.ts · 22 LOCtokens/common.tssrc/vs/editor/common/tokens/sparseTokensStore.ts · 260 LOCtokens/sparseTokensStore…sparseMultilineTokens.ts ×10 · 49 introduced LOCsparseMultilineTokens.ts…tokensStore.test|title=TokensStore inserting a newline|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…sparseMultilineTokens.ts ×11 · 65 introduced LOCsparseMultilineTokens.ts…tokensStore.test|title=TokensStore issue #86303 - color shifting between different tokens|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…sparseMultilineTokens.ts ×2 · 7 introduced LOCsparseMultilineTokens.ts…tokensStore.test|title=TokensStore deleting a newline|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…sparseMultilineTokens.ts ×2 · 6 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×2 · 6 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×9 · 74 introduced LOCsparseMultilineTokens.ts…languageConfigurationRegistry.ts ×8 · 53 introduced LOClanguageConfigurationReg…sparseTokensStore.ts ×1 · 3 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×5 · 21 introduced LOCsparseMultilineTokens.ts…semanticTokensProviderStyling.ts ×6 · 16 introduced LOCsemanticTokensProviderSt…semanticTokensProviderStyling.ts ×2 · 5 introduced LOCsemanticTokensProviderSt…semanticTokensProviderStyling.ts ×1 · 19 introduced LOCsemanticTokensProviderSt…semanticTokensProviderStyling.ts ×18 · 247 introduced LOCsemanticTokensProviderSt…sparseTokensStore.ts ×1 · 4 introduced LOCsparseTokensStore.ts ×1tokensStore.test|title=TokensStore partial tokens 1|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…sparseTokensStore.ts ×3 · 9 introduced LOCsparseTokensStore.ts ×3sparseTokensStore.ts ×2 · 3 introduced LOCsparseTokensStore.ts ×2sparseTokensStore.ts ×2 · 4 introduced LOCsparseTokensStore.ts ×2sparseMultilineTokens.ts ×3 · 48 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×1 · 3 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×1 · 7 introduced LOCsparseMultilineTokens.ts…range.ts ×1 · 3 introduced LOCrange.ts ×1sparseTokensStore.ts ×3 · 5 introduced LOCsparseTokensStore.ts ×3sparseMultilineTokens.ts ×1 · 3 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×1 · 4 introduced LOCsparseTokensStore.ts ×1sparseTokensStore.ts ×1 · 2 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×3 · 9 introduced LOCsparseMultilineTokens.ts…tokensStore.test|title=TokensStore issue #94133: Semantic colors stick around when using (only) range provider|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…tokensStore.test|title=TokensStore addSparseTokens skips overlapping semantic tokens that produce backward endOffsets|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…sparseMultilineTokens.ts ×1 · 1 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×1 · 1 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×4 · 18 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×1 · 2 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×3 · 6 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×1 · 3 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×4 · 7 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×1 · 2 introduced LOCsparseTokensStore.ts ×1sparseTokensStore.ts ×1 · 3 introduced LOCsparseTokensStore.ts ×1sparseTokensStore.ts ×10 · 83 introduced LOCsparseTokensStore.ts ×10sparseMultilineTokens.ts ×2 · 11 introduced LOCsparseMultilineTokens.ts…tokensStore.test|title=TokensStore BUG: setPartial with startLineNumber > 1 and token removal creates invalid state|occurrence=1 · 0 introduced LOCtokensStore.test|title=T…sparseTokensStore.ts ×1 · 6 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×1 · 1 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×4 · 13 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×6 · 56 introduced LOCsparseTokensStore.ts ×6sparseMultilineTokens.ts ×6 · 15 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×1 · 2 introduced LOCsparseTokensStore.ts ×1sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×2 · 4 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×3 · 6 introduced LOCsparseMultilineTokens.ts…sparseTokensStore.ts ×2 · 5 introduced LOCsparseTokensStore.ts ×2sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×1 · 2 introduced LOCsparseMultilineTokens.ts…sparseMultilineTokens.ts ×33 · 153 introduced LOCsparseMultilineTokens.ts…tokensStore.test|title=TokensStore BUG: setPartial with split that creates empty first piece with invalid line numbers|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore BUG: setPartial with split that creates empty first piece with invalid line numbers|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore BUG: setPartial with startLineNumber > 1 and token removal creates invalid state|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore BUG: setPartial with startLineNumber > 1 and token removal creates invalid state|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore addSparseTokens skips overlapping semantic tokens that produce backward endOffsets|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore addSparseTokens skips overlapping semantic tokens that produce backward endOffsets|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore bug|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore bug|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore deleting a newline 2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore deleting a newline 2|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore deleting a newline|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore deleting a newline|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore inserting a newline|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore inserting a newline|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore issue #147944: Language id "vs.editor.nullLanguage" is not configured nor known|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore issue #147944: Language id "vs.editor.nullLanguage" is not configured nor known|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore issue #179268: a complex edit|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore issue #179268: a complex edit|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore issue #86303 - color shifting between different tokens|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore issue #86303 - color shifting between different tokens|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore issue #91936: Semantic token color highlighting fails on line with selected text|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore issue #91936: Semantic token color highlighting fails on line with selected text|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore issue #94133: Semantic colors stick around when using (only) range provider|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore issue #94133: Semantic colors stick around when using (only) range provider|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore issue #95949: Identifiers are colored in bold when targetting keywords|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore issue #95949: Identifiers are colored in bold when targetting keywords|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore partial tokens 1|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore partial tokens 1|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore partial tokens 2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore partial tokens 2|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore partial tokens 3|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore partial tokens 3|occurrence=1tokensStore.test|title=T…tokensStore.test|title=TokensStore piece with startLineNumber 0 and endLineNumber -1 after encompassing deletion|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/tokensStore.test|title=TokensStore piece with startLineNumber 0 and endLineNumber -1 after encompassing deletion|occurrence=1tokensStore.test|title=T…semanticTokensProviderStyling.test|title=ModelService issue #134973: invalid semantic tokens should be handled better|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/semanticTokensProviderStyling.test|title=ModelService issue #134973: invalid semantic tokens should be handled better|occurrence=1semanticTokensProviderSt…semanticTokensProviderStyling.test|title=ModelService issue #148651: VSCode UI process can hang if a semantic token with negative values is returned by language service|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/semanticTokensProviderStyling.test|title=ModelService issue #148651: VSCode UI process can hang if a semantic token with negative values is returned by language service|occurrence=1semanticTokensProviderSt…semanticTokensProviderStyling.test|title=ModelService issue #149130: vscode freezes because of Bracket Pair Colorization|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/semanticTokensProviderStyling.test|title=ModelService issue #149130: vscode freezes because of Bracket Pair Colorization|occurrence=1semanticTokensProviderSt…Focused file · src/vs/editor/common/tokens/sparseMultilineTokens.ts · 617 LOCtokens/sparseMultilineTo…

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- sparseMultilineTokens.ts ×33
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CharCode } from '../../../base/common/charCode.js';
7 > import { Position } from '../core/position.js';
8 > import { IRange, Range } from '../core/range.js';
9 > import { countEOL } from '../core/misc/eolCounter.js';
10 > import { ITextModel } from '../model.js';
11 > import { RateLimiter } from './common.js';
12 >
13 > /**
14 > * Represents sparse tokens over a contiguous range of lines.
15 > */
16 > export class SparseMultilineTokens {
17 >
18 > public static create(startLineNumber: number, tokens: Uint32Array): SparseMultilineTokens {
19 > return new SparseMultilineTokens(startLineNumber, new SparseMultilineTokensStorage(tokens));
20 > }
21 >
22 > private _startLineNumber: number;
23 > private _endLineNumber: number;
24 > private readonly _tokens: SparseMultilineTokensStorage;
25 >
26 > /**
27 > * (Inclusive) start line number for these tokens.
28 > */
29 > public get startLineNumber(): number {
30 > return this._startLineNumber; sparseMultilineTokens.ts ×2
31 > }
33 > /**
34 > * (Inclusive) end line number for these tokens.
35 > */
36 > public get endLineNumber(): number {
37 > return this._endLineNumber; sparseMultilineTokens.ts ×2
38 > }
40 > private constructor(startLineNumber: number, tokens: SparseMultilineTokensStorage) {
41 > this._startLineNumber = startLineNumber;
42 > this._tokens = tokens;
43 > this._endLineNumber = this._startLineNumber + this._tokens.getMaxDeltaLine();
44 > }
45 >
46 > public toString(): string {
47 > return this._tokens.toString(this._startLineNumber); semanticTokensProviderStyling.ts ×18
48 > }
50 > private _updateEndLineNumber(): void {
51 > this._endLineNumber = this._startLineNumber + this._tokens.getMaxDeltaLine(); sparseMultilineTokens.ts ×3
52 > }
54 > public isEmpty(): boolean {
55 > return this._tokens.isEmpty(); sparseMultilineTokens.ts ×3
56 > }
58 > public getLineTokens(lineNumber: number): SparseLineTokens | null {
59 > if (this._startLineNumber <= lineNumber && lineNumber <= this._endLineNumber) { sparseTokensStore.ts ×10
60 > return this._tokens.getLineTokens(lineNumber - this._startLineNumber);
61 > }
62 return null;
65 > public getRange(): Range | null {
66 > const deltaRange = this._tokens.getRange(); sparseMultilineTokens.ts ×4
67 > if (!deltaRange) {
68 return deltaRange;
69 }
70 > return new Range(this._startLineNumber + deltaRange.startLineNumber, deltaRange.startColumn, this._startLineNumber + deltaRange.endLineNumber, deltaRange.endColumn); sparseMultilineTokens.ts ×4
71 > }
73 > public removeTokens(range: Range): void {
74 > const startLineIndex = range.startLineNumber - this._startLineNumber; sparseTokensStore.ts ×6
75 > const endLineIndex = range.endLineNumber - this._startLineNumber;
76 >
77 > this._startLineNumber += this._tokens.removeTokens(startLineIndex, range.startColumn - 1, endLineIndex, range.endColumn - 1);
78 > this._updateEndLineNumber();
79 > }
81 > public split(range: Range): [SparseMultilineTokens, SparseMultilineTokens] {
82 > // split tokens to two: sparseMultilineTokens.ts ×3
83 > // a) all the tokens before `range`
84 > // b) all the tokens after `range`
85 > const startLineIndex = range.startLineNumber - this._startLineNumber;
86 > const endLineIndex = range.endLineNumber - this._startLineNumber;
87 >
88 > const [a, b, bDeltaLine] = this._tokens.split(startLineIndex, range.startColumn - 1, endLineIndex, range.endColumn - 1);
89 > return [new SparseMultilineTokens(this._startLineNumber, a), new SparseMultilineTokens(this._startLineNumber + bDeltaLine, b)];
90 > }
92 > public applyEdit(range: IRange, text: string): void {
93 const [eolCount, firstLineLength, lastLineLength] = countEOL(text);
94 this.acceptEdit(range, eolCount, firstLineLength, lastLineLength, text.length > 0 ? text.charCodeAt(0) : CharCode.Null);
95 }
97 > public acceptEdit(range: IRange, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {
98 > this._acceptDeleteRange(range); sparseMultilineTokens.ts ×6
99 > this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength, lastLineLength, firstCharCode);
100 > this._updateEndLineNumber();
101 > }
103 > private _acceptDeleteRange(range: IRange): void {
104 > if (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) { sparseMultilineTokens.ts ×6
105 > // Nothing to delete sparseMultilineTokens.ts ×11
106 > return;
107 > }
109 > const firstLineIndex = range.startLineNumber - this._startLineNumber;
110 > const lastLineIndex = range.endLineNumber - this._startLineNumber;
111 >
112 > if (lastLineIndex < 0) {
113 // this deletion occurs entirely before this block, so we only need to adjust line numbers
114 const deletedLinesCount = lastLineIndex - firstLineIndex;
115 this._startLineNumber -= deletedLinesCount;
116 return;
117 }
119 > const tokenMaxDeltaLine = this._tokens.getMaxDeltaLine();
120 >
121 > if (firstLineIndex >= tokenMaxDeltaLine + 1) {
122 // this deletion occurs entirely after this block, so there is nothing to do
123 return;
124 }
126 > if (firstLineIndex < 0 && lastLineIndex >= tokenMaxDeltaLine + 1) { sparseMultilineTokens.ts ×6
127 > // this deletion completely encompasses this block sparseMultilineTokens.ts ×2
128 > this._startLineNumber = 0;
129 > this._tokens.clear();
130 > return;
131 > }
133 > if (firstLineIndex < 0) {
134 > const deletedBefore = -firstLineIndex; sparseMultilineTokens.ts ×2
135 > this._startLineNumber -= deletedBefore;
136 >
137 > this._tokens.acceptDeleteRange(range.startColumn - 1, 0, 0, lastLineIndex, range.endColumn - 1);
139 > this._tokens.acceptDeleteRange(0, firstLineIndex, range.startColumn - 1, lastLineIndex, range.endColumn - 1); sparseMultilineTokens.ts ×2
140 > }
143 > private _acceptInsertText(position: Position, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {
145 > if (eolCount === 0 && firstLineLength === 0) {
146 > // Nothing to insert sparseMultilineTokens.ts ×4
147 > return;
148 > }
150 > const lineIndex = position.lineNumber - this._startLineNumber;
151 >
152 > if (lineIndex < 0) {
153 // this insertion occurs before this block, so we only need to adjust line numbers
154 this._startLineNumber += eolCount;
155 return;
156 }
158 > const tokenMaxDeltaLine = this._tokens.getMaxDeltaLine();
159 >
160 > if (lineIndex >= tokenMaxDeltaLine + 1) {
161 // this insertion occurs after this block, so there is nothing to do
162 return;
163 }
165 > this._tokens.acceptInsertText(lineIndex, position.column - 1, eolCount, firstLineLength, lastLineLength, firstCharCode);
168 > public reportIfInvalid(model: ITextModel): void {
169 > this._tokens.reportIfInvalid(model, this._startLineNumber); sparseMultilineTokens.ts ×5
170 > }
172 >
173 > class SparseMultilineTokensStorage {
174 > /**
175 > * The encoding of tokens is:
176 > * 4*i deltaLine (from `startLineNumber`)
177 > * 4*i+1 startCharacter (from the line start)
178 > * 4*i+2 endCharacter (from the line start)
179 > * 4*i+3 metadata
180 > */
181 > private readonly _tokens: Uint32Array;
182 > private _tokenCount: number;
183 >
184 > constructor(tokens: Uint32Array) {
185 > this._tokens = tokens;
186 > this._tokenCount = tokens.length / 4;
187 > }
188 >
189 > public toString(startLineNumber: number): string {
190 > const pieces: string[] = []; semanticTokensProviderStyling.ts ×18
191 > for (let i = 0; i < this._tokenCount; i++) {
192 > pieces.push(`(${this._getDeltaLine(i) + startLineNumber},${this._getStartCharacter(i)}-${this._getEndCharacter(i)})`);
193 > }
194 > return `[${pieces.join(',')}]`;
195 > }
197 > public getMaxDeltaLine(): number {
198 > const tokenCount = this._getTokenCount();
199 > if (tokenCount === 0) {
200 > return -1; sparseMultilineTokens.ts ×1
201 > }
202 > return this._getDeltaLine(tokenCount - 1); sparseMultilineTokens.ts ×33
203 > }
204 >
205 > public getRange(): Range | null {
206 > const tokenCount = this._getTokenCount(); sparseMultilineTokens.ts ×4
207 > if (tokenCount === 0) {
208 return null;
209 }
210 > const startChar = this._getStartCharacter(0); sparseMultilineTokens.ts ×4
211 > const maxDeltaLine = this._getDeltaLine(tokenCount - 1);
212 > const endChar = this._getEndCharacter(tokenCount - 1);
213 > return new Range(0, startChar + 1, maxDeltaLine, endChar + 1);
214 > }
216 > private _getTokenCount(): number {
217 > return this._tokenCount;
218 > }
219 >
220 > private _getDeltaLine(tokenIndex: number): number {
221 > return this._tokens[4 * tokenIndex];
222 > }
223 >
224 > private _getStartCharacter(tokenIndex: number): number {
225 > return this._tokens[4 * tokenIndex + 1]; sparseMultilineTokens.ts ×1
226 > }
228 > private _getEndCharacter(tokenIndex: number): number {
229 > return this._tokens[4 * tokenIndex + 2]; sparseMultilineTokens.ts ×1
230 > }
232 > public isEmpty(): boolean {
233 > return (this._getTokenCount() === 0); sparseMultilineTokens.ts ×3
234 > }
236 > public getLineTokens(deltaLine: number): SparseLineTokens | null {
237 > let low = 0; sparseTokensStore.ts ×10
238 > let high = this._getTokenCount() - 1;
239 >
240 > while (low < high) {
241 > const mid = low + Math.floor((high - low) / 2); sparseMultilineTokens.ts ×4
242 > const midDeltaLine = this._getDeltaLine(mid);
243 >
244 > if (midDeltaLine < deltaLine) {
245 > low = mid + 1; sparseMultilineTokens.ts ×1
246 > } else if (midDeltaLine > deltaLine) { sparseMultilineTokens.ts ×4
247 > high = mid - 1; sparseMultilineTokens.ts ×1
249 > let min = mid; sparseMultilineTokens.ts ×3
250 > while (min > low && this._getDeltaLine(min - 1) === deltaLine) {
252 > }
253 > let max = mid; sparseMultilineTokens.ts ×3
254 > while (max < high && this._getDeltaLine(max + 1) === deltaLine) {
256 > }
257 > return new SparseLineTokens(this._tokens.subarray(4 * min, 4 * max + 4)); sparseMultilineTokens.ts ×3
258 > }
261 > if (this._getDeltaLine(low) === deltaLine) {
262 > return new SparseLineTokens(this._tokens.subarray(4 * low, 4 * low + 4)); sparseMultilineTokens.ts ×1
263 > }
265 > return null;
268 > public clear(): void {
269 > this._tokenCount = 0; sparseMultilineTokens.ts ×2
270 > }
272 > public removeTokens(startDeltaLine: number, startChar: number, endDeltaLine: number, endChar: number): number {
273 > const tokens = this._tokens; sparseTokensStore.ts ×6
274 > const tokenCount = this._tokenCount;
275 > let newTokenCount = 0;
276 > let hasDeletedTokens = false;
277 > let firstDeltaLine = 0;
278 > for (let i = 0; i < tokenCount; i++) {
279 > const srcOffset = 4 * i;
280 > const tokenDeltaLine = tokens[srcOffset];
281 > const tokenStartCharacter = tokens[srcOffset + 1];
282 > const tokenEndCharacter = tokens[srcOffset + 2];
283 > const tokenMetadata = tokens[srcOffset + 3];
284 >
285 > if (
286 > (tokenDeltaLine > startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar))
287 > && (tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar))
288 > ) {
289 > hasDeletedTokens = true; sparseMultilineTokens.ts ×1
290 > } else { sparseTokensStore.ts ×6
291 > if (newTokenCount === 0) { sparseMultilineTokens.ts ×3
292 > firstDeltaLine = tokenDeltaLine;
293 > }
294 > if (hasDeletedTokens) {
295 > // must move the token to the left sparseMultilineTokens.ts ×1
296 > const destOffset = 4 * newTokenCount;
297 > tokens[destOffset] = tokenDeltaLine - firstDeltaLine;
298 > tokens[destOffset + 1] = tokenStartCharacter;
299 > tokens[destOffset + 2] = tokenEndCharacter;
300 > tokens[destOffset + 3] = tokenMetadata;
301 > } else if (firstDeltaLine !== 0) { sparseMultilineTokens.ts ×3
302 > // must adjust the delta line in place sparseMultilineTokens.ts ×1
303 > tokens[srcOffset] = tokenDeltaLine - firstDeltaLine;
304 > }
305 > newTokenCount++; sparseMultilineTokens.ts ×3
306 > }
308 >
309 > this._tokenCount = newTokenCount;
310 >
311 > return firstDeltaLine;
312 > }
314 > public split(startDeltaLine: number, startChar: number, endDeltaLine: number, endChar: number): [SparseMultilineTokensStorage, SparseMultilineTokensStorage, number] {
315 > const tokens = this._tokens; sparseMultilineTokens.ts ×3
316 > const tokenCount = this._tokenCount;
317 > const aTokens: number[] = [];
318 > const bTokens: number[] = [];
319 > let destTokens: number[] = aTokens;
320 > let destOffset = 0;
321 > let destFirstDeltaLine: number = 0;
322 > for (let i = 0; i < tokenCount; i++) {
323 > const srcOffset = 4 * i;
324 > const tokenDeltaLine = tokens[srcOffset];
325 > const tokenStartCharacter = tokens[srcOffset + 1];
326 > const tokenEndCharacter = tokens[srcOffset + 2];
327 > const tokenMetadata = tokens[srcOffset + 3];
328 >
329 > if ((tokenDeltaLine > startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar))) {
330 > if ((tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar))) {
331 // this token is touching the range
332 continue;
334 > // this token is after the range
335 > if (destTokens !== bTokens) {
336 > // this token is the first token after the range
337 > destTokens = bTokens;
338 > destOffset = 0;
339 > destFirstDeltaLine = tokenDeltaLine;
340 > }
341 > }
342 > }
343 >
344 > destTokens[destOffset++] = tokenDeltaLine - destFirstDeltaLine;
345 > destTokens[destOffset++] = tokenStartCharacter;
346 > destTokens[destOffset++] = tokenEndCharacter;
347 > destTokens[destOffset++] = tokenMetadata;
348 > }
349 >
350 > return [new SparseMultilineTokensStorage(new Uint32Array(aTokens)), new SparseMultilineTokensStorage(new Uint32Array(bTokens)), destFirstDeltaLine];
351 > }
353 > public acceptDeleteRange(horizontalShiftForFirstLineTokens: number, startDeltaLine: number, startCharacter: number, endDeltaLine: number, endCharacter: number): void {
354 > // This is a bit complex, here are the cases I used to think about this: sparseMultilineTokens.ts ×9
355 > //
356 > // 1. The token starts before the deletion range
357 > // 1a. The token is completely before the deletion range
358 > // -----------
359 > // xxxxxxxxxxx
360 > // 1b. The token starts before, the deletion range ends after the token
361 > // -----------
362 > // xxxxxxxxxxx
363 > // 1c. The token starts before, the deletion range ends precisely with the token
364 > // ---------------
365 > // xxxxxxxx
366 > // 1d. The token starts before, the deletion range is inside the token
367 > // ---------------
368 > // xxxxx
369 > //
370 > // 2. The token starts at the same position with the deletion range
371 > // 2a. The token starts at the same position, and ends inside the deletion range
372 > // -------
373 > // xxxxxxxxxxx
374 > // 2b. The token starts at the same position, and ends at the same position as the deletion range
375 > // ----------
376 > // xxxxxxxxxx
377 > // 2c. The token starts at the same position, and ends after the deletion range
378 > // -------------
379 > // xxxxxxx
380 > //
381 > // 3. The token starts inside the deletion range
382 > // 3a. The token is inside the deletion range
383 > // -------
384 > // xxxxxxxxxxxxx
385 > // 3b. The token starts inside the deletion range, and ends at the same position as the deletion range
386 > // ----------
387 > // xxxxxxxxxxxxx
388 > // 3c. The token starts inside the deletion range, and ends after the deletion range
389 > // ------------
390 > // xxxxxxxxxxx
391 > //
392 > // 4. The token starts after the deletion range
393 > // -----------
394 > // xxxxxxxx
395 > //
396 > const tokens = this._tokens;
397 > const tokenCount = this._tokenCount;
398 > const deletedLineCount = (endDeltaLine - startDeltaLine);
399 > let newTokenCount = 0;
400 > let hasDeletedTokens = false;
401 > for (let i = 0; i < tokenCount; i++) {
402 > const srcOffset = 4 * i;
403 > let tokenDeltaLine = tokens[srcOffset];
404 > let tokenStartCharacter = tokens[srcOffset + 1];
405 > let tokenEndCharacter = tokens[srcOffset + 2];
406 > const tokenMetadata = tokens[srcOffset + 3];
407 >
408 > if (tokenDeltaLine < startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter <= startCharacter)) {
409 > // 1a. The token is completely before the deletion range sparseMultilineTokens.ts ×2
410 > // => nothing to do
411 > newTokenCount++;
412 > continue;
413 > } else if (tokenDeltaLine === startDeltaLine && tokenStartCharacter < startCharacter) { sparseMultilineTokens.ts ×9
414 > // 1b, 1c, 1d sparseMultilineTokens.ts ×10
415 > // => the token survives, but it needs to shrink
416 > if (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {
417 > // 1d. The token starts before, the deletion range is inside the token
418 > // => the token shrinks by the deletion character count
419 > tokenEndCharacter -= (endCharacter - startCharacter);
420 > } else {
421 > // 1b. The token starts before, the deletion range ends after the token
422 > // 1c. The token starts before, the deletion range ends precisely with the token
423 > // => the token shrinks its ending to the deletion start
424 > tokenEndCharacter = startCharacter;
425 > }
426 > } else if (tokenDeltaLine === startDeltaLine && tokenStartCharacter === startCharacter) { sparseMultilineTokens.ts ×9
427 // 2a, 2b, 2c
428 if (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {
429 // 2c. The token starts at the same position, and ends after the deletion range
430 // => the token shrinks by the deletion character count
431 tokenEndCharacter -= (endCharacter - startCharacter);
432 } else {
433 // 2a. The token starts at the same position, and ends inside the deletion range
434 // 2b. The token starts at the same position, and ends at the same position as the deletion range
435 // => the token is deleted
436 hasDeletedTokens = true;
437 continue;
438 }
439 > } else if (tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter < endCharacter)) { sparseMultilineTokens.ts ×9
440 > // 3a, 3b, 3c sparseMultilineTokens.ts ×10
441 > if (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {
442 > // 3c. The token starts inside the deletion range, and ends after the deletion range
443 > // => the token moves to continue right after the deletion
444 > tokenDeltaLine = startDeltaLine;
445 > tokenStartCharacter = startCharacter;
446 > tokenEndCharacter = tokenStartCharacter + (tokenEndCharacter - endCharacter);
447 > } else {
448 > // 3a. The token is inside the deletion range
449 > // 3b. The token starts inside the deletion range, and ends at the same position as the deletion range
450 > // => the token is deleted
451 > hasDeletedTokens = true;
452 > continue;
453 > }
454 > } else if (tokenDeltaLine > endDeltaLine) { sparseMultilineTokens.ts ×9
455 > // 4. (partial) The token starts after the deletion range, on a line below... sparseMultilineTokens.ts ×10
456 > if (deletedLineCount === 0 && !hasDeletedTokens) {
457 // early stop, there is no need to walk all the tokens and do nothing...
458 newTokenCount = tokenCount;
459 break;
460 }
461 > tokenDeltaLine -= deletedLineCount; sparseMultilineTokens.ts ×10
462 > } else if (tokenDeltaLine === endDeltaLine && tokenStartCharacter >= endCharacter) { sparseMultilineTokens.ts ×9
463 > // 4. (continued) The token starts after the deletion range, on the last line where a deletion occurs sparseMultilineTokens.ts ×2
464 > if (horizontalShiftForFirstLineTokens && tokenDeltaLine === 0) {
465 > tokenStartCharacter += horizontalShiftForFirstLineTokens; sparseMultilineTokens.ts ×2
466 > tokenEndCharacter += horizontalShiftForFirstLineTokens;
467 > }
468 > tokenDeltaLine -= deletedLineCount; sparseMultilineTokens.ts ×2
469 > tokenStartCharacter -= (endCharacter - startCharacter);
470 > tokenEndCharacter -= (endCharacter - startCharacter);
471 > } else {
472 throw new Error(`Not possible!`);
473 }
475 > const destOffset = 4 * newTokenCount;
476 > tokens[destOffset] = tokenDeltaLine;
477 > tokens[destOffset + 1] = tokenStartCharacter;
478 > tokens[destOffset + 2] = tokenEndCharacter;
479 > tokens[destOffset + 3] = tokenMetadata;
480 > newTokenCount++;
481 > }
482 >
483 > this._tokenCount = newTokenCount;
484 > }
486 > public acceptInsertText(deltaLine: number, character: number, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {
487 > // Here are the cases I used to think about this: sparseMultilineTokens.ts ×11
488 > //
489 > // 1. The token is completely before the insertion point
490 > // ----------- |
491 > // 2. The token ends precisely at the insertion point
492 > // -----------|
493 > // 3. The token contains the insertion point
494 > // -----|------
495 > // 4. The token starts precisely at the insertion point
496 > // |-----------
497 > // 5. The token is completely after the insertion point
498 > // | -----------
499 > //
500 > const isInsertingPreciselyOneWordCharacter = (
501 > eolCount === 0
502 > && firstLineLength === 1 sparseMultilineTokens.ts ×10
503 && (
504 (firstCharCode >= CharCode.Digit0 && firstCharCode <= CharCode.Digit9)
505 || (firstCharCode >= CharCode.A && firstCharCode <= CharCode.Z)
506 || (firstCharCode >= CharCode.a && firstCharCode <= CharCode.z)
508 > );
509 > const tokens = this._tokens;
510 > const tokenCount = this._tokenCount;
511 > for (let i = 0; i < tokenCount; i++) {
512 > const offset = 4 * i;
513 > let tokenDeltaLine = tokens[offset];
514 > let tokenStartCharacter = tokens[offset + 1];
515 > let tokenEndCharacter = tokens[offset + 2];
516 >
517 > if (tokenDeltaLine < deltaLine || (tokenDeltaLine === deltaLine && tokenEndCharacter < character)) {
518 > // 1. The token is completely before the insertion point
519 > // => nothing to do
520 > continue;
521 > } else if (tokenDeltaLine === deltaLine && tokenEndCharacter === character) {
522 // 2. The token ends precisely at the insertion point
523 // => expand the end character only if inserting precisely one character that is a word character
524 if (isInsertingPreciselyOneWordCharacter) {
525 tokenEndCharacter += 1;
526 } else {
527 continue;
528 }
529 > } else if (tokenDeltaLine === deltaLine && tokenStartCharacter < character && character < tokenEndCharacter) { sparseMultilineTokens.ts ×11
530 > // 3. The token contains the insertion point sparseMultilineTokens.ts ×10
531 > if (eolCount === 0) {
532 > // => just expand the end character
533 > tokenEndCharacter += firstLineLength;
534 > } else {
535 > // => cut off the token
536 > tokenEndCharacter = character;
537 > }
539 > // 4. or 5.
540 > if (tokenDeltaLine === deltaLine && tokenStartCharacter === character) {
541 > // 4. The token starts precisely at the insertion point sparseMultilineTokens.ts ×10
542 > // => grow the token (by keeping its start constant) only if inserting precisely one character that is a word character
543 > // => otherwise behave as in case 5.
544 > if (isInsertingPreciselyOneWordCharacter) {
545 continue;
546 }
548 > // => the token must move and keep its size constant sparseMultilineTokens.ts ×11
549 > if (tokenDeltaLine === deltaLine) {
550 > tokenDeltaLine += eolCount;
551 > // this token is on the line where the insertion is taking place
552 > if (eolCount === 0) {
553 tokenStartCharacter += firstLineLength;
554 tokenEndCharacter += firstLineLength;
556 > const tokenLength = tokenEndCharacter - tokenStartCharacter;
557 > tokenStartCharacter = lastLineLength + (tokenStartCharacter - character);
558 > tokenEndCharacter = tokenStartCharacter + tokenLength;
559 > }
560 > } else {
561 > tokenDeltaLine += eolCount; sparseMultilineTokens.ts ×10
562 > }
564 >
565 > tokens[offset] = tokenDeltaLine;
566 > tokens[offset + 1] = tokenStartCharacter;
567 > tokens[offset + 2] = tokenEndCharacter;
568 > }
569 > }
571 > private static _rateLimiter = new RateLimiter(10 / 60); // limit to 10 times per minute
572 >
573 > public reportIfInvalid(model: ITextModel, startLineNumber: number): void {
574 > for (let i = 0; i < this._tokenCount; i++) { sparseMultilineTokens.ts ×5
575 > const lineNumber = this._getDeltaLine(i) + startLineNumber;
576 >
577 > if (lineNumber < 1) {
578 SparseMultilineTokensStorage._rateLimiter.runIfNotLimited(() => {
579 console.error('Invalid Semantic Tokens Data From Extension: lineNumber < 1');
580 });
581 > } else if (lineNumber > model.getLineCount()) { sparseMultilineTokens.ts ×5
582 SparseMultilineTokensStorage._rateLimiter.runIfNotLimited(() => {
583 console.error('Invalid Semantic Tokens Data From Extension: lineNumber > model.getLineCount()');
584 });
585 > } else if (this._getEndCharacter(i) > model.getLineLength(lineNumber)) { sparseMultilineTokens.ts ×5
586 SparseMultilineTokensStorage._rateLimiter.runIfNotLimited(() => {
587 console.error('Invalid Semantic Tokens Data From Extension: end character > model.getLineLength(lineNumber)');
588 });
589 }
591 > }
593 >
594 > export class SparseLineTokens {
595 >
596 > private readonly _tokens: Uint32Array;
597 >
598 > constructor(tokens: Uint32Array) {
599 > this._tokens = tokens; sparseTokensStore.ts ×10
600 > }
602 > public getCount(): number {
603 > return this._tokens.length / 4; sparseTokensStore.ts ×10
604 > }
606 > public getStartCharacter(tokenIndex: number): number {
607 > return this._tokens[4 * tokenIndex + 1]; sparseTokensStore.ts ×10
608 > }
610 > public getEndCharacter(tokenIndex: number): number {
611 > return this._tokens[4 * tokenIndex + 2]; sparseTokensStore.ts ×10
612 > }
614 > public getMetadata(tokenIndex: number): number {
615 > return this._tokens[4 * tokenIndex + 3]; sparseTokensStore.ts ×10
616 > }