Path: blob/main/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts
5241 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 '../../../../editor/contrib/codeAction/browser/codeAction.js';6import '../../../../editor/contrib/codelens/browser/codelens.js';7import '../../../../editor/contrib/colorPicker/browser/colorPickerContribution.js';8import '../../../../editor/contrib/format/browser/format.js';9import '../../../../editor/contrib/gotoSymbol/browser/goToCommands.js';10import '../../../../editor/contrib/documentSymbols/browser/documentSymbols.js';11import '../../../../editor/contrib/hover/browser/getHover.js';12import '../../../../editor/contrib/links/browser/getLinks.js';13import '../../../../editor/contrib/parameterHints/browser/provideSignatureHelp.js';14import '../../../../editor/contrib/smartSelect/browser/smartSelect.js';15import '../../../../editor/contrib/suggest/browser/suggest.js';16import '../../../../editor/contrib/rename/browser/rename.js';17import '../../../../editor/contrib/inlayHints/browser/inlayHintsController.js';1819import assert from 'assert';20import { setUnexpectedErrorHandler, errorHandler } from '../../../../base/common/errors.js';21import { URI } from '../../../../base/common/uri.js';22import { Event } from '../../../../base/common/event.js';23import * as types from '../../common/extHostTypes.js';24import { createTextModel } from '../../../../editor/test/common/testTextModel.js';25import { TestRPCProtocol } from '../common/testRPCProtocol.js';26import { MarkerService } from '../../../../platform/markers/common/markerService.js';27import { IMarkerService } from '../../../../platform/markers/common/markers.js';28import { ICommandService, CommandsRegistry } from '../../../../platform/commands/common/commands.js';29import { IModelService } from '../../../../editor/common/services/model.js';30import { ExtHostLanguageFeatures } from '../../common/extHostLanguageFeatures.js';31import { MainThreadLanguageFeatures } from '../../browser/mainThreadLanguageFeatures.js';32import { ExtHostApiCommands } from '../../common/extHostApiCommands.js';33import { ExtHostCommands } from '../../common/extHostCommands.js';34import { MainThreadCommands } from '../../browser/mainThreadCommands.js';35import { ExtHostDocuments } from '../../common/extHostDocuments.js';36import { ExtHostDocumentsAndEditors } from '../../common/extHostDocumentsAndEditors.js';37import { MainContext, ExtHostContext } from '../../common/extHost.protocol.js';38import { ExtHostDiagnostics } from '../../common/extHostDiagnostics.js';39import type * as vscode from 'vscode';40import '../../../contrib/search/browser/search.contribution.js';41import { ILogService, NullLogService } from '../../../../platform/log/common/log.js';42import { ITextModel } from '../../../../editor/common/model.js';43import { nullExtensionDescription, IExtensionService } from '../../../services/extensions/common/extensions.js';44import { dispose, ImmortalReference } from '../../../../base/common/lifecycle.js';45import { IEditorWorkerService } from '../../../../editor/common/services/editorWorker.js';46import { mock } from '../../../../base/test/common/mock.js';47import { NullApiDeprecationService } from '../../common/extHostApiDeprecationService.js';48import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';49import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';50import { IResolvedTextEditorModel, ITextModelService } from '../../../../editor/common/services/resolverService.js';51import { IExtHostFileSystemInfo } from '../../common/extHostFileSystemInfo.js';52import { URITransformerService } from '../../common/extHostUriTransformerService.js';53import { IOutlineModelService, OutlineModelService } from '../../../../editor/contrib/documentSymbols/browser/outlineModel.js';54import { ILanguageFeatureDebounceService, LanguageFeatureDebounceService } from '../../../../editor/common/services/languageFeatureDebounce.js';55import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';56import { LanguageFeaturesService } from '../../../../editor/common/services/languageFeaturesService.js';57import { assertType } from '../../../../base/common/types.js';58import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';59import { IExtHostTelemetry } from '../../common/extHostTelemetry.js';60import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';61import { TestConfigurationService } from '../../../../platform/configuration/test/common/testConfigurationService.js';62import { IEnvironmentService } from '../../../../platform/environment/common/environment.js';63import { TestInstantiationService } from '../../../../platform/instantiation/test/common/instantiationServiceMock.js';64import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';65import { runWithFakedTimers } from '../../../../base/test/common/timeTravelScheduler.js';66import { timeout } from '../../../../base/common/async.js';67import { FormattingOptions } from '../../../../editor/common/languages.js';6869function assertRejects(fn: () => Promise<any>, message: string = 'Expected rejection') {70return fn().then(() => assert.ok(false, message), _err => assert.ok(true));71}7273function isLocation(value: vscode.Location | vscode.LocationLink): value is vscode.Location {74const candidate = value as vscode.Location;75return candidate && candidate.uri instanceof URI && candidate.range instanceof types.Range;76}7778suite('ExtHostLanguageFeatureCommands', function () {79const defaultSelector = { scheme: 'far' };80let model: ITextModel;8182let insta: TestInstantiationService;83let rpcProtocol: TestRPCProtocol;84let extHost: ExtHostLanguageFeatures;85let mainThread: MainThreadLanguageFeatures;86let commands: ExtHostCommands;87let disposables: vscode.Disposable[] = [];8889let originalErrorHandler: (e: any) => any;9091suiteSetup(() => {92model = createTextModel(93[94'This is the first line',95'This is the second line',96'This is the third line',97].join('\n'),98undefined,99undefined,100URI.parse('far://testing/file.b'));101originalErrorHandler = errorHandler.getUnexpectedErrorHandler();102setUnexpectedErrorHandler(() => { });103104// Use IInstantiationService to get typechecking when instantiating105rpcProtocol = new TestRPCProtocol();106const services = new ServiceCollection();107services.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {108override asCanonicalUri(uri: URI): URI {109return uri;110}111});112services.set(ILanguageFeaturesService, new SyncDescriptor(LanguageFeaturesService));113services.set(IExtensionService, new class extends mock<IExtensionService>() {114override async activateByEvent() {115116}117override activationEventIsDone(activationEvent: string): boolean {118return true;119}120});121services.set(ICommandService, new SyncDescriptor(class extends mock<ICommandService>() {122123override executeCommand(id: string, ...args: any): any {124const command = CommandsRegistry.getCommands().get(id);125if (!command) {126return Promise.reject(new Error(id + ' NOT known'));127}128const { handler } = command;129return Promise.resolve(insta.invokeFunction(handler, ...args));130}131}));132services.set(IEnvironmentService, new class extends mock<IEnvironmentService>() {133override isBuilt: boolean = true;134override isExtensionDevelopment: boolean = false;135});136services.set(IMarkerService, new MarkerService());137services.set(ILogService, new SyncDescriptor(NullLogService));138services.set(ILanguageFeatureDebounceService, new SyncDescriptor(LanguageFeatureDebounceService));139services.set(IModelService, new class extends mock<IModelService>() {140override getModel() { return model; }141override onModelRemoved = Event.None;142});143services.set(ITextModelService, new class extends mock<ITextModelService>() {144override async createModelReference() {145return new ImmortalReference<IResolvedTextEditorModel>(new class extends mock<IResolvedTextEditorModel>() {146override textEditorModel = model;147});148}149});150services.set(IEditorWorkerService, new class extends mock<IEditorWorkerService>() {151override async computeMoreMinimalEdits(_uri: any, edits: any) {152return edits || undefined;153}154});155services.set(ILanguageFeatureDebounceService, new SyncDescriptor(LanguageFeatureDebounceService));156services.set(IOutlineModelService, new SyncDescriptor(OutlineModelService));157services.set(IConfigurationService, new TestConfigurationService());158159insta = new TestInstantiationService(services);160161const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());162extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({163addedDocuments: [{164isDirty: false,165versionId: model.getVersionId(),166languageId: model.getLanguageId(),167uri: model.uri,168lines: model.getValue().split(model.getEOL()),169EOL: model.getEOL(),170encoding: 'utf8'171}]172});173const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);174rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments);175176commands = new ExtHostCommands(rpcProtocol, new NullLogService(), new class extends mock<IExtHostTelemetry>() {177override onExtensionError(): boolean {178return true;179}180});181rpcProtocol.set(ExtHostContext.ExtHostCommands, commands);182rpcProtocol.set(MainContext.MainThreadCommands, insta.createInstance(MainThreadCommands, rpcProtocol));183ExtHostApiCommands.register(commands);184185const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService(), new class extends mock<IExtHostFileSystemInfo>() { }, extHostDocumentsAndEditors);186rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics);187188extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService, new class extends mock<IExtHostTelemetry>() {189override onExtensionError(): boolean {190return true;191}192});193rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost);194195mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, insta.createInstance(MainThreadLanguageFeatures, rpcProtocol));196197// forcefully create the outline service so that `ensureNoDisposablesAreLeakedInTestSuite` doesn't bark198insta.get(IOutlineModelService);199200return rpcProtocol.sync();201});202203suiteTeardown(() => {204setUnexpectedErrorHandler(originalErrorHandler);205model.dispose();206mainThread.dispose();207208(<OutlineModelService>insta.get(IOutlineModelService)).dispose();209insta.dispose();210});211212teardown(() => {213disposables = dispose(disposables);214return rpcProtocol.sync();215});216217ensureNoDisposablesAreLeakedInTestSuite();218219// --- workspace symbols220221function testApiCmd(name: string, fn: () => Promise<any>) {222test(name, async function () {223await runWithFakedTimers({}, async () => {224await fn();225await timeout(10000); // API commands for things that allow commands dispose their result delay. This is to be nice226// because otherwise properties like command are disposed too early227});228});229230}231232test('WorkspaceSymbols, invalid arguments', function () {233const promises = [234assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider')),235assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', null)),236assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', undefined)),237assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', true))238];239return Promise.all(promises);240});241242test('WorkspaceSymbols, back and forth', function () {243244disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, <vscode.WorkspaceSymbolProvider>{245provideWorkspaceSymbols(query): any {246return [247new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first')),248new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/second'))249];250}251}));252253disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, <vscode.WorkspaceSymbolProvider>{254provideWorkspaceSymbols(query): any {255return [256new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first'))257];258}259}));260261return rpcProtocol.sync().then(() => {262return commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', 'testing').then(value => {263264assert.strictEqual(value.length, 2); // de-duped265for (const info of value) {266assert.strictEqual(info instanceof types.SymbolInformation, true);267assert.strictEqual(info.name, 'testing');268assert.strictEqual(info.kind, types.SymbolKind.Array);269}270});271});272});273274test('executeWorkspaceSymbolProvider should accept empty string, #39522', async function () {275276disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, {277provideWorkspaceSymbols(): vscode.SymbolInformation[] {278return [new types.SymbolInformation('hello', types.SymbolKind.Array, new types.Range(0, 0, 0, 0), URI.parse('foo:bar')) as vscode.SymbolInformation];279}280}));281282await rpcProtocol.sync();283let symbols = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', '');284assert.strictEqual(symbols.length, 1);285286await rpcProtocol.sync();287symbols = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', '*');288assert.strictEqual(symbols.length, 1);289});290291// --- formatting292test('executeFormatDocumentProvider, back and forth', async function () {293294disposables.push(extHost.registerDocumentFormattingEditProvider(nullExtensionDescription, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {295provideDocumentFormattingEdits() {296return [types.TextEdit.insert(new types.Position(0, 0), '42')];297}298}));299300await rpcProtocol.sync();301const edits = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeFormatDocumentProvider', model.uri, {302insertSpaces: false,303tabSize: 4,304} satisfies FormattingOptions);305assert.strictEqual(edits.length, 1);306});307308309// --- rename310test('vscode.prepareRename', async function () {311disposables.push(extHost.registerRenameProvider(nullExtensionDescription, defaultSelector, new class implements vscode.RenameProvider {312313prepareRename(document: vscode.TextDocument, position: vscode.Position) {314return {315range: new types.Range(0, 12, 0, 24),316placeholder: 'foooPlaceholder'317};318}319320provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string) {321const edit = new types.WorkspaceEdit();322edit.insert(document.uri, <types.Position>position, newName);323return edit;324}325}));326327await rpcProtocol.sync();328329const data = await commands.executeCommand<{ range: vscode.Range; placeholder: string }>('vscode.prepareRename', model.uri, new types.Position(0, 12));330331assert.ok(data);332assert.strictEqual(data.placeholder, 'foooPlaceholder');333assert.strictEqual(data.range.start.line, 0);334assert.strictEqual(data.range.start.character, 12);335assert.strictEqual(data.range.end.line, 0);336assert.strictEqual(data.range.end.character, 24);337338});339340test('vscode.executeDocumentRenameProvider', async function () {341disposables.push(extHost.registerRenameProvider(nullExtensionDescription, defaultSelector, new class implements vscode.RenameProvider {342provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string) {343const edit = new types.WorkspaceEdit();344edit.insert(document.uri, <types.Position>position, newName);345return edit;346}347}));348349await rpcProtocol.sync();350351const edit = await commands.executeCommand<vscode.WorkspaceEdit>('vscode.executeDocumentRenameProvider', model.uri, new types.Position(0, 12), 'newNameOfThis');352353assert.ok(edit);354assert.strictEqual(edit.has(model.uri), true);355const textEdits = edit.get(model.uri);356assert.strictEqual(textEdits.length, 1);357assert.strictEqual(textEdits[0].newText, 'newNameOfThis');358});359360// --- definition361362test('Definition, invalid arguments', function () {363const promises = [364assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider')),365assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', null)),366assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', undefined)),367assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', true, false))368];369370return Promise.all(promises);371});372373test('Definition, back and forth', function () {374375disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{376provideDefinition(doc: any): any {377return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));378}379}));380disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{381provideDefinition(doc: any): any {382// duplicate result will get removed383return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));384}385}));386disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{387provideDefinition(doc: any): any {388return [389new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),390new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),391new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),392];393}394}));395396return rpcProtocol.sync().then(() => {397return commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {398assert.strictEqual(values.length, 4);399for (const v of values) {400assert.ok(v.uri instanceof URI);401assert.ok(v.range instanceof types.Range);402}403});404});405});406407408test('Definition, back and forth (sorting & de-deduping)', function () {409410disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{411provideDefinition(doc: any): any {412return new types.Location(URI.parse('file:///b'), new types.Range(1, 0, 0, 0));413}414}));415disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{416provideDefinition(doc: any): any {417// duplicate result will get removed418return new types.Location(URI.parse('file:///b'), new types.Range(1, 0, 0, 0));419}420}));421disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{422provideDefinition(doc: any): any {423return [424new types.Location(URI.parse('file:///a'), new types.Range(2, 0, 0, 0)),425new types.Location(URI.parse('file:///c'), new types.Range(3, 0, 0, 0)),426new types.Location(URI.parse('file:///d'), new types.Range(4, 0, 0, 0)),427];428}429}));430431return rpcProtocol.sync().then(() => {432return commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {433assert.strictEqual(values.length, 4);434435assert.strictEqual(values[0].uri.path, '/a');436assert.strictEqual(values[1].uri.path, '/b');437assert.strictEqual(values[2].uri.path, '/c');438assert.strictEqual(values[3].uri.path, '/d');439});440});441});442443test('Definition Link', () => {444disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{445provideDefinition(doc: any): (vscode.Location | vscode.LocationLink)[] {446return [447new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),448{ targetUri: doc.uri, targetRange: new types.Range(1, 0, 0, 0), targetSelectionRange: new types.Range(1, 1, 1, 1), originSelectionRange: new types.Range(2, 2, 2, 2) }449];450}451}));452453return rpcProtocol.sync().then(() => {454return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {455assert.strictEqual(values.length, 2);456for (const v of values) {457if (isLocation(v)) {458assert.ok(v.uri instanceof URI);459assert.ok(v.range instanceof types.Range);460} else {461assert.ok(v.targetUri instanceof URI);462assert.ok(v.targetRange instanceof types.Range);463assert.ok(v.targetSelectionRange instanceof types.Range);464assert.ok(v.originSelectionRange instanceof types.Range);465}466}467});468});469});470471// --- declaration472473test('Declaration, back and forth', function () {474475disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{476provideDeclaration(doc: any): any {477return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));478}479}));480disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{481provideDeclaration(doc: any): any {482// duplicate result will get removed483return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));484}485}));486disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{487provideDeclaration(doc: any): any {488return [489new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),490new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),491new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),492];493}494}));495496return rpcProtocol.sync().then(() => {497return commands.executeCommand<vscode.Location[]>('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => {498assert.strictEqual(values.length, 4);499for (const v of values) {500assert.ok(v.uri instanceof URI);501assert.ok(v.range instanceof types.Range);502}503});504});505});506507test('Declaration Link', () => {508disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{509provideDeclaration(doc: any): (vscode.Location | vscode.LocationLink)[] {510return [511new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),512{ targetUri: doc.uri, targetRange: new types.Range(1, 0, 0, 0), targetSelectionRange: new types.Range(1, 1, 1, 1), originSelectionRange: new types.Range(2, 2, 2, 2) }513];514}515}));516517return rpcProtocol.sync().then(() => {518return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => {519assert.strictEqual(values.length, 2);520for (const v of values) {521if (isLocation(v)) {522assert.ok(v.uri instanceof URI);523assert.ok(v.range instanceof types.Range);524} else {525assert.ok(v.targetUri instanceof URI);526assert.ok(v.targetRange instanceof types.Range);527assert.ok(v.targetSelectionRange instanceof types.Range);528assert.ok(v.originSelectionRange instanceof types.Range);529}530}531});532});533});534535// --- type definition536537test('Type Definition, invalid arguments', function () {538const promises = [539assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider')),540assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', null)),541assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', undefined)),542assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', true, false))543];544545return Promise.all(promises);546});547548test('Type Definition, back and forth', function () {549550disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{551provideTypeDefinition(doc: any): any {552return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));553}554}));555disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{556provideTypeDefinition(doc: any): any {557// duplicate result will get removed558return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));559}560}));561disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{562provideTypeDefinition(doc: any): any {563return [564new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),565new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),566new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),567];568}569}));570571return rpcProtocol.sync().then(() => {572return commands.executeCommand<vscode.Location[]>('vscode.executeTypeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {573assert.strictEqual(values.length, 4);574for (const v of values) {575assert.ok(v.uri instanceof URI);576assert.ok(v.range instanceof types.Range);577}578});579});580});581582test('Type Definition Link', () => {583disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{584provideTypeDefinition(doc: any): (vscode.Location | vscode.LocationLink)[] {585return [586new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),587{ targetUri: doc.uri, targetRange: new types.Range(1, 0, 0, 0), targetSelectionRange: new types.Range(1, 1, 1, 1), originSelectionRange: new types.Range(2, 2, 2, 2) }588];589}590}));591592return rpcProtocol.sync().then(() => {593return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeTypeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {594assert.strictEqual(values.length, 2);595for (const v of values) {596if (isLocation(v)) {597assert.ok(v.uri instanceof URI);598assert.ok(v.range instanceof types.Range);599} else {600assert.ok(v.targetUri instanceof URI);601assert.ok(v.targetRange instanceof types.Range);602assert.ok(v.targetSelectionRange instanceof types.Range);603assert.ok(v.originSelectionRange instanceof types.Range);604}605}606});607});608});609610// --- implementation611612test('Implementation, invalid arguments', function () {613const promises = [614assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider')),615assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider', null)),616assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider', undefined)),617assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider', true, false))618];619620return Promise.all(promises);621});622623test('Implementation, back and forth', function () {624625disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{626provideImplementation(doc: any): any {627return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));628}629}));630disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{631provideImplementation(doc: any): any {632// duplicate result will get removed633return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));634}635}));636disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{637provideImplementation(doc: any): any {638return [639new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),640new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),641new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),642];643}644}));645646return rpcProtocol.sync().then(() => {647return commands.executeCommand<vscode.Location[]>('vscode.executeImplementationProvider', model.uri, new types.Position(0, 0)).then(values => {648assert.strictEqual(values.length, 4);649for (const v of values) {650assert.ok(v.uri instanceof URI);651assert.ok(v.range instanceof types.Range);652}653});654});655});656657test('Implementation Definition Link', () => {658disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{659provideImplementation(doc: any): (vscode.Location | vscode.LocationLink)[] {660return [661new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),662{ targetUri: doc.uri, targetRange: new types.Range(1, 0, 0, 0), targetSelectionRange: new types.Range(1, 1, 1, 1), originSelectionRange: new types.Range(2, 2, 2, 2) }663];664}665}));666667return rpcProtocol.sync().then(() => {668return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeImplementationProvider', model.uri, new types.Position(0, 0)).then(values => {669assert.strictEqual(values.length, 2);670for (const v of values) {671if (isLocation(v)) {672assert.ok(v.uri instanceof URI);673assert.ok(v.range instanceof types.Range);674} else {675assert.ok(v.targetUri instanceof URI);676assert.ok(v.targetRange instanceof types.Range);677assert.ok(v.targetSelectionRange instanceof types.Range);678assert.ok(v.originSelectionRange instanceof types.Range);679}680}681});682});683});684685// --- references686687test('reference search, back and forth', function () {688689disposables.push(extHost.registerReferenceProvider(nullExtensionDescription, defaultSelector, <vscode.ReferenceProvider>{690provideReferences() {691return [692new types.Location(URI.parse('some:uri/path'), new types.Range(0, 1, 0, 5))693];694}695}));696697return commands.executeCommand<vscode.Location[]>('vscode.executeReferenceProvider', model.uri, new types.Position(0, 0)).then(values => {698assert.strictEqual(values.length, 1);699const [first] = values;700assert.strictEqual(first.uri.toString(), 'some:uri/path');701assert.strictEqual(first.range.start.line, 0);702assert.strictEqual(first.range.start.character, 1);703assert.strictEqual(first.range.end.line, 0);704assert.strictEqual(first.range.end.character, 5);705});706});707708// --- document highlights709710test('"vscode.executeDocumentHighlights" API has stopped returning DocumentHighlight[]#200056', async function () {711712713disposables.push(extHost.registerDocumentHighlightProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentHighlightProvider>{714provideDocumentHighlights() {715return [716new types.DocumentHighlight(new types.Range(0, 17, 0, 25), types.DocumentHighlightKind.Read)717];718}719}));720721await rpcProtocol.sync();722723return commands.executeCommand<vscode.DocumentHighlight[]>('vscode.executeDocumentHighlights', model.uri, new types.Position(0, 0)).then(values => {724assert.ok(Array.isArray(values));725assert.strictEqual(values.length, 1);726const [first] = values;727assert.strictEqual(first.range.start.line, 0);728assert.strictEqual(first.range.start.character, 17);729assert.strictEqual(first.range.end.line, 0);730assert.strictEqual(first.range.end.character, 25);731});732733});734735// --- outline736737test('Outline, back and forth', function () {738disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{739provideDocumentSymbols(): any {740return [741new types.SymbolInformation('testing1', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)),742new types.SymbolInformation('testing2', types.SymbolKind.Enum, new types.Range(0, 1, 0, 3)),743];744}745}));746747return rpcProtocol.sync().then(() => {748return commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => {749assert.strictEqual(values.length, 2);750const [first, second] = values;751assert.strictEqual(first instanceof types.SymbolInformation, true);752assert.strictEqual(second instanceof types.SymbolInformation, true);753assert.strictEqual(first.name, 'testing2');754assert.strictEqual(second.name, 'testing1');755});756});757});758759test('vscode.executeDocumentSymbolProvider command only returns SymbolInformation[] rather than DocumentSymbol[] #57984', function () {760disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{761provideDocumentSymbols(): any {762return [763new types.SymbolInformation('SymbolInformation', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0))764];765}766}));767disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{768provideDocumentSymbols(): any {769const root = new types.DocumentSymbol('DocumentSymbol', 'DocumentSymbol#detail', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0));770root.children = [new types.DocumentSymbol('DocumentSymbol#child', 'DocumentSymbol#detail#child', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0))];771return [root];772}773}));774775return rpcProtocol.sync().then(() => {776return commands.executeCommand<(vscode.SymbolInformation & vscode.DocumentSymbol)[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => {777assert.strictEqual(values.length, 2);778const [first, second] = values;779assert.strictEqual(first instanceof types.SymbolInformation, true);780assert.strictEqual(first instanceof types.DocumentSymbol, false);781assert.strictEqual(second instanceof types.SymbolInformation, true);782assert.strictEqual(first.name, 'DocumentSymbol');783assert.strictEqual(first.children.length, 1);784assert.strictEqual(second.name, 'SymbolInformation');785});786});787});788789// --- suggest790791testApiCmd('triggerCharacter is null when completion provider is called programmatically #159914', async function () {792793let actualContext: vscode.CompletionContext | undefined;794795disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{796provideCompletionItems(_doc, _pos, _tok, context): any {797actualContext = context;798return [];799}800}, []));801802await rpcProtocol.sync();803804await commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4));805806assert.ok(actualContext);807assert.deepStrictEqual(actualContext, { triggerKind: types.CompletionTriggerKind.Invoke, triggerCharacter: undefined });808809});810811testApiCmd('Suggest, back and forth', async function () {812813disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{814provideCompletionItems(): any {815const a = new types.CompletionItem('item1');816a.documentation = new types.MarkdownString('hello_md_string');817const b = new types.CompletionItem('item2');818b.textEdit = types.TextEdit.replace(new types.Range(0, 4, 0, 8), 'foo'); // overwite after819const c = new types.CompletionItem('item3');820c.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 6), 'foobar'); // overwite before & after821822// snippet string!823const d = new types.CompletionItem('item4');824d.range = new types.Range(0, 1, 0, 4);// overwite before825d.insertText = new types.SnippetString('foo$0bar');826return [a, b, c, d];827}828}, []));829830await rpcProtocol.sync();831832const list = await commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4));833assert.ok(list instanceof types.CompletionList);834const values = list.items;835assert.ok(Array.isArray(values));836assert.strictEqual(values.length, 4);837const [first, second, third, fourth] = values;838assert.strictEqual(first.label, 'item1');839assert.strictEqual(first.textEdit, undefined); // no text edit, default ranges840assert.ok(!types.Range.isRange(first.range));841assert.strictEqual((<types.MarkdownString>first.documentation).value, 'hello_md_string');842assert.strictEqual(second.label, 'item2');843assert.strictEqual(second.textEdit!.newText, 'foo');844assert.strictEqual(second.textEdit!.range.start.line, 0);845assert.strictEqual(second.textEdit!.range.start.character, 4);846assert.strictEqual(second.textEdit!.range.end.line, 0);847assert.strictEqual(second.textEdit!.range.end.character, 8);848assert.strictEqual(third.label, 'item3');849assert.strictEqual(third.textEdit!.newText, 'foobar');850assert.strictEqual(third.textEdit!.range.start.line, 0);851assert.strictEqual(third.textEdit!.range.start.character, 1);852assert.strictEqual(third.textEdit!.range.end.line, 0);853assert.strictEqual(third.textEdit!.range.end.character, 6);854assert.strictEqual(fourth.label, 'item4');855assert.strictEqual(fourth.textEdit, undefined);856const range: any = fourth.range!;857assert.ok(types.Range.isRange(range));858assert.strictEqual(range.start.line, 0);859assert.strictEqual(range.start.character, 1);860assert.strictEqual(range.end.line, 0);861assert.strictEqual(range.end.character, 4);862assert.ok(fourth.insertText instanceof types.SnippetString);863assert.strictEqual((<types.SnippetString>fourth.insertText).value, 'foo$0bar');864865});866867testApiCmd('Suggest, return CompletionList !array', async function () {868869disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{870provideCompletionItems(): any {871const a = new types.CompletionItem('item1');872const b = new types.CompletionItem('item2');873// eslint-disable-next-line local/code-no-any-casts874return new types.CompletionList(<any>[a, b], true);875}876}, []));877878await rpcProtocol.sync();879880const list = await commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4));881882assert.ok(list instanceof types.CompletionList);883assert.strictEqual(list.isIncomplete, true);884});885886testApiCmd('Suggest, resolve completion items', async function () {887888889let resolveCount = 0;890891disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{892provideCompletionItems(): any {893const a = new types.CompletionItem('item1');894const b = new types.CompletionItem('item2');895const c = new types.CompletionItem('item3');896const d = new types.CompletionItem('item4');897return new types.CompletionList([a, b, c, d], false);898},899resolveCompletionItem(item) {900resolveCount += 1;901return item;902}903}, []));904905await rpcProtocol.sync();906907const list = await commands.executeCommand<vscode.CompletionList>(908'vscode.executeCompletionItemProvider',909model.uri,910new types.Position(0, 4),911undefined,9122 // maxItemsToResolve913);914915assert.ok(list instanceof types.CompletionList);916assert.strictEqual(resolveCount, 2);917918});919920testApiCmd('"vscode.executeCompletionItemProvider" doesnot return a preselect field #53749', async function () {921922923924disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{925provideCompletionItems(): any {926const a = new types.CompletionItem('item1');927a.preselect = true;928const b = new types.CompletionItem('item2');929const c = new types.CompletionItem('item3');930c.preselect = true;931const d = new types.CompletionItem('item4');932return new types.CompletionList([a, b, c, d], false);933}934}, []));935936await rpcProtocol.sync();937938const list = await commands.executeCommand<vscode.CompletionList>(939'vscode.executeCompletionItemProvider',940model.uri,941new types.Position(0, 4),942undefined943);944945assert.ok(list instanceof types.CompletionList);946assert.strictEqual(list.items.length, 4);947948const [a, b, c, d] = list.items;949assert.strictEqual(a.preselect, true);950assert.strictEqual(b.preselect, undefined);951assert.strictEqual(c.preselect, true);952assert.strictEqual(d.preselect, undefined);953});954955testApiCmd('executeCompletionItemProvider doesn\'t capture commitCharacters #58228', async function () {956disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{957provideCompletionItems(): any {958const a = new types.CompletionItem('item1');959a.commitCharacters = ['a', 'b'];960const b = new types.CompletionItem('item2');961return new types.CompletionList([a, b], false);962}963}, []));964965await rpcProtocol.sync();966967const list = await commands.executeCommand<vscode.CompletionList>(968'vscode.executeCompletionItemProvider',969model.uri,970new types.Position(0, 4),971undefined972);973974assert.ok(list instanceof types.CompletionList);975assert.strictEqual(list.items.length, 2);976977const [a, b] = list.items;978assert.deepStrictEqual(a.commitCharacters, ['a', 'b']);979assert.strictEqual(b.commitCharacters, undefined);980});981982testApiCmd('vscode.executeCompletionItemProvider returns the wrong CompletionItemKinds in insiders #95715', async function () {983disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{984provideCompletionItems(): any {985return [986new types.CompletionItem('My Method', types.CompletionItemKind.Method),987new types.CompletionItem('My Property', types.CompletionItemKind.Property),988];989}990}, []));991992await rpcProtocol.sync();993994const list = await commands.executeCommand<vscode.CompletionList>(995'vscode.executeCompletionItemProvider',996model.uri,997new types.Position(0, 4),998undefined999);10001001assert.ok(list instanceof types.CompletionList);1002assert.strictEqual(list.items.length, 2);10031004const [a, b] = list.items;1005assert.strictEqual(a.kind, types.CompletionItemKind.Method);1006assert.strictEqual(b.kind, types.CompletionItemKind.Property);1007});10081009// --- signatureHelp10101011test('Parameter Hints, back and forth', async () => {1012disposables.push(extHost.registerSignatureHelpProvider(nullExtensionDescription, defaultSelector, new class implements vscode.SignatureHelpProvider {1013provideSignatureHelp(_document: vscode.TextDocument, _position: vscode.Position, _token: vscode.CancellationToken, context: vscode.SignatureHelpContext): vscode.SignatureHelp {1014return {1015activeSignature: 0,1016activeParameter: 1,1017signatures: [1018{1019label: 'abc',1020documentation: `${context.triggerKind === 1 /* vscode.SignatureHelpTriggerKind.Invoke */ ? 'invoked' : 'unknown'} ${context.triggerCharacter}`,1021parameters: []1022}1023]1024};1025}1026}, []));10271028await rpcProtocol.sync();10291030const firstValue = await commands.executeCommand<vscode.SignatureHelp>('vscode.executeSignatureHelpProvider', model.uri, new types.Position(0, 1), ',');1031assert.strictEqual(firstValue.activeSignature, 0);1032assert.strictEqual(firstValue.activeParameter, 1);1033assert.strictEqual(firstValue.signatures.length, 1);1034assert.strictEqual(firstValue.signatures[0].label, 'abc');1035assert.strictEqual(firstValue.signatures[0].documentation, 'invoked ,');1036});10371038// --- quickfix10391040testApiCmd('QuickFix, back and forth', function () {1041disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1042provideCodeActions(): vscode.Command[] {1043return [{ command: 'testing', title: 'Title', arguments: [1, 2, true] }];1044}1045}));10461047return rpcProtocol.sync().then(() => {1048return commands.executeCommand<vscode.Command[]>('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => {1049assert.strictEqual(value.length, 1);1050const [first] = value;1051assert.strictEqual(first.title, 'Title');1052assert.strictEqual(first.command, 'testing');1053assert.deepStrictEqual(first.arguments, [1, 2, true]);1054});1055});1056});10571058testApiCmd('vscode.executeCodeActionProvider results seem to be missing their `command` property #45124', function () {1059disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1060provideCodeActions(document, range): vscode.CodeAction[] {1061return [{1062command: {1063arguments: [document, range],1064command: 'command',1065title: 'command_title',1066},1067kind: types.CodeActionKind.Empty.append('foo'),1068title: 'title',1069}];1070}1071}));10721073return rpcProtocol.sync().then(() => {1074return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => {1075assert.strictEqual(value.length, 1);1076const [first] = value;1077assert.ok(first.command);1078assert.strictEqual(first.command.command, 'command');1079assert.strictEqual(first.command.title, 'command_title');1080assert.strictEqual(first.kind!.value, 'foo');1081assert.strictEqual(first.title, 'title');10821083});1084});1085});10861087testApiCmd('vscode.executeCodeActionProvider passes Range to provider although Selection is passed in #77997', function () {1088disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1089provideCodeActions(document, rangeOrSelection): vscode.CodeAction[] {1090return [{1091command: {1092arguments: [document, rangeOrSelection],1093command: 'command',1094title: 'command_title',1095},1096kind: types.CodeActionKind.Empty.append('foo'),1097title: 'title',1098}];1099}1100}));11011102const selection = new types.Selection(0, 0, 1, 1);11031104return rpcProtocol.sync().then(() => {1105return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, selection).then(value => {1106assert.strictEqual(value.length, 1);1107const [first] = value;1108assert.ok(first.command);1109assert.ok(first.command.arguments![1] instanceof types.Selection);1110assert.ok(first.command.arguments![1].isEqual(selection));1111});1112});1113});11141115testApiCmd('vscode.executeCodeActionProvider results seem to be missing their `isPreferred` property #78098', function () {1116disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1117provideCodeActions(document, rangeOrSelection): vscode.CodeAction[] {1118return [{1119command: {1120arguments: [document, rangeOrSelection],1121command: 'command',1122title: 'command_title',1123},1124kind: types.CodeActionKind.Empty.append('foo'),1125title: 'title',1126isPreferred: true1127}];1128}1129}));11301131const selection = new types.Selection(0, 0, 1, 1);11321133return rpcProtocol.sync().then(() => {1134return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, selection).then(value => {1135assert.strictEqual(value.length, 1);1136const [first] = value;1137assert.strictEqual(first.isPreferred, true);1138});1139});1140});11411142testApiCmd('resolving code action', async function () {11431144let didCallResolve = 0;1145class MyAction extends types.CodeAction { }11461147disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1148provideCodeActions(document, rangeOrSelection): vscode.CodeAction[] {1149return [new MyAction('title', types.CodeActionKind.Empty.append('foo'))];1150},1151resolveCodeAction(action): vscode.CodeAction {1152assert.ok(action instanceof MyAction);11531154didCallResolve += 1;1155action.title = 'resolved title';1156action.edit = new types.WorkspaceEdit();1157return action;1158}1159}));11601161const selection = new types.Selection(0, 0, 1, 1);11621163await rpcProtocol.sync();11641165const value = await commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, selection, undefined, 1000);1166assert.strictEqual(didCallResolve, 1);1167assert.strictEqual(value.length, 1);11681169const [first] = value;1170assert.strictEqual(first.title, 'title'); // does NOT change1171assert.ok(first.edit); // is set1172});11731174// --- code lens11751176testApiCmd('CodeLens, back and forth', function () {11771178const complexArg = {1179foo() { },1180bar() { },1181big: extHost1182};11831184disposables.push(extHost.registerCodeLensProvider(nullExtensionDescription, defaultSelector, <vscode.CodeLensProvider>{1185provideCodeLenses(): any {1186return [new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Title', command: 'cmd', arguments: [1, true, complexArg] })];1187}1188}));11891190return rpcProtocol.sync().then(() => {1191return commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri).then(value => {1192assert.strictEqual(value.length, 1);1193const [first] = value;11941195assert.strictEqual(first.command!.title, 'Title');1196assert.strictEqual(first.command!.command, 'cmd');1197assert.strictEqual(first.command!.arguments![0], 1);1198assert.strictEqual(first.command!.arguments![1], true);1199assert.strictEqual(first.command!.arguments![2], complexArg);1200});1201});1202});12031204testApiCmd('CodeLens, resolve', async function () {12051206let resolveCount = 0;12071208disposables.push(extHost.registerCodeLensProvider(nullExtensionDescription, defaultSelector, <vscode.CodeLensProvider>{1209provideCodeLenses(): any {1210return [1211new types.CodeLens(new types.Range(0, 0, 1, 1)),1212new types.CodeLens(new types.Range(0, 0, 1, 1)),1213new types.CodeLens(new types.Range(0, 0, 1, 1)),1214new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Already resolved', command: 'fff' })1215];1216},1217resolveCodeLens(codeLens: types.CodeLens) {1218codeLens.command = { title: resolveCount.toString(), command: 'resolved' };1219resolveCount += 1;1220return codeLens;1221}1222}));12231224await rpcProtocol.sync();12251226let value = await commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri, 2);12271228assert.strictEqual(value.length, 3); // the resolve argument defines the number of results being returned1229assert.strictEqual(resolveCount, 2);12301231resolveCount = 0;1232value = await commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri);12331234assert.strictEqual(value.length, 4);1235assert.strictEqual(resolveCount, 0);1236});12371238testApiCmd('Links, back and forth', function () {12391240disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{1241provideDocumentLinks(): any {1242return [new types.DocumentLink(new types.Range(0, 0, 0, 20), URI.parse('foo:bar'))];1243}1244}));12451246return rpcProtocol.sync().then(() => {1247return commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri).then(value => {1248assert.strictEqual(value.length, 1);1249const [first] = value;12501251assert.strictEqual(first.target + '', 'foo:bar');1252assert.strictEqual(first.range.start.line, 0);1253assert.strictEqual(first.range.start.character, 0);1254assert.strictEqual(first.range.end.line, 0);1255assert.strictEqual(first.range.end.character, 20);1256});1257});1258});12591260testApiCmd('What\'s the condition for DocumentLink target to be undefined? #106308', async function () {1261disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{1262provideDocumentLinks(): any {1263return [new types.DocumentLink(new types.Range(0, 0, 0, 20), undefined)];1264},1265resolveDocumentLink(link) {1266link.target = URI.parse('foo:bar');1267return link;1268}1269}));12701271await rpcProtocol.sync();12721273const links1 = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri);1274assert.strictEqual(links1.length, 1);1275assert.strictEqual(links1[0].target, undefined);12761277const links2 = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri, 1000);1278assert.strictEqual(links2.length, 1);1279assert.strictEqual(links2[0].target!.toString(), URI.parse('foo:bar').toString());12801281});12821283testApiCmd('DocumentLink[] vscode.executeLinkProvider returns lack tooltip #213970', async function () {1284disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{1285provideDocumentLinks(): any {1286const link = new types.DocumentLink(new types.Range(0, 0, 0, 20), URI.parse('foo:bar'));1287link.tooltip = 'Link Tooltip';1288return [link];1289}1290}));12911292await rpcProtocol.sync();12931294const links1 = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri);1295assert.strictEqual(links1.length, 1);1296assert.strictEqual(links1[0].tooltip, 'Link Tooltip');1297});129812991300test('Color provider', function () {13011302disposables.push(extHost.registerColorProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentColorProvider>{1303provideDocumentColors(): vscode.ColorInformation[] {1304return [new types.ColorInformation(new types.Range(0, 0, 0, 20), new types.Color(0.1, 0.2, 0.3, 0.4))];1305},1306provideColorPresentations(): vscode.ColorPresentation[] {1307const cp = new types.ColorPresentation('#ABC');1308cp.textEdit = types.TextEdit.replace(new types.Range(1, 0, 1, 20), '#ABC');1309cp.additionalTextEdits = [types.TextEdit.insert(new types.Position(2, 20), '*')];1310return [cp];1311}1312}));13131314return rpcProtocol.sync().then(() => {1315return commands.executeCommand<vscode.ColorInformation[]>('vscode.executeDocumentColorProvider', model.uri).then(value => {1316assert.strictEqual(value.length, 1);1317const [first] = value;13181319assert.strictEqual(first.color.red, 0.1);1320assert.strictEqual(first.color.green, 0.2);1321assert.strictEqual(first.color.blue, 0.3);1322assert.strictEqual(first.color.alpha, 0.4);1323assert.strictEqual(first.range.start.line, 0);1324assert.strictEqual(first.range.start.character, 0);1325assert.strictEqual(first.range.end.line, 0);1326assert.strictEqual(first.range.end.character, 20);1327});1328}).then(() => {1329const color = new types.Color(0.5, 0.6, 0.7, 0.8);1330const range = new types.Range(0, 0, 0, 20);1331return commands.executeCommand<vscode.ColorPresentation[]>('vscode.executeColorPresentationProvider', color, { uri: model.uri, range }).then(value => {1332assert.strictEqual(value.length, 1);1333const [first] = value;13341335assert.strictEqual(first.label, '#ABC');1336assert.strictEqual(first.textEdit!.newText, '#ABC');1337assert.strictEqual(first.textEdit!.range.start.line, 1);1338assert.strictEqual(first.textEdit!.range.start.character, 0);1339assert.strictEqual(first.textEdit!.range.end.line, 1);1340assert.strictEqual(first.textEdit!.range.end.character, 20);1341assert.strictEqual(first.additionalTextEdits!.length, 1);1342assert.strictEqual(first.additionalTextEdits![0].range.start.line, 2);1343assert.strictEqual(first.additionalTextEdits![0].range.start.character, 20);1344assert.strictEqual(first.additionalTextEdits![0].range.end.line, 2);1345assert.strictEqual(first.additionalTextEdits![0].range.end.character, 20);1346});1347});1348});13491350test('"TypeError: e.onCancellationRequested is not a function" calling hover provider in Insiders #54174', function () {13511352disposables.push(extHost.registerHoverProvider(nullExtensionDescription, defaultSelector, <vscode.HoverProvider>{1353provideHover(): any {1354return new types.Hover('fofofofo');1355}1356}));13571358return rpcProtocol.sync().then(() => {1359return commands.executeCommand<vscode.Hover[]>('vscode.executeHoverProvider', model.uri, new types.Position(1, 1)).then(value => {1360assert.strictEqual(value.length, 1);1361assert.strictEqual(value[0].contents.length, 1);1362});1363});1364});13651366// --- inline hints13671368testApiCmd('Inlay Hints, back and forth', async function () {1369disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1370provideInlayHints() {1371return [new types.InlayHint(new types.Position(0, 1), 'Foo')];1372}1373}));13741375await rpcProtocol.sync();13761377const value = await commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', model.uri, new types.Range(0, 0, 20, 20));1378assert.strictEqual(value.length, 1);13791380const [first] = value;1381assert.strictEqual(first.label, 'Foo');1382assert.strictEqual(first.position.line, 0);1383assert.strictEqual(first.position.character, 1);1384});13851386testApiCmd('Inline Hints, merge', async function () {1387disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1388provideInlayHints() {1389const part = new types.InlayHintLabelPart('Bar');1390part.tooltip = 'part_tooltip';1391part.command = { command: 'cmd', title: 'part' };1392const hint = new types.InlayHint(new types.Position(10, 11), [part]);1393hint.tooltip = 'hint_tooltip';1394hint.paddingLeft = true;1395hint.paddingRight = false;1396return [hint];1397}1398}));13991400disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1401provideInlayHints() {1402const hint = new types.InlayHint(new types.Position(0, 1), 'Foo', types.InlayHintKind.Parameter);1403hint.textEdits = [types.TextEdit.insert(new types.Position(0, 0), 'Hello')];1404return [hint];1405}1406}));14071408await rpcProtocol.sync();14091410const value = await commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', model.uri, new types.Range(0, 0, 20, 20));1411assert.strictEqual(value.length, 2);14121413const [first, second] = value;1414assert.strictEqual(first.label, 'Foo');1415assert.strictEqual(first.position.line, 0);1416assert.strictEqual(first.position.character, 1);1417assert.strictEqual(first.textEdits?.length, 1);1418assert.strictEqual(first.textEdits[0].newText, 'Hello');14191420assert.strictEqual(second.position.line, 10);1421assert.strictEqual(second.position.character, 11);1422assert.strictEqual(second.paddingLeft, true);1423assert.strictEqual(second.paddingRight, false);1424assert.strictEqual(second.tooltip, 'hint_tooltip');14251426const label = (<types.InlayHintLabelPart[]>second.label)[0];1427assertType(label instanceof types.InlayHintLabelPart);1428assert.strictEqual(label.value, 'Bar');1429assert.strictEqual(label.tooltip, 'part_tooltip');1430assert.strictEqual(label.command?.command, 'cmd');1431assert.strictEqual(label.command?.title, 'part');1432});14331434testApiCmd('Inline Hints, bad provider', async function () {1435disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1436provideInlayHints() {1437return [new types.InlayHint(new types.Position(0, 1), 'Foo')];1438}1439}));1440disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1441provideInlayHints() {1442throw new Error();1443}1444}));14451446await rpcProtocol.sync();14471448const value = await commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', model.uri, new types.Range(0, 0, 20, 20));1449assert.strictEqual(value.length, 1);14501451const [first] = value;1452assert.strictEqual(first.label, 'Foo');1453assert.strictEqual(first.position.line, 0);1454assert.strictEqual(first.position.character, 1);1455});14561457// --- selection ranges14581459test('Selection Range, back and forth', async function () {14601461disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{1462provideSelectionRanges() {1463return [1464new types.SelectionRange(new types.Range(0, 10, 0, 18), new types.SelectionRange(new types.Range(0, 2, 0, 20))),1465];1466}1467}));14681469await rpcProtocol.sync();1470const value = await commands.executeCommand<vscode.SelectionRange[]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]);1471assert.strictEqual(value.length, 1);1472assert.ok(value[0].parent);1473});14741475// --- call hierarchy14761477test('CallHierarchy, back and forth', async function () {14781479disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyProvider {14801481prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.CallHierarchyItem> {1482return new types.CallHierarchyItem(types.SymbolKind.Constant, 'ROOT', 'ROOT', document.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0));1483}14841485provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyIncomingCall[]> {14861487return [new types.CallHierarchyIncomingCall(1488new types.CallHierarchyItem(types.SymbolKind.Constant, 'INCOMING', 'INCOMING', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0)),1489[new types.Range(0, 0, 0, 0)]1490)];1491}14921493provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyOutgoingCall[]> {1494return [new types.CallHierarchyOutgoingCall(1495new types.CallHierarchyItem(types.SymbolKind.Constant, 'OUTGOING', 'OUTGOING', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0)),1496[new types.Range(0, 0, 0, 0)]1497)];1498}1499}));15001501await rpcProtocol.sync();15021503const root = await commands.executeCommand<vscode.CallHierarchyItem[]>('vscode.prepareCallHierarchy', model.uri, new types.Position(0, 0));15041505assert.ok(Array.isArray(root));1506assert.strictEqual(root.length, 1);1507assert.strictEqual(root[0].name, 'ROOT');15081509const incoming = await commands.executeCommand<vscode.CallHierarchyIncomingCall[]>('vscode.provideIncomingCalls', root[0]);1510assert.strictEqual(incoming.length, 1);1511assert.strictEqual(incoming[0].from.name, 'INCOMING');15121513const outgoing = await commands.executeCommand<vscode.CallHierarchyOutgoingCall[]>('vscode.provideOutgoingCalls', root[0]);1514assert.strictEqual(outgoing.length, 1);1515assert.strictEqual(outgoing[0].to.name, 'OUTGOING');1516});15171518test('prepareCallHierarchy throws TypeError if clangd returns empty result #137415', async function () {15191520disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyProvider {1521prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.CallHierarchyItem[]> {1522return [];1523}1524provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyIncomingCall[]> {1525return [];1526}1527provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyOutgoingCall[]> {1528return [];1529}1530}));15311532await rpcProtocol.sync();15331534const root = await commands.executeCommand<vscode.CallHierarchyItem[]>('vscode.prepareCallHierarchy', model.uri, new types.Position(0, 0));15351536assert.ok(Array.isArray(root));1537assert.strictEqual(root.length, 0);1538});15391540// --- type hierarchy15411542test('TypeHierarchy, back and forth', async function () {154315441545disposables.push(extHost.registerTypeHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.TypeHierarchyProvider {1546prepareTypeHierarchy(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TypeHierarchyItem[]> {1547return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'ROOT', 'ROOT', document.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))];1548}1549provideTypeHierarchySupertypes(item: vscode.TypeHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TypeHierarchyItem[]> {1550return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'SUPER', 'SUPER', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))];1551}1552provideTypeHierarchySubtypes(item: vscode.TypeHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TypeHierarchyItem[]> {1553return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'SUB', 'SUB', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))];1554}1555}));15561557await rpcProtocol.sync();15581559const root = await commands.executeCommand<vscode.TypeHierarchyItem[]>('vscode.prepareTypeHierarchy', model.uri, new types.Position(0, 0));15601561assert.ok(Array.isArray(root));1562assert.strictEqual(root.length, 1);1563assert.strictEqual(root[0].name, 'ROOT');15641565const incoming = await commands.executeCommand<vscode.TypeHierarchyItem[]>('vscode.provideSupertypes', root[0]);1566assert.strictEqual(incoming.length, 1);1567assert.strictEqual(incoming[0].name, 'SUPER');15681569const outgoing = await commands.executeCommand<vscode.TypeHierarchyItem[]>('vscode.provideSubtypes', root[0]);1570assert.strictEqual(outgoing.length, 1);1571assert.strictEqual(outgoing[0].name, 'SUB');1572});15731574test('selectionRangeProvider on inner array always returns outer array #91852', async function () {15751576disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{1577provideSelectionRanges(_doc, positions) {1578const [first] = positions;1579return [1580new types.SelectionRange(new types.Range(first.line, first.character, first.line, first.character)),1581];1582}1583}));15841585await rpcProtocol.sync();1586const value = await commands.executeCommand<vscode.SelectionRange[]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]);1587assert.strictEqual(value.length, 1);1588assert.strictEqual(value[0].range.start.line, 0);1589assert.strictEqual(value[0].range.start.character, 10);1590assert.strictEqual(value[0].range.end.line, 0);1591assert.strictEqual(value[0].range.end.character, 10);1592});15931594test('more element test of selectionRangeProvider on inner array always returns outer array #91852', async function () {15951596disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{1597provideSelectionRanges(_doc, positions) {1598const [first, second] = positions;1599return [1600new types.SelectionRange(new types.Range(first.line, first.character, first.line, first.character)),1601new types.SelectionRange(new types.Range(second.line, second.character, second.line, second.character)),1602];1603}1604}));16051606await rpcProtocol.sync();1607const value = await commands.executeCommand<vscode.SelectionRange[]>(1608'vscode.executeSelectionRangeProvider',1609model.uri,1610[new types.Position(0, 0), new types.Position(0, 10)]1611);1612assert.strictEqual(value.length, 2);1613assert.strictEqual(value[0].range.start.line, 0);1614assert.strictEqual(value[0].range.start.character, 0);1615assert.strictEqual(value[0].range.end.line, 0);1616assert.strictEqual(value[0].range.end.character, 0);1617assert.strictEqual(value[1].range.start.line, 0);1618assert.strictEqual(value[1].range.start.character, 10);1619assert.strictEqual(value[1].range.end.line, 0);1620assert.strictEqual(value[1].range.end.character, 10);1621});1622});162316241625