Skip to content

Commit 83770f6

Browse files
committed
Fixes microsoft#136540: Do not eat up error or fall back to the next provider in case an error is thrown
1 parent d791072 commit 83770f6

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

src/vs/editor/common/services/getSemanticTokens.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export class DocumentSemanticTokensResult {
2727
constructor(
2828
public readonly provider: DocumentSemanticTokensProvider,
2929
public readonly tokens: SemanticTokens | SemanticTokensEdits | null,
30+
public readonly error: any
3031
) { }
3132
}
3233

@@ -45,22 +46,27 @@ export async function getDocumentSemanticTokens(model: ITextModel, lastProvider:
4546
// Get tokens from all providers at the same time.
4647
const results = await Promise.all(providers.map(async (provider) => {
4748
let result: SemanticTokens | SemanticTokensEdits | null | undefined;
49+
let error: any = null;
4850
try {
4951
result = await provider.provideDocumentSemanticTokens(model, (provider === lastProvider ? lastResultId : null), token);
5052
} catch (err) {
51-
onUnexpectedExternalError(err);
53+
error = err;
5254
result = null;
5355
}
5456

5557
if (!result || (!isSemanticTokens(result) && !isSemanticTokensEdits(result))) {
5658
result = null;
5759
}
5860

59-
return new DocumentSemanticTokensResult(provider, result);
61+
return new DocumentSemanticTokensResult(provider, result, error);
6062
}));
6163

62-
// Try to return the first result with actual tokens
64+
// Try to return the first result with actual tokens or
65+
// the first result which threw an error (!!)
6366
for (const result of results) {
67+
if (result.error) {
68+
throw result.error;
69+
}
6470
if (result.tokens) {
6571
return result;
6672
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*---------------------------------------------------------------------------------------------
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 * as assert from 'assert';
7+
import { CancellationToken } from 'vs/base/common/cancellation';
8+
import { canceled } from 'vs/base/common/errors';
9+
import { DisposableStore } from 'vs/base/common/lifecycle';
10+
import { ITextModel } from 'vs/editor/common/model';
11+
import { DocumentSemanticTokensProvider, DocumentSemanticTokensProviderRegistry, ProviderResult, SemanticTokens, SemanticTokensEdits, SemanticTokensLegend } from 'vs/editor/common/modes';
12+
import { getDocumentSemanticTokens } from 'vs/editor/common/services/getSemanticTokens';
13+
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
14+
15+
suite('getSemanticTokens', () => {
16+
17+
test('issue #136540: semantic highlighting flickers', async () => {
18+
const disposables = new DisposableStore();
19+
20+
const provider = new class implements DocumentSemanticTokensProvider {
21+
getLegend(): SemanticTokensLegend {
22+
return { tokenTypes: ['test'], tokenModifiers: [] };
23+
}
24+
provideDocumentSemanticTokens(model: ITextModel, lastResultId: string | null, token: CancellationToken): ProviderResult<SemanticTokens | SemanticTokensEdits> {
25+
throw canceled();
26+
}
27+
releaseDocumentSemanticTokens(resultId: string | undefined): void {
28+
}
29+
};
30+
31+
disposables.add(DocumentSemanticTokensProviderRegistry.register('testLang', provider));
32+
33+
const textModel = disposables.add(createTextModel('example', undefined, 'testLang'));
34+
35+
await getDocumentSemanticTokens(textModel, null, null, CancellationToken.None).then((res) => {
36+
assert.fail();
37+
}, (err) => {
38+
assert.ok(!!err);
39+
});
40+
41+
disposables.dispose();
42+
});
43+
44+
});

0 commit comments

Comments
 (0)