diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 56ec349bd71..d1abdbfb679 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -746,6 +746,10 @@ export class SemanticColoringAdapter { for (let i = 0, len = oldAreas.length; i < len; i++) { const oldAreaData = oldAreas[i]; const oldAreaTokenCount = (oldAreaData.length / 5) | 0; + if (oldAreaTokenCount === 0) { + // skip old empty areas + continue; + } if (newTokenEndIndex - newTokenStartIndex < oldAreaTokenCount) { // there are too many old tokens, this cannot work break; @@ -772,6 +776,10 @@ export class SemanticColoringAdapter { for (let i = oldAreas.length - 1; i >= 0; i--) { const oldAreaData = oldAreas[i]; const oldAreaTokenCount = (oldAreaData.length / 5) | 0; + if (oldAreaTokenCount === 0) { + // skip old empty areas + continue; + } if (newTokenEndIndex - newTokenStartIndex < oldAreaTokenCount) { // there are too many old tokens, this cannot work break; diff --git a/src/vs/workbench/test/electron-browser/api/semanticTokens.test.ts b/src/vs/workbench/test/electron-browser/api/semanticTokens.test.ts index a7e12e704e6..238127ce61f 100644 --- a/src/vs/workbench/test/electron-browser/api/semanticTokens.test.ts +++ b/src/vs/workbench/test/electron-browser/api/semanticTokens.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import * as types from 'vs/workbench/api/common/extHostTypes'; -import { TestRPCProtocol } from './testRPCProtocol'; +import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol'; import { SemanticColoringAdapter } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; @@ -305,4 +305,39 @@ suite('SemanticColoringAdapter', () => { ]); adapter.releaseSemanticColoring(result1.id); }); + + test('going from empty to 1 semantic token', async () => { + doc.onEvents({ + versionId: 2, + eol: '\n', + changes: [{ + range: { startLineNumber: 1, startColumn: 1, endLineNumber: 23, endColumn: 18 }, + rangeOffset: 0, + rangeLength: 0, + text: '' + }] + }); + + const result1 = decodeSemanticTokensDto((await adapter.provideSemanticColoring(resource, 0, CancellationToken.None))!); + assertDTO(result1, [ + { type: 'full', line: 1, tokens: [] }, + ]); + + doc.onEvents({ + versionId: 3, + eol: '\n', + changes: [{ + range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, + rangeOffset: 0, + rangeLength: 0, + text: 'const enum E01 {}\n' + }] + }); + + const result2 = decodeSemanticTokensDto((await adapter.provideSemanticColoring(resource, result1.id, CancellationToken.None))!); + assertDTO(result2, [ + { type: 'full', line: 1, tokens: [0] } + ]); + adapter.releaseSemanticColoring(result1.id); + }); });