Path: blob/main/src/vs/workbench/api/test/browser/extHostLanguageFeatures.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { TestInstantiationService } from '../../../../platform/instantiation/test/common/instantiationServiceMock.js';7import { setUnexpectedErrorHandler, errorHandler } from '../../../../base/common/errors.js';8import { URI } from '../../../../base/common/uri.js';9import * as types from '../../common/extHostTypes.js';10import { createTextModel } from '../../../../editor/test/common/testTextModel.js';11import { Position as EditorPosition, Position } from '../../../../editor/common/core/position.js';12import { Range as EditorRange } from '../../../../editor/common/core/range.js';13import { TestRPCProtocol } from '../common/testRPCProtocol.js';14import { IMarkerService } from '../../../../platform/markers/common/markers.js';15import { MarkerService } from '../../../../platform/markers/common/markerService.js';16import { ExtHostLanguageFeatures } from '../../common/extHostLanguageFeatures.js';17import { MainThreadLanguageFeatures } from '../../browser/mainThreadLanguageFeatures.js';18import { ExtHostCommands } from '../../common/extHostCommands.js';19import { MainThreadCommands } from '../../browser/mainThreadCommands.js';20import { ExtHostDocuments } from '../../common/extHostDocuments.js';21import { ExtHostDocumentsAndEditors } from '../../common/extHostDocumentsAndEditors.js';22import * as languages from '../../../../editor/common/languages.js';23import { getCodeLensModel } from '../../../../editor/contrib/codelens/browser/codelens.js';24import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition, getReferencesAtPosition } from '../../../../editor/contrib/gotoSymbol/browser/goToSymbol.js';25import { getHoversPromise } from '../../../../editor/contrib/hover/browser/getHover.js';26import { getOccurrencesAtPosition } from '../../../../editor/contrib/wordHighlighter/browser/wordHighlighter.js';27import { getCodeActions } from '../../../../editor/contrib/codeAction/browser/codeAction.js';28import { getWorkspaceSymbols } from '../../../contrib/search/common/search.js';29import { rename } from '../../../../editor/contrib/rename/browser/rename.js';30import { provideSignatureHelp } from '../../../../editor/contrib/parameterHints/browser/provideSignatureHelp.js';31import { provideSuggestionItems, CompletionOptions } from '../../../../editor/contrib/suggest/browser/suggest.js';32import { getDocumentFormattingEditsUntilResult, getDocumentRangeFormattingEditsUntilResult, getOnTypeFormattingEdits } from '../../../../editor/contrib/format/browser/format.js';33import { getLinks } from '../../../../editor/contrib/links/browser/getLinks.js';34import { MainContext, ExtHostContext } from '../../common/extHost.protocol.js';35import { ExtHostDiagnostics } from '../../common/extHostDiagnostics.js';36import type * as vscode from 'vscode';37import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';38import { NullLogService } from '../../../../platform/log/common/log.js';39import { ITextModel, EndOfLineSequence } from '../../../../editor/common/model.js';40import { getColors } from '../../../../editor/contrib/colorPicker/browser/color.js';41import { CancellationToken } from '../../../../base/common/cancellation.js';42import { nullExtensionDescription as defaultExtension } from '../../../services/extensions/common/extensions.js';43import { provideSelectionRanges } from '../../../../editor/contrib/smartSelect/browser/smartSelect.js';44import { mock } from '../../../../base/test/common/mock.js';45import { IEditorWorkerService } from '../../../../editor/common/services/editorWorker.js';46import { DisposableStore } from '../../../../base/common/lifecycle.js';47import { NullApiDeprecationService } from '../../common/extHostApiDeprecationService.js';48import { Progress } from '../../../../platform/progress/common/progress.js';49import { IExtHostFileSystemInfo } from '../../common/extHostFileSystemInfo.js';50import { URITransformerService } from '../../common/extHostUriTransformerService.js';51import { OutlineModel } from '../../../../editor/contrib/documentSymbols/browser/outlineModel.js';52import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';53import { LanguageFeaturesService } from '../../../../editor/common/services/languageFeaturesService.js';54import { CodeActionTriggerSource } from '../../../../editor/contrib/codeAction/common/types.js';55import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';56import { IExtHostTelemetry } from '../../common/extHostTelemetry.js';57import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';58import { runWithFakedTimers } from '../../../../base/test/common/timeTravelScheduler.js';5960suite('ExtHostLanguageFeatures', function () {6162const defaultSelector = { scheme: 'far' };63let model: ITextModel;64let extHost: ExtHostLanguageFeatures;65let mainThread: MainThreadLanguageFeatures;66const disposables = new DisposableStore();67let rpcProtocol: TestRPCProtocol;68let languageFeaturesService: ILanguageFeaturesService;69let originalErrorHandler: (e: any) => any;70let instantiationService: TestInstantiationService;7172setup(() => {7374model = createTextModel(75[76'This is the first line',77'This is the second line',78'This is the third line',79].join('\n'),80undefined,81undefined,82URI.parse('far://testing/file.a'));8384rpcProtocol = new TestRPCProtocol();8586languageFeaturesService = new LanguageFeaturesService();8788// Use IInstantiationService to get typechecking when instantiating89let inst: IInstantiationService;90{91instantiationService = new TestInstantiationService();92instantiationService.stub(IMarkerService, MarkerService);93instantiationService.set(ILanguageFeaturesService, languageFeaturesService);94instantiationService.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {95override asCanonicalUri(uri: URI): URI {96return uri;97}98});99inst = instantiationService;100}101102originalErrorHandler = errorHandler.getUnexpectedErrorHandler();103setUnexpectedErrorHandler(() => { });104105const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());106extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({107addedDocuments: [{108isDirty: false,109versionId: model.getVersionId(),110languageId: model.getLanguageId(),111uri: model.uri,112lines: model.getValue().split(model.getEOL()),113EOL: model.getEOL(),114encoding: 'utf8'115}]116});117const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);118rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments);119120const commands = new ExtHostCommands(rpcProtocol, new NullLogService(), new class extends mock<IExtHostTelemetry>() {121override onExtensionError(): boolean {122return true;123}124});125rpcProtocol.set(ExtHostContext.ExtHostCommands, commands);126rpcProtocol.set(MainContext.MainThreadCommands, disposables.add(inst.createInstance(MainThreadCommands, rpcProtocol)));127128const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService(), new class extends mock<IExtHostFileSystemInfo>() { }, extHostDocumentsAndEditors);129rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics);130131extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService, new class extends mock<IExtHostTelemetry>() {132override onExtensionError(): boolean {133return true;134}135});136rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost);137138mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, disposables.add(inst.createInstance(MainThreadLanguageFeatures, rpcProtocol)));139});140141teardown(() => {142disposables.clear();143144setUnexpectedErrorHandler(originalErrorHandler);145model.dispose();146mainThread.dispose();147instantiationService.dispose();148149return rpcProtocol.sync();150});151152ensureNoDisposablesAreLeakedInTestSuite();153154// --- outline155156test('DocumentSymbols, register/deregister', async () => {157assert.strictEqual(languageFeaturesService.documentSymbolProvider.all(model).length, 0);158const d1 = extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentSymbolProvider {159provideDocumentSymbols() {160return <vscode.SymbolInformation[]>[];161}162});163164await rpcProtocol.sync();165assert.strictEqual(languageFeaturesService.documentSymbolProvider.all(model).length, 1);166d1.dispose();167return rpcProtocol.sync();168169});170171test('DocumentSymbols, evil provider', async () => {172disposables.add(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentSymbolProvider {173provideDocumentSymbols(): any {174throw new Error('evil document symbol provider');175}176}));177disposables.add(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentSymbolProvider {178provideDocumentSymbols(): any {179return [new types.SymbolInformation('test', types.SymbolKind.Field, new types.Range(0, 0, 0, 0))];180}181}));182183await rpcProtocol.sync();184const value = (await OutlineModel.create(languageFeaturesService.documentSymbolProvider, model, CancellationToken.None)).asListOfDocumentSymbols();185assert.strictEqual(value.length, 1);186});187188test('DocumentSymbols, data conversion', async () => {189disposables.add(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentSymbolProvider {190provideDocumentSymbols(): any {191return [new types.SymbolInformation('test', types.SymbolKind.Field, new types.Range(0, 0, 0, 0))];192}193}));194195await rpcProtocol.sync();196const value = (await OutlineModel.create(languageFeaturesService.documentSymbolProvider, model, CancellationToken.None)).asListOfDocumentSymbols();197assert.strictEqual(value.length, 1);198const entry = value[0];199assert.strictEqual(entry.name, 'test');200assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });201});202203test('Quick Outline uses a not ideal sorting, #138502', async function () {204const symbols = [205{ name: 'containers', range: { startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 26 } },206{ name: 'container 0', range: { startLineNumber: 2, startColumn: 5, endLineNumber: 5, endColumn: 1 } },207{ name: 'name', range: { startLineNumber: 2, startColumn: 5, endLineNumber: 2, endColumn: 16 } },208{ name: 'ports', range: { startLineNumber: 3, startColumn: 5, endLineNumber: 5, endColumn: 1 } },209{ name: 'ports 0', range: { startLineNumber: 4, startColumn: 9, endLineNumber: 4, endColumn: 26 } },210{ name: 'containerPort', range: { startLineNumber: 4, startColumn: 9, endLineNumber: 4, endColumn: 26 } }211];212213disposables.add(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, {214provideDocumentSymbols: (doc, token): any => {215return symbols.map(s => {216return new types.SymbolInformation(217s.name,218types.SymbolKind.Object,219new types.Range(s.range.startLineNumber - 1, s.range.startColumn - 1, s.range.endLineNumber - 1, s.range.endColumn - 1)220);221});222}223}));224225await rpcProtocol.sync();226227const value = (await OutlineModel.create(languageFeaturesService.documentSymbolProvider, model, CancellationToken.None)).asListOfDocumentSymbols();228229assert.strictEqual(value.length, 6);230assert.deepStrictEqual(value.map(s => s.name), ['containers', 'container 0', 'name', 'ports', 'ports 0', 'containerPort']);231});232233// --- code lens234235test('CodeLens, evil provider', async () => {236return runWithFakedTimers({ useFakeTimers: true }, async () => {237disposables.add(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, new class implements vscode.CodeLensProvider {238provideCodeLenses(): any {239throw new Error('evil');240}241}));242disposables.add(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, new class implements vscode.CodeLensProvider {243provideCodeLenses() {244return [new types.CodeLens(new types.Range(0, 0, 0, 0))];245}246}));247248await rpcProtocol.sync();249const value = await getCodeLensModel(languageFeaturesService.codeLensProvider, model, CancellationToken.None);250assert.strictEqual(value.lenses.length, 1);251value.dispose();252});253});254255test('CodeLens, do not resolve a resolved lens', async () => {256return runWithFakedTimers({ useFakeTimers: true }, async () => {257disposables.add(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, new class implements vscode.CodeLensProvider {258provideCodeLenses(): any {259return [new types.CodeLens(260new types.Range(0, 0, 0, 0),261{ command: 'id', title: 'Title' })];262}263resolveCodeLens(): any {264assert.ok(false, 'do not resolve');265}266}));267268await rpcProtocol.sync();269const value = await getCodeLensModel(languageFeaturesService.codeLensProvider, model, CancellationToken.None);270assert.strictEqual(value.lenses.length, 1);271const [data] = value.lenses;272const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None));273assert.strictEqual(symbol!.command!.id, 'id');274assert.strictEqual(symbol!.command!.title, 'Title');275value.dispose();276});277});278279test('CodeLens, missing command', async () => {280return runWithFakedTimers({ useFakeTimers: true }, async () => {281disposables.add(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, new class implements vscode.CodeLensProvider {282provideCodeLenses() {283return [new types.CodeLens(new types.Range(0, 0, 0, 0))];284}285}));286287await rpcProtocol.sync();288const value = await getCodeLensModel(languageFeaturesService.codeLensProvider, model, CancellationToken.None);289assert.strictEqual(value.lenses.length, 1);290const [data] = value.lenses;291const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None));292assert.strictEqual(symbol, undefined);293value.dispose();294});295});296297// --- definition298299test('Definition, data conversion', async () => {300301disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {302provideDefinition(): any {303return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];304}305}));306307await rpcProtocol.sync();308const value = await getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);309assert.strictEqual(value.length, 1);310const [entry] = value;311assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });312assert.strictEqual(entry.uri.toString(), model.uri.toString());313});314315test('Definition, one or many', async () => {316317disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {318provideDefinition(): any {319return [new types.Location(model.uri, new types.Range(1, 1, 1, 1))];320}321}));322disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {323provideDefinition(): any {324return new types.Location(model.uri, new types.Range(2, 1, 1, 1));325}326}));327328await rpcProtocol.sync();329const value = await getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);330assert.strictEqual(value.length, 2);331});332333test('Definition, registration order', async () => {334335disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {336provideDefinition(): any {337return [new types.Location(URI.parse('far://first'), new types.Range(2, 3, 4, 5))];338}339}));340341disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {342provideDefinition(): any {343return new types.Location(URI.parse('far://second'), new types.Range(1, 2, 3, 4));344}345}));346347await rpcProtocol.sync();348const value = await getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);349assert.strictEqual(value.length, 2);350// let [first, second] = value;351assert.strictEqual(value[0].uri.authority, 'second');352assert.strictEqual(value[1].uri.authority, 'first');353});354355test('Definition, evil provider', async () => {356357disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {358provideDefinition(): any {359throw new Error('evil provider');360}361}));362disposables.add(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.DefinitionProvider {363provideDefinition(): any {364return new types.Location(model.uri, new types.Range(1, 1, 1, 1));365}366}));367368await rpcProtocol.sync();369const value = await getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);370assert.strictEqual(value.length, 1);371});372373// -- declaration374375test('Declaration, data conversion', async () => {376377disposables.add(extHost.registerDeclarationProvider(defaultExtension, defaultSelector, new class implements vscode.DeclarationProvider {378provideDeclaration(): any {379return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];380}381}));382383await rpcProtocol.sync();384const value = await getDeclarationsAtPosition(languageFeaturesService.declarationProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);385assert.strictEqual(value.length, 1);386const [entry] = value;387assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });388assert.strictEqual(entry.uri.toString(), model.uri.toString());389});390391// --- implementation392393test('Implementation, data conversion', async () => {394395disposables.add(extHost.registerImplementationProvider(defaultExtension, defaultSelector, new class implements vscode.ImplementationProvider {396provideImplementation(): any {397return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];398}399}));400401await rpcProtocol.sync();402const value = await getImplementationsAtPosition(languageFeaturesService.implementationProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);403assert.strictEqual(value.length, 1);404const [entry] = value;405assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });406assert.strictEqual(entry.uri.toString(), model.uri.toString());407});408409// --- type definition410411test('Type Definition, data conversion', async () => {412413disposables.add(extHost.registerTypeDefinitionProvider(defaultExtension, defaultSelector, new class implements vscode.TypeDefinitionProvider {414provideTypeDefinition(): any {415return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];416}417}));418419await rpcProtocol.sync();420const value = await getTypeDefinitionsAtPosition(languageFeaturesService.typeDefinitionProvider, model, new EditorPosition(1, 1), false, CancellationToken.None);421assert.strictEqual(value.length, 1);422const [entry] = value;423assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });424assert.strictEqual(entry.uri.toString(), model.uri.toString());425});426427// --- extra info428429test('HoverProvider, word range at pos', async () => {430431disposables.add(extHost.registerHoverProvider(defaultExtension, defaultSelector, new class implements vscode.HoverProvider {432provideHover(): any {433return new types.Hover('Hello');434}435}));436437await rpcProtocol.sync();438const hovers = await getHoversPromise(languageFeaturesService.hoverProvider, model, new EditorPosition(1, 1), CancellationToken.None);439assert.strictEqual(hovers.length, 1);440const [entry] = hovers;441assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });442});443444445test('HoverProvider, given range', async () => {446447disposables.add(extHost.registerHoverProvider(defaultExtension, defaultSelector, new class implements vscode.HoverProvider {448provideHover(): any {449return new types.Hover('Hello', new types.Range(3, 0, 8, 7));450}451}));452453await rpcProtocol.sync();454const hovers = await getHoversPromise(languageFeaturesService.hoverProvider, model, new EditorPosition(1, 1), CancellationToken.None);455assert.strictEqual(hovers.length, 1);456const [entry] = hovers;457assert.deepStrictEqual(entry.range, { startLineNumber: 4, startColumn: 1, endLineNumber: 9, endColumn: 8 });458});459460461test('HoverProvider, registration order', async () => {462disposables.add(extHost.registerHoverProvider(defaultExtension, defaultSelector, new class implements vscode.HoverProvider {463provideHover(): any {464return new types.Hover('registered first');465}466}));467468469disposables.add(extHost.registerHoverProvider(defaultExtension, defaultSelector, new class implements vscode.HoverProvider {470provideHover(): any {471return new types.Hover('registered second');472}473}));474475await rpcProtocol.sync();476const value = await getHoversPromise(languageFeaturesService.hoverProvider, model, new EditorPosition(1, 1), CancellationToken.None);477assert.strictEqual(value.length, 2);478const [first, second] = value;479assert.strictEqual(first.contents[0].value, 'registered second');480assert.strictEqual(second.contents[0].value, 'registered first');481});482483484test('HoverProvider, evil provider', async () => {485486disposables.add(extHost.registerHoverProvider(defaultExtension, defaultSelector, new class implements vscode.HoverProvider {487provideHover(): any {488throw new Error('evil');489}490}));491disposables.add(extHost.registerHoverProvider(defaultExtension, defaultSelector, new class implements vscode.HoverProvider {492provideHover(): any {493return new types.Hover('Hello');494}495}));496497await rpcProtocol.sync();498const hovers = await getHoversPromise(languageFeaturesService.hoverProvider, model, new EditorPosition(1, 1), CancellationToken.None);499assert.strictEqual(hovers.length, 1);500});501502// --- occurrences503504test('Occurrences, data conversion', async () => {505506disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentHighlightProvider {507provideDocumentHighlights(): any {508return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];509}510}));511512await rpcProtocol.sync();513const value = (await getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, new EditorPosition(1, 2), CancellationToken.None))!;514assert.strictEqual(value.size, 1);515const [entry] = Array.from(value.values())[0];516assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });517assert.strictEqual(entry.kind, languages.DocumentHighlightKind.Text);518});519520test('Occurrences, order 1/2', async () => {521522disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentHighlightProvider {523provideDocumentHighlights(): any {524return undefined;525}526}));527disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, '*', new class implements vscode.DocumentHighlightProvider {528provideDocumentHighlights(): any {529return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];530}531}));532533await rpcProtocol.sync();534const value = (await getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, new EditorPosition(1, 2), CancellationToken.None))!;535assert.strictEqual(value.size, 1);536const [entry] = Array.from(value.values())[0];537assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });538assert.strictEqual(entry.kind, languages.DocumentHighlightKind.Text);539});540541test('Occurrences, order 2/2', async () => {542543disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentHighlightProvider {544provideDocumentHighlights(): any {545return [new types.DocumentHighlight(new types.Range(0, 0, 0, 2))];546}547}));548disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, '*', new class implements vscode.DocumentHighlightProvider {549provideDocumentHighlights(): any {550return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];551}552}));553554await rpcProtocol.sync();555const value = (await getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, new EditorPosition(1, 2), CancellationToken.None))!;556assert.strictEqual(value.size, 1);557const [entry] = Array.from(value.values())[0];558assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 3 });559assert.strictEqual(entry.kind, languages.DocumentHighlightKind.Text);560});561562test('Occurrences, evil provider', async () => {563564disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentHighlightProvider {565provideDocumentHighlights(): any {566throw new Error('evil');567}568}));569570disposables.add(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentHighlightProvider {571provideDocumentHighlights(): any {572return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];573}574}));575576await rpcProtocol.sync();577const value = await getOccurrencesAtPosition(languageFeaturesService.documentHighlightProvider, model, new EditorPosition(1, 2), CancellationToken.None);578assert.strictEqual(value!.size, 1);579});580581// --- references582583test('References, registration order', async () => {584585disposables.add(extHost.registerReferenceProvider(defaultExtension, defaultSelector, new class implements vscode.ReferenceProvider {586provideReferences(): any {587return [new types.Location(URI.parse('far://register/first'), new types.Range(0, 0, 0, 0))];588}589}));590591disposables.add(extHost.registerReferenceProvider(defaultExtension, defaultSelector, new class implements vscode.ReferenceProvider {592provideReferences(): any {593return [new types.Location(URI.parse('far://register/second'), new types.Range(0, 0, 0, 0))];594}595}));596597await rpcProtocol.sync();598const value = await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, new EditorPosition(1, 2), false, false, CancellationToken.None);599assert.strictEqual(value.length, 2);600const [first, second] = value;601assert.strictEqual(first.uri.path, '/second');602assert.strictEqual(second.uri.path, '/first');603});604605test('References, data conversion', async () => {606607disposables.add(extHost.registerReferenceProvider(defaultExtension, defaultSelector, new class implements vscode.ReferenceProvider {608provideReferences(): any {609return [new types.Location(model.uri, new types.Position(0, 0))];610}611}));612613await rpcProtocol.sync();614const value = await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, new EditorPosition(1, 2), false, false, CancellationToken.None);615assert.strictEqual(value.length, 1);616const [item] = value;617assert.deepStrictEqual(item.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });618assert.strictEqual(item.uri.toString(), model.uri.toString());619});620621test('References, evil provider', async () => {622623disposables.add(extHost.registerReferenceProvider(defaultExtension, defaultSelector, new class implements vscode.ReferenceProvider {624provideReferences(): any {625throw new Error('evil');626}627}));628disposables.add(extHost.registerReferenceProvider(defaultExtension, defaultSelector, new class implements vscode.ReferenceProvider {629provideReferences(): any {630return [new types.Location(model.uri, new types.Range(0, 0, 0, 0))];631}632}));633634await rpcProtocol.sync();635const value = await getReferencesAtPosition(languageFeaturesService.referenceProvider, model, new EditorPosition(1, 2), false, false, CancellationToken.None);636assert.strictEqual(value.length, 1);637});638639// --- quick fix640641test('Quick Fix, command data conversion', async () => {642return runWithFakedTimers({ useFakeTimers: true }, async () => {643disposables.add(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, {644provideCodeActions(): vscode.Command[] {645return [646{ command: 'test1', title: 'Testing1' },647{ command: 'test2', title: 'Testing2' }648];649}650}));651652await rpcProtocol.sync();653const value = await getCodeActions(languageFeaturesService.codeActionProvider, model, model.getFullModelRange(), { type: languages.CodeActionTriggerType.Invoke, triggerAction: CodeActionTriggerSource.QuickFix }, Progress.None, CancellationToken.None);654const { validActions: actions } = value;655assert.strictEqual(actions.length, 2);656const [first, second] = actions;657assert.strictEqual(first.action.title, 'Testing1');658assert.strictEqual(first.action.command!.id, 'test1');659assert.strictEqual(second.action.title, 'Testing2');660assert.strictEqual(second.action.command!.id, 'test2');661value.dispose();662});663});664665test('Quick Fix, code action data conversion', async () => {666return runWithFakedTimers({ useFakeTimers: true }, async () => {667disposables.add(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, {668provideCodeActions(): vscode.CodeAction[] {669return [670{671title: 'Testing1',672command: { title: 'Testing1Command', command: 'test1' },673kind: types.CodeActionKind.Empty.append('test.scope')674}675];676}677}));678679await rpcProtocol.sync();680const value = await getCodeActions(languageFeaturesService.codeActionProvider, model, model.getFullModelRange(), { type: languages.CodeActionTriggerType.Invoke, triggerAction: CodeActionTriggerSource.Default }, Progress.None, CancellationToken.None);681const { validActions: actions } = value;682assert.strictEqual(actions.length, 1);683const [first] = actions;684assert.strictEqual(first.action.title, 'Testing1');685assert.strictEqual(first.action.command!.title, 'Testing1Command');686assert.strictEqual(first.action.command!.id, 'test1');687assert.strictEqual(first.action.kind, 'test.scope');688value.dispose();689});690});691692693test('Cannot read property \'id\' of undefined, #29469', async () => {694return runWithFakedTimers({ useFakeTimers: true }, async () => {695disposables.add(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, new class implements vscode.CodeActionProvider {696provideCodeActions(): any {697return [698undefined,699null,700{ command: 'test', title: 'Testing' }701];702}703}));704705await rpcProtocol.sync();706const value = await getCodeActions(languageFeaturesService.codeActionProvider, model, model.getFullModelRange(), { type: languages.CodeActionTriggerType.Invoke, triggerAction: CodeActionTriggerSource.Default }, Progress.None, CancellationToken.None);707const { validActions: actions } = value;708assert.strictEqual(actions.length, 1);709value.dispose();710});711});712713test('Quick Fix, evil provider', async () => {714return runWithFakedTimers({ useFakeTimers: true }, async () => {715disposables.add(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, new class implements vscode.CodeActionProvider {716provideCodeActions(): any {717throw new Error('evil');718}719}));720disposables.add(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, new class implements vscode.CodeActionProvider {721provideCodeActions(): any {722return [{ command: 'test', title: 'Testing' }];723}724}));725726await rpcProtocol.sync();727const value = await getCodeActions(languageFeaturesService.codeActionProvider, model, model.getFullModelRange(), { type: languages.CodeActionTriggerType.Invoke, triggerAction: CodeActionTriggerSource.QuickFix }, Progress.None, CancellationToken.None);728const { validActions: actions } = value;729assert.strictEqual(actions.length, 1);730value.dispose();731});732});733734// --- navigate types735736test('Navigate types, evil provider', async () => {737738disposables.add(extHost.registerWorkspaceSymbolProvider(defaultExtension, new class implements vscode.WorkspaceSymbolProvider {739provideWorkspaceSymbols(): any {740throw new Error('evil');741}742}));743744disposables.add(extHost.registerWorkspaceSymbolProvider(defaultExtension, new class implements vscode.WorkspaceSymbolProvider {745provideWorkspaceSymbols(): any {746return [new types.SymbolInformation('testing', types.SymbolKind.Array, new types.Range(0, 0, 1, 1))];747}748}));749750await rpcProtocol.sync();751const value = await getWorkspaceSymbols('');752assert.strictEqual(value.length, 1);753const [first] = value;754assert.strictEqual(first.symbol.name, 'testing');755});756757test('Navigate types, de-duplicate results', async () => {758const uri = URI.from({ scheme: 'foo', path: '/some/path' });759disposables.add(extHost.registerWorkspaceSymbolProvider(defaultExtension, new class implements vscode.WorkspaceSymbolProvider {760provideWorkspaceSymbols(): any {761return [new types.SymbolInformation('ONE', types.SymbolKind.Array, undefined, new types.Location(uri, new types.Range(0, 0, 1, 1)))];762}763}));764765disposables.add(extHost.registerWorkspaceSymbolProvider(defaultExtension, new class implements vscode.WorkspaceSymbolProvider {766provideWorkspaceSymbols(): any {767return [new types.SymbolInformation('ONE', types.SymbolKind.Array, undefined, new types.Location(uri, new types.Range(0, 0, 1, 1)))]; // get de-duped768}769}));770771disposables.add(extHost.registerWorkspaceSymbolProvider(defaultExtension, new class implements vscode.WorkspaceSymbolProvider {772provideWorkspaceSymbols(): any {773return [new types.SymbolInformation('ONE', types.SymbolKind.Array, undefined, new types.Location(uri, undefined!))]; // NO dedupe because of resolve774}775resolveWorkspaceSymbol(a: vscode.SymbolInformation) {776return a;777}778}));779780disposables.add(extHost.registerWorkspaceSymbolProvider(defaultExtension, new class implements vscode.WorkspaceSymbolProvider {781provideWorkspaceSymbols(): any {782return [new types.SymbolInformation('ONE', types.SymbolKind.Struct, undefined, new types.Location(uri, new types.Range(0, 0, 1, 1)))]; // NO dedupe because of kind783}784}));785786await rpcProtocol.sync();787const value = await getWorkspaceSymbols('');788assert.strictEqual(value.length, 3);789});790791// --- rename792793test('Rename, evil provider 0/2', async () => {794795disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {796provideRenameEdits(): any {797throw new class Foo { };798}799}));800801await rpcProtocol.sync();802try {803await rename(languageFeaturesService.renameProvider, model, new EditorPosition(1, 1), 'newName');804throw Error();805}806catch (err) {807// expected808}809});810811test('Rename, evil provider 1/2', async () => {812813disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {814provideRenameEdits(): any {815throw Error('evil');816}817}));818819await rpcProtocol.sync();820const value = await rename(languageFeaturesService.renameProvider, model, new EditorPosition(1, 1), 'newName');821assert.strictEqual(value.rejectReason, 'evil');822});823824test('Rename, evil provider 2/2', async () => {825826disposables.add(extHost.registerRenameProvider(defaultExtension, '*', new class implements vscode.RenameProvider {827provideRenameEdits(): any {828throw Error('evil');829}830}));831832disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {833provideRenameEdits(): any {834const edit = new types.WorkspaceEdit();835edit.replace(model.uri, new types.Range(0, 0, 0, 0), 'testing');836return edit;837}838}));839840await rpcProtocol.sync();841const value = await rename(languageFeaturesService.renameProvider, model, new EditorPosition(1, 1), 'newName');842assert.strictEqual(value.edits.length, 1);843});844845test('Rename, ordering', async () => {846847disposables.add(extHost.registerRenameProvider(defaultExtension, '*', new class implements vscode.RenameProvider {848provideRenameEdits(): any {849const edit = new types.WorkspaceEdit();850edit.replace(model.uri, new types.Range(0, 0, 0, 0), 'testing');851edit.replace(model.uri, new types.Range(1, 0, 1, 0), 'testing');852return edit;853}854}));855856disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {857provideRenameEdits(): any {858return;859}860}));861862await rpcProtocol.sync();863const value = await rename(languageFeaturesService.renameProvider, model, new EditorPosition(1, 1), 'newName');864// least relevant rename provider865assert.strictEqual(value.edits.length, 2);866});867868test('Multiple RenameProviders don\'t respect all possible PrepareRename handlers 1/2, #98352', async function () {869870const called = [false, false, false, false];871872disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {873prepareRename(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.Range> {874called[0] = true;875const range = document.getWordRangeAtPosition(position);876return range;877}878879provideRenameEdits(): vscode.ProviderResult<vscode.WorkspaceEdit> {880called[1] = true;881return undefined;882}883}));884885disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {886prepareRename(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.Range> {887called[2] = true;888return Promise.reject('Cannot rename this symbol2.');889}890provideRenameEdits(): vscode.ProviderResult<vscode.WorkspaceEdit> {891called[3] = true;892return undefined;893}894}));895896await rpcProtocol.sync();897await rename(languageFeaturesService.renameProvider, model, new EditorPosition(1, 1), 'newName');898899assert.deepStrictEqual(called, [true, true, true, false]);900});901902test('Multiple RenameProviders don\'t respect all possible PrepareRename handlers 2/2, #98352', async function () {903904const called = [false, false, false];905906disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {907prepareRename(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.Range> {908called[0] = true;909const range = document.getWordRangeAtPosition(position);910return range;911}912913provideRenameEdits(): vscode.ProviderResult<vscode.WorkspaceEdit> {914called[1] = true;915return undefined;916}917}));918919disposables.add(extHost.registerRenameProvider(defaultExtension, defaultSelector, new class implements vscode.RenameProvider {920921provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string,): vscode.ProviderResult<vscode.WorkspaceEdit> {922called[2] = true;923return new types.WorkspaceEdit();924}925}));926927await rpcProtocol.sync();928await rename(languageFeaturesService.renameProvider, model, new EditorPosition(1, 1), 'newName');929930// first provider has NO prepare which means it is taken by default931assert.deepStrictEqual(called, [false, false, true]);932});933934// --- parameter hints935936test('Parameter Hints, order', async () => {937938disposables.add(extHost.registerSignatureHelpProvider(defaultExtension, defaultSelector, new class implements vscode.SignatureHelpProvider {939provideSignatureHelp(): any {940return undefined;941}942}, []));943944disposables.add(extHost.registerSignatureHelpProvider(defaultExtension, defaultSelector, new class implements vscode.SignatureHelpProvider {945provideSignatureHelp(): vscode.SignatureHelp {946return {947signatures: [],948activeParameter: 0,949activeSignature: 0950};951}952}, []));953954await rpcProtocol.sync();955const value = await provideSignatureHelp(languageFeaturesService.signatureHelpProvider, model, new EditorPosition(1, 1), { triggerKind: languages.SignatureHelpTriggerKind.Invoke, isRetrigger: false }, CancellationToken.None);956assert.ok(value);957});958959test('Parameter Hints, evil provider', async () => {960961disposables.add(extHost.registerSignatureHelpProvider(defaultExtension, defaultSelector, new class implements vscode.SignatureHelpProvider {962provideSignatureHelp(): any {963throw new Error('evil');964}965}, []));966967await rpcProtocol.sync();968const value = await provideSignatureHelp(languageFeaturesService.signatureHelpProvider, model, new EditorPosition(1, 1), { triggerKind: languages.SignatureHelpTriggerKind.Invoke, isRetrigger: false }, CancellationToken.None);969assert.strictEqual(value, undefined);970});971972// --- suggestions973974test('Suggest, order 1/3', async () => {975return runWithFakedTimers({ useFakeTimers: true }, async () => {976disposables.add(extHost.registerCompletionItemProvider(defaultExtension, '*', new class implements vscode.CompletionItemProvider {977provideCompletionItems(): any {978return [new types.CompletionItem('testing1')];979}980}, []));981982disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {983provideCompletionItems(): any {984return [new types.CompletionItem('testing2')];985}986}, []));987988await rpcProtocol.sync();989const value = await provideSuggestionItems(languageFeaturesService.completionProvider, model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set<languages.CompletionItemKind>().add(languages.CompletionItemKind.Snippet)));990assert.strictEqual(value.items.length, 1);991assert.strictEqual(value.items[0].completion.insertText, 'testing2');992value.disposable.dispose();993});994});995996test('Suggest, order 2/3', async () => {997return runWithFakedTimers({ useFakeTimers: true }, async () => {998disposables.add(extHost.registerCompletionItemProvider(defaultExtension, '*', new class implements vscode.CompletionItemProvider {999provideCompletionItems(): any {1000return [new types.CompletionItem('weak-selector')]; // weaker selector but result1001}1002}, []));10031004disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {1005provideCompletionItems(): any {1006return []; // stronger selector but not a good result;1007}1008}, []));10091010await rpcProtocol.sync();1011const value = await provideSuggestionItems(languageFeaturesService.completionProvider, model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set<languages.CompletionItemKind>().add(languages.CompletionItemKind.Snippet)));1012assert.strictEqual(value.items.length, 1);1013assert.strictEqual(value.items[0].completion.insertText, 'weak-selector');1014value.disposable.dispose();1015});1016});10171018test('Suggest, order 3/3', async () => {1019return runWithFakedTimers({ useFakeTimers: true }, async () => {1020disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {1021provideCompletionItems(): any {1022return [new types.CompletionItem('strong-1')];1023}1024}, []));10251026disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {1027provideCompletionItems(): any {1028return [new types.CompletionItem('strong-2')];1029}1030}, []));10311032await rpcProtocol.sync();1033const value = await provideSuggestionItems(languageFeaturesService.completionProvider, model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set<languages.CompletionItemKind>().add(languages.CompletionItemKind.Snippet)));1034assert.strictEqual(value.items.length, 2);1035assert.strictEqual(value.items[0].completion.insertText, 'strong-1'); // sort by label1036assert.strictEqual(value.items[1].completion.insertText, 'strong-2');1037value.disposable.dispose();1038});1039});10401041test('Suggest, evil provider', async () => {1042return runWithFakedTimers({ useFakeTimers: true }, async () => {1043disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {1044provideCompletionItems(): any {1045throw new Error('evil');1046}1047}, []));10481049disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {1050provideCompletionItems(): any {1051return [new types.CompletionItem('testing')];1052}1053}, []));105410551056await rpcProtocol.sync();1057const value = await provideSuggestionItems(languageFeaturesService.completionProvider, model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set<languages.CompletionItemKind>().add(languages.CompletionItemKind.Snippet)));1058assert.strictEqual(value.items[0].container.incomplete, false);1059value.disposable.dispose();1060});1061});10621063test('Suggest, CompletionList', async () => {1064return runWithFakedTimers({ useFakeTimers: true }, async () => {1065disposables.add(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, new class implements vscode.CompletionItemProvider {1066provideCompletionItems(): any {1067return new types.CompletionList([<any>new types.CompletionItem('hello')], true);1068}1069}, []));10701071await rpcProtocol.sync();1072await provideSuggestionItems(languageFeaturesService.completionProvider, model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set<languages.CompletionItemKind>().add(languages.CompletionItemKind.Snippet))).then(model => {1073assert.strictEqual(model.items[0].container.incomplete, true);1074model.disposable.dispose();1075});1076});1077});10781079// --- format10801081const NullWorkerService = new class extends mock<IEditorWorkerService>() {1082override computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[] | null | undefined): Promise<languages.TextEdit[] | undefined> {1083return Promise.resolve(edits ?? undefined);1084}1085};10861087test('Format Doc, data conversion', async () => {1088disposables.add(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {1089provideDocumentFormattingEdits(): any {1090return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'testing'), types.TextEdit.setEndOfLine(types.EndOfLine.LF)];1091}1092}));10931094await rpcProtocol.sync();1095const value = (await getDocumentFormattingEditsUntilResult(NullWorkerService, languageFeaturesService, model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!;1096assert.strictEqual(value.length, 2);1097const [first, second] = value;1098assert.strictEqual(first.text, 'testing');1099assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });1100assert.strictEqual(second.eol, EndOfLineSequence.LF);1101assert.strictEqual(second.text, '');1102assert.deepStrictEqual(second.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });1103});11041105test('Format Doc, evil provider', async () => {1106disposables.add(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {1107provideDocumentFormattingEdits(): any {1108throw new Error('evil');1109}1110}));11111112await rpcProtocol.sync();1113return getDocumentFormattingEditsUntilResult(NullWorkerService, languageFeaturesService, model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None);1114});11151116test('Format Doc, order', async () => {11171118disposables.add(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {1119provideDocumentFormattingEdits(): any {1120return undefined;1121}1122}));11231124disposables.add(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {1125provideDocumentFormattingEdits(): any {1126return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'testing')];1127}1128}));11291130disposables.add(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {1131provideDocumentFormattingEdits(): any {1132return undefined;1133}1134}));11351136await rpcProtocol.sync();1137const value = (await getDocumentFormattingEditsUntilResult(NullWorkerService, languageFeaturesService, model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!;1138assert.strictEqual(value.length, 1);1139const [first] = value;1140assert.strictEqual(first.text, 'testing');1141assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });1142});11431144test('Format Range, data conversion', async () => {1145disposables.add(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentRangeFormattingEditProvider {1146provideDocumentRangeFormattingEdits(): any {1147return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'testing')];1148}1149}));11501151await rpcProtocol.sync();1152const value = (await getDocumentRangeFormattingEditsUntilResult(NullWorkerService, languageFeaturesService, model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!;1153assert.strictEqual(value.length, 1);1154const [first] = value;1155assert.strictEqual(first.text, 'testing');1156assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });1157});11581159test('Format Range, + format_doc', async () => {1160disposables.add(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentRangeFormattingEditProvider {1161provideDocumentRangeFormattingEdits(): any {1162return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'range')];1163}1164}));1165disposables.add(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentRangeFormattingEditProvider {1166provideDocumentRangeFormattingEdits(): any {1167return [new types.TextEdit(new types.Range(2, 3, 4, 5), 'range2')];1168}1169}));1170disposables.add(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {1171provideDocumentFormattingEdits(): any {1172return [new types.TextEdit(new types.Range(0, 0, 1, 1), 'doc')];1173}1174}));1175await rpcProtocol.sync();1176const value = (await getDocumentRangeFormattingEditsUntilResult(NullWorkerService, languageFeaturesService, model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!;1177assert.strictEqual(value.length, 1);1178const [first] = value;1179assert.strictEqual(first.text, 'range2');1180assert.strictEqual(first.range.startLineNumber, 3);1181assert.strictEqual(first.range.startColumn, 4);1182assert.strictEqual(first.range.endLineNumber, 5);1183assert.strictEqual(first.range.endColumn, 6);1184});11851186test('Format Range, evil provider', async () => {1187disposables.add(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentRangeFormattingEditProvider {1188provideDocumentRangeFormattingEdits(): any {1189throw new Error('evil');1190}1191}));11921193await rpcProtocol.sync();1194return getDocumentRangeFormattingEditsUntilResult(NullWorkerService, languageFeaturesService, model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None);1195});11961197test('Format on Type, data conversion', async () => {11981199disposables.add(extHost.registerOnTypeFormattingEditProvider(defaultExtension, defaultSelector, new class implements vscode.OnTypeFormattingEditProvider {1200provideOnTypeFormattingEdits(): any {1201return [new types.TextEdit(new types.Range(0, 0, 0, 0), arguments[2])];1202}1203}, [';']));12041205await rpcProtocol.sync();1206const value = (await getOnTypeFormattingEdits(NullWorkerService, languageFeaturesService, model, new EditorPosition(1, 1), ';', { insertSpaces: true, tabSize: 2 }, CancellationToken.None))!;1207assert.strictEqual(value.length, 1);1208const [first] = value;1209assert.strictEqual(first.text, ';');1210assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });1211});12121213test('Links, data conversion', async () => {12141215disposables.add(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentLinkProvider {1216provideDocumentLinks() {1217const link = new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3'));1218link.tooltip = 'tooltip';1219return [link];1220}1221}));12221223await rpcProtocol.sync();1224const { links } = disposables.add(await getLinks(languageFeaturesService.linkProvider, model, CancellationToken.None));1225assert.strictEqual(links.length, 1);1226const [first] = links;1227assert.strictEqual(first.url?.toString(), 'foo:bar#3');1228assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 });1229assert.strictEqual(first.tooltip, 'tooltip');1230});12311232test('Links, evil provider', async () => {12331234disposables.add(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentLinkProvider {1235provideDocumentLinks() {1236return [new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3'))];1237}1238}));12391240disposables.add(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentLinkProvider {1241provideDocumentLinks(): any {1242throw new Error();1243}1244}));12451246await rpcProtocol.sync();1247const { links } = disposables.add(await getLinks(languageFeaturesService.linkProvider, model, CancellationToken.None));1248assert.strictEqual(links.length, 1);1249const [first] = links;1250assert.strictEqual(first.url?.toString(), 'foo:bar#3');1251assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 });1252});12531254test('Document colors, data conversion', async () => {12551256disposables.add(extHost.registerColorProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentColorProvider {1257provideDocumentColors(): vscode.ColorInformation[] {1258return [new types.ColorInformation(new types.Range(0, 0, 0, 20), new types.Color(0.1, 0.2, 0.3, 0.4))];1259}1260provideColorPresentations(color: vscode.Color, context: { range: vscode.Range; document: vscode.TextDocument }): vscode.ColorPresentation[] {1261return [];1262}1263}));12641265await rpcProtocol.sync();1266const value = await getColors(languageFeaturesService.colorProvider, model, CancellationToken.None);1267assert.strictEqual(value.length, 1);1268const [first] = value;1269assert.deepStrictEqual(first.colorInfo.color, { red: 0.1, green: 0.2, blue: 0.3, alpha: 0.4 });1270assert.deepStrictEqual(first.colorInfo.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 21 });1271});12721273// -- selection ranges12741275test('Selection Ranges, data conversion', async () => {1276disposables.add(extHost.registerSelectionRangeProvider(defaultExtension, defaultSelector, new class implements vscode.SelectionRangeProvider {1277provideSelectionRanges() {1278return [1279new types.SelectionRange(new types.Range(0, 10, 0, 18), new types.SelectionRange(new types.Range(0, 2, 0, 20))),1280];1281}1282}));12831284await rpcProtocol.sync();12851286provideSelectionRanges(languageFeaturesService.selectionRangeProvider, model, [new Position(1, 17)], { selectLeadingAndTrailingWhitespace: true, selectSubwords: true }, CancellationToken.None).then(ranges => {1287assert.strictEqual(ranges.length, 1);1288assert.ok(ranges[0].length >= 2);1289});1290});12911292test('Selection Ranges, bad data', async () => {12931294try {1295const _a = new types.SelectionRange(new types.Range(0, 10, 0, 18),1296new types.SelectionRange(new types.Range(0, 11, 0, 18))1297);1298assert.ok(false, String(_a));1299} catch (err) {1300assert.ok(true);1301}13021303});1304});130513061307