Path: blob/main/src/vs/workbench/api/test/browser/extHostApiCommands.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 '../../../../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';6768function assertRejects(fn: () => Promise<any>, message: string = 'Expected rejection') {69return fn().then(() => assert.ok(false, message), _err => assert.ok(true));70}7172function isLocation(value: vscode.Location | vscode.LocationLink): value is vscode.Location {73const candidate = value as vscode.Location;74return candidate && candidate.uri instanceof URI && candidate.range instanceof types.Range;75}7677suite('ExtHostLanguageFeatureCommands', function () {78const defaultSelector = { scheme: 'far' };79let model: ITextModel;8081let insta: TestInstantiationService;82let rpcProtocol: TestRPCProtocol;83let extHost: ExtHostLanguageFeatures;84let mainThread: MainThreadLanguageFeatures;85let commands: ExtHostCommands;86let disposables: vscode.Disposable[] = [];8788let originalErrorHandler: (e: any) => any;8990suiteSetup(() => {91model = createTextModel(92[93'This is the first line',94'This is the second line',95'This is the third line',96].join('\n'),97undefined,98undefined,99URI.parse('far://testing/file.b'));100originalErrorHandler = errorHandler.getUnexpectedErrorHandler();101setUnexpectedErrorHandler(() => { });102103// Use IInstantiationService to get typechecking when instantiating104rpcProtocol = new TestRPCProtocol();105const services = new ServiceCollection();106services.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {107override asCanonicalUri(uri: URI): URI {108return uri;109}110});111services.set(ILanguageFeaturesService, new SyncDescriptor(LanguageFeaturesService));112services.set(IExtensionService, new class extends mock<IExtensionService>() {113override async activateByEvent() {114115}116override activationEventIsDone(activationEvent: string): boolean {117return true;118}119});120services.set(ICommandService, new SyncDescriptor(class extends mock<ICommandService>() {121122override executeCommand(id: string, ...args: any): any {123const command = CommandsRegistry.getCommands().get(id);124if (!command) {125return Promise.reject(new Error(id + ' NOT known'));126}127const { handler } = command;128return Promise.resolve(insta.invokeFunction(handler, ...args));129}130}));131services.set(IEnvironmentService, new class extends mock<IEnvironmentService>() {132override isBuilt: boolean = true;133override isExtensionDevelopment: boolean = false;134});135services.set(IMarkerService, new MarkerService());136services.set(ILogService, new SyncDescriptor(NullLogService));137services.set(ILanguageFeatureDebounceService, new SyncDescriptor(LanguageFeatureDebounceService));138services.set(IModelService, new class extends mock<IModelService>() {139override getModel() { return model; }140override onModelRemoved = Event.None;141});142services.set(ITextModelService, new class extends mock<ITextModelService>() {143override async createModelReference() {144return new ImmortalReference<IResolvedTextEditorModel>(new class extends mock<IResolvedTextEditorModel>() {145override textEditorModel = model;146});147}148});149services.set(IEditorWorkerService, new class extends mock<IEditorWorkerService>() {150override async computeMoreMinimalEdits(_uri: any, edits: any) {151return edits || undefined;152}153});154services.set(ILanguageFeatureDebounceService, new SyncDescriptor(LanguageFeatureDebounceService));155services.set(IOutlineModelService, new SyncDescriptor(OutlineModelService));156services.set(IConfigurationService, new TestConfigurationService());157158insta = new TestInstantiationService(services);159160const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());161extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({162addedDocuments: [{163isDirty: false,164versionId: model.getVersionId(),165languageId: model.getLanguageId(),166uri: model.uri,167lines: model.getValue().split(model.getEOL()),168EOL: model.getEOL(),169encoding: 'utf8'170}]171});172const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);173rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments);174175commands = new ExtHostCommands(rpcProtocol, new NullLogService(), new class extends mock<IExtHostTelemetry>() {176override onExtensionError(): boolean {177return true;178}179});180rpcProtocol.set(ExtHostContext.ExtHostCommands, commands);181rpcProtocol.set(MainContext.MainThreadCommands, insta.createInstance(MainThreadCommands, rpcProtocol));182ExtHostApiCommands.register(commands);183184const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService(), new class extends mock<IExtHostFileSystemInfo>() { }, extHostDocumentsAndEditors);185rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics);186187extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService, new class extends mock<IExtHostTelemetry>() {188override onExtensionError(): boolean {189return true;190}191});192rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost);193194mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, insta.createInstance(MainThreadLanguageFeatures, rpcProtocol));195196// forcefully create the outline service so that `ensureNoDisposablesAreLeakedInTestSuite` doesn't bark197insta.get(IOutlineModelService);198199return rpcProtocol.sync();200});201202suiteTeardown(() => {203setUnexpectedErrorHandler(originalErrorHandler);204model.dispose();205mainThread.dispose();206207(<OutlineModelService>insta.get(IOutlineModelService)).dispose();208insta.dispose();209});210211teardown(() => {212disposables = dispose(disposables);213return rpcProtocol.sync();214});215216ensureNoDisposablesAreLeakedInTestSuite();217218// --- workspace symbols219220function testApiCmd(name: string, fn: () => Promise<any>) {221test(name, async function () {222await runWithFakedTimers({}, async () => {223await fn();224await timeout(10000); // API commands for things that allow commands dispose their result delay. This is to be nice225// because otherwise properties like command are disposed too early226});227});228229}230231test('WorkspaceSymbols, invalid arguments', function () {232const promises = [233assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider')),234assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', null)),235assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', undefined)),236assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', true))237];238return Promise.all(promises);239});240241test('WorkspaceSymbols, back and forth', function () {242243disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, <vscode.WorkspaceSymbolProvider>{244provideWorkspaceSymbols(query): any {245return [246new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first')),247new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/second'))248];249}250}));251252disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, <vscode.WorkspaceSymbolProvider>{253provideWorkspaceSymbols(query): any {254return [255new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first'))256];257}258}));259260return rpcProtocol.sync().then(() => {261return commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', 'testing').then(value => {262263assert.strictEqual(value.length, 2); // de-duped264for (const info of value) {265assert.strictEqual(info instanceof types.SymbolInformation, true);266assert.strictEqual(info.name, 'testing');267assert.strictEqual(info.kind, types.SymbolKind.Array);268}269});270});271});272273test('executeWorkspaceSymbolProvider should accept empty string, #39522', async function () {274275disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, {276provideWorkspaceSymbols(): vscode.SymbolInformation[] {277return [new types.SymbolInformation('hello', types.SymbolKind.Array, new types.Range(0, 0, 0, 0), URI.parse('foo:bar')) as vscode.SymbolInformation];278}279}));280281await rpcProtocol.sync();282let symbols = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', '');283assert.strictEqual(symbols.length, 1);284285await rpcProtocol.sync();286symbols = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', '*');287assert.strictEqual(symbols.length, 1);288});289290// --- formatting291test('executeFormatDocumentProvider, back and forth', async function () {292293disposables.push(extHost.registerDocumentFormattingEditProvider(nullExtensionDescription, defaultSelector, new class implements vscode.DocumentFormattingEditProvider {294provideDocumentFormattingEdits() {295return [types.TextEdit.insert(new types.Position(0, 0), '42')];296}297}));298299await rpcProtocol.sync();300const edits = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeFormatDocumentProvider', model.uri);301assert.strictEqual(edits.length, 1);302});303304305// --- rename306test('vscode.prepareRename', async function () {307disposables.push(extHost.registerRenameProvider(nullExtensionDescription, defaultSelector, new class implements vscode.RenameProvider {308309prepareRename(document: vscode.TextDocument, position: vscode.Position) {310return {311range: new types.Range(0, 12, 0, 24),312placeholder: 'foooPlaceholder'313};314}315316provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string) {317const edit = new types.WorkspaceEdit();318edit.insert(document.uri, <types.Position>position, newName);319return edit;320}321}));322323await rpcProtocol.sync();324325const data = await commands.executeCommand<{ range: vscode.Range; placeholder: string }>('vscode.prepareRename', model.uri, new types.Position(0, 12));326327assert.ok(data);328assert.strictEqual(data.placeholder, 'foooPlaceholder');329assert.strictEqual(data.range.start.line, 0);330assert.strictEqual(data.range.start.character, 12);331assert.strictEqual(data.range.end.line, 0);332assert.strictEqual(data.range.end.character, 24);333334});335336test('vscode.executeDocumentRenameProvider', async function () {337disposables.push(extHost.registerRenameProvider(nullExtensionDescription, defaultSelector, new class implements vscode.RenameProvider {338provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string) {339const edit = new types.WorkspaceEdit();340edit.insert(document.uri, <types.Position>position, newName);341return edit;342}343}));344345await rpcProtocol.sync();346347const edit = await commands.executeCommand<vscode.WorkspaceEdit>('vscode.executeDocumentRenameProvider', model.uri, new types.Position(0, 12), 'newNameOfThis');348349assert.ok(edit);350assert.strictEqual(edit.has(model.uri), true);351const textEdits = edit.get(model.uri);352assert.strictEqual(textEdits.length, 1);353assert.strictEqual(textEdits[0].newText, 'newNameOfThis');354});355356// --- definition357358test('Definition, invalid arguments', function () {359const promises = [360assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider')),361assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', null)),362assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', undefined)),363assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', true, false))364];365366return Promise.all(promises);367});368369test('Definition, back and forth', function () {370371disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{372provideDefinition(doc: any): any {373return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));374}375}));376disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{377provideDefinition(doc: any): any {378// duplicate result will get removed379return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));380}381}));382disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{383provideDefinition(doc: any): any {384return [385new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),386new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),387new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),388];389}390}));391392return rpcProtocol.sync().then(() => {393return commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {394assert.strictEqual(values.length, 4);395for (const v of values) {396assert.ok(v.uri instanceof URI);397assert.ok(v.range instanceof types.Range);398}399});400});401});402403404test('Definition, back and forth (sorting & de-deduping)', function () {405406disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{407provideDefinition(doc: any): any {408return new types.Location(URI.parse('file:///b'), new types.Range(1, 0, 0, 0));409}410}));411disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{412provideDefinition(doc: any): any {413// duplicate result will get removed414return new types.Location(URI.parse('file:///b'), new types.Range(1, 0, 0, 0));415}416}));417disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{418provideDefinition(doc: any): any {419return [420new types.Location(URI.parse('file:///a'), new types.Range(2, 0, 0, 0)),421new types.Location(URI.parse('file:///c'), new types.Range(3, 0, 0, 0)),422new types.Location(URI.parse('file:///d'), new types.Range(4, 0, 0, 0)),423];424}425}));426427return rpcProtocol.sync().then(() => {428return commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {429assert.strictEqual(values.length, 4);430431assert.strictEqual(values[0].uri.path, '/a');432assert.strictEqual(values[1].uri.path, '/b');433assert.strictEqual(values[2].uri.path, '/c');434assert.strictEqual(values[3].uri.path, '/d');435});436});437});438439test('Definition Link', () => {440disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{441provideDefinition(doc: any): (vscode.Location | vscode.LocationLink)[] {442return [443new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),444{ 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) }445];446}447}));448449return rpcProtocol.sync().then(() => {450return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {451assert.strictEqual(values.length, 2);452for (const v of values) {453if (isLocation(v)) {454assert.ok(v.uri instanceof URI);455assert.ok(v.range instanceof types.Range);456} else {457assert.ok(v.targetUri instanceof URI);458assert.ok(v.targetRange instanceof types.Range);459assert.ok(v.targetSelectionRange instanceof types.Range);460assert.ok(v.originSelectionRange instanceof types.Range);461}462}463});464});465});466467// --- declaration468469test('Declaration, back and forth', function () {470471disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{472provideDeclaration(doc: any): any {473return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));474}475}));476disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{477provideDeclaration(doc: any): any {478// duplicate result will get removed479return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));480}481}));482disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{483provideDeclaration(doc: any): any {484return [485new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),486new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),487new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),488];489}490}));491492return rpcProtocol.sync().then(() => {493return commands.executeCommand<vscode.Location[]>('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => {494assert.strictEqual(values.length, 4);495for (const v of values) {496assert.ok(v.uri instanceof URI);497assert.ok(v.range instanceof types.Range);498}499});500});501});502503test('Declaration Link', () => {504disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{505provideDeclaration(doc: any): (vscode.Location | vscode.LocationLink)[] {506return [507new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),508{ 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) }509];510}511}));512513return rpcProtocol.sync().then(() => {514return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => {515assert.strictEqual(values.length, 2);516for (const v of values) {517if (isLocation(v)) {518assert.ok(v.uri instanceof URI);519assert.ok(v.range instanceof types.Range);520} else {521assert.ok(v.targetUri instanceof URI);522assert.ok(v.targetRange instanceof types.Range);523assert.ok(v.targetSelectionRange instanceof types.Range);524assert.ok(v.originSelectionRange instanceof types.Range);525}526}527});528});529});530531// --- type definition532533test('Type Definition, invalid arguments', function () {534const promises = [535assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider')),536assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', null)),537assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', undefined)),538assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', true, false))539];540541return Promise.all(promises);542});543544test('Type Definition, back and forth', function () {545546disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{547provideTypeDefinition(doc: any): any {548return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));549}550}));551disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{552provideTypeDefinition(doc: any): any {553// duplicate result will get removed554return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));555}556}));557disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{558provideTypeDefinition(doc: any): any {559return [560new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),561new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),562new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),563];564}565}));566567return rpcProtocol.sync().then(() => {568return commands.executeCommand<vscode.Location[]>('vscode.executeTypeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {569assert.strictEqual(values.length, 4);570for (const v of values) {571assert.ok(v.uri instanceof URI);572assert.ok(v.range instanceof types.Range);573}574});575});576});577578test('Type Definition Link', () => {579disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{580provideTypeDefinition(doc: any): (vscode.Location | vscode.LocationLink)[] {581return [582new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),583{ 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) }584];585}586}));587588return rpcProtocol.sync().then(() => {589return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeTypeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {590assert.strictEqual(values.length, 2);591for (const v of values) {592if (isLocation(v)) {593assert.ok(v.uri instanceof URI);594assert.ok(v.range instanceof types.Range);595} else {596assert.ok(v.targetUri instanceof URI);597assert.ok(v.targetRange instanceof types.Range);598assert.ok(v.targetSelectionRange instanceof types.Range);599assert.ok(v.originSelectionRange instanceof types.Range);600}601}602});603});604});605606// --- implementation607608test('Implementation, invalid arguments', function () {609const promises = [610assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider')),611assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider', null)),612assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider', undefined)),613assertRejects(() => commands.executeCommand('vscode.executeImplementationProvider', true, false))614];615616return Promise.all(promises);617});618619test('Implementation, back and forth', function () {620621disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{622provideImplementation(doc: any): any {623return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));624}625}));626disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{627provideImplementation(doc: any): any {628// duplicate result will get removed629return new types.Location(doc.uri, new types.Range(1, 0, 0, 0));630}631}));632disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{633provideImplementation(doc: any): any {634return [635new types.Location(doc.uri, new types.Range(2, 0, 0, 0)),636new types.Location(doc.uri, new types.Range(3, 0, 0, 0)),637new types.Location(doc.uri, new types.Range(4, 0, 0, 0)),638];639}640}));641642return rpcProtocol.sync().then(() => {643return commands.executeCommand<vscode.Location[]>('vscode.executeImplementationProvider', model.uri, new types.Position(0, 0)).then(values => {644assert.strictEqual(values.length, 4);645for (const v of values) {646assert.ok(v.uri instanceof URI);647assert.ok(v.range instanceof types.Range);648}649});650});651});652653test('Implementation Definition Link', () => {654disposables.push(extHost.registerImplementationProvider(nullExtensionDescription, defaultSelector, <vscode.ImplementationProvider>{655provideImplementation(doc: any): (vscode.Location | vscode.LocationLink)[] {656return [657new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),658{ 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) }659];660}661}));662663return rpcProtocol.sync().then(() => {664return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeImplementationProvider', model.uri, new types.Position(0, 0)).then(values => {665assert.strictEqual(values.length, 2);666for (const v of values) {667if (isLocation(v)) {668assert.ok(v.uri instanceof URI);669assert.ok(v.range instanceof types.Range);670} else {671assert.ok(v.targetUri instanceof URI);672assert.ok(v.targetRange instanceof types.Range);673assert.ok(v.targetSelectionRange instanceof types.Range);674assert.ok(v.originSelectionRange instanceof types.Range);675}676}677});678});679});680681// --- references682683test('reference search, back and forth', function () {684685disposables.push(extHost.registerReferenceProvider(nullExtensionDescription, defaultSelector, <vscode.ReferenceProvider>{686provideReferences() {687return [688new types.Location(URI.parse('some:uri/path'), new types.Range(0, 1, 0, 5))689];690}691}));692693return commands.executeCommand<vscode.Location[]>('vscode.executeReferenceProvider', model.uri, new types.Position(0, 0)).then(values => {694assert.strictEqual(values.length, 1);695const [first] = values;696assert.strictEqual(first.uri.toString(), 'some:uri/path');697assert.strictEqual(first.range.start.line, 0);698assert.strictEqual(first.range.start.character, 1);699assert.strictEqual(first.range.end.line, 0);700assert.strictEqual(first.range.end.character, 5);701});702});703704// --- document highlights705706test('"vscode.executeDocumentHighlights" API has stopped returning DocumentHighlight[]#200056', async function () {707708709disposables.push(extHost.registerDocumentHighlightProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentHighlightProvider>{710provideDocumentHighlights() {711return [712new types.DocumentHighlight(new types.Range(0, 17, 0, 25), types.DocumentHighlightKind.Read)713];714}715}));716717await rpcProtocol.sync();718719return commands.executeCommand<vscode.DocumentHighlight[]>('vscode.executeDocumentHighlights', model.uri, new types.Position(0, 0)).then(values => {720assert.ok(Array.isArray(values));721assert.strictEqual(values.length, 1);722const [first] = values;723assert.strictEqual(first.range.start.line, 0);724assert.strictEqual(first.range.start.character, 17);725assert.strictEqual(first.range.end.line, 0);726assert.strictEqual(first.range.end.character, 25);727});728729});730731// --- outline732733test('Outline, back and forth', function () {734disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{735provideDocumentSymbols(): any {736return [737new types.SymbolInformation('testing1', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)),738new types.SymbolInformation('testing2', types.SymbolKind.Enum, new types.Range(0, 1, 0, 3)),739];740}741}));742743return rpcProtocol.sync().then(() => {744return commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => {745assert.strictEqual(values.length, 2);746const [first, second] = values;747assert.strictEqual(first instanceof types.SymbolInformation, true);748assert.strictEqual(second instanceof types.SymbolInformation, true);749assert.strictEqual(first.name, 'testing2');750assert.strictEqual(second.name, 'testing1');751});752});753});754755test('vscode.executeDocumentSymbolProvider command only returns SymbolInformation[] rather than DocumentSymbol[] #57984', function () {756disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{757provideDocumentSymbols(): any {758return [759new types.SymbolInformation('SymbolInformation', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0))760];761}762}));763disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{764provideDocumentSymbols(): any {765const root = new types.DocumentSymbol('DocumentSymbol', 'DocumentSymbol#detail', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0));766root.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))];767return [root];768}769}));770771return rpcProtocol.sync().then(() => {772return commands.executeCommand<(vscode.SymbolInformation & vscode.DocumentSymbol)[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => {773assert.strictEqual(values.length, 2);774const [first, second] = values;775assert.strictEqual(first instanceof types.SymbolInformation, true);776assert.strictEqual(first instanceof types.DocumentSymbol, false);777assert.strictEqual(second instanceof types.SymbolInformation, true);778assert.strictEqual(first.name, 'DocumentSymbol');779assert.strictEqual(first.children.length, 1);780assert.strictEqual(second.name, 'SymbolInformation');781});782});783});784785// --- suggest786787testApiCmd('triggerCharacter is null when completion provider is called programmatically #159914', async function () {788789let actualContext: vscode.CompletionContext | undefined;790791disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{792provideCompletionItems(_doc, _pos, _tok, context): any {793actualContext = context;794return [];795}796}, []));797798await rpcProtocol.sync();799800await commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4));801802assert.ok(actualContext);803assert.deepStrictEqual(actualContext, { triggerKind: types.CompletionTriggerKind.Invoke, triggerCharacter: undefined });804805});806807testApiCmd('Suggest, back and forth', async function () {808809disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{810provideCompletionItems(): any {811const a = new types.CompletionItem('item1');812a.documentation = new types.MarkdownString('hello_md_string');813const b = new types.CompletionItem('item2');814b.textEdit = types.TextEdit.replace(new types.Range(0, 4, 0, 8), 'foo'); // overwite after815const c = new types.CompletionItem('item3');816c.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 6), 'foobar'); // overwite before & after817818// snippet string!819const d = new types.CompletionItem('item4');820d.range = new types.Range(0, 1, 0, 4);// overwite before821d.insertText = new types.SnippetString('foo$0bar');822return [a, b, c, d];823}824}, []));825826await rpcProtocol.sync();827828const list = await commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4));829assert.ok(list instanceof types.CompletionList);830const values = list.items;831assert.ok(Array.isArray(values));832assert.strictEqual(values.length, 4);833const [first, second, third, fourth] = values;834assert.strictEqual(first.label, 'item1');835assert.strictEqual(first.textEdit, undefined); // no text edit, default ranges836assert.ok(!types.Range.isRange(first.range));837assert.strictEqual((<types.MarkdownString>first.documentation).value, 'hello_md_string');838assert.strictEqual(second.label, 'item2');839assert.strictEqual(second.textEdit!.newText, 'foo');840assert.strictEqual(second.textEdit!.range.start.line, 0);841assert.strictEqual(second.textEdit!.range.start.character, 4);842assert.strictEqual(second.textEdit!.range.end.line, 0);843assert.strictEqual(second.textEdit!.range.end.character, 8);844assert.strictEqual(third.label, 'item3');845assert.strictEqual(third.textEdit!.newText, 'foobar');846assert.strictEqual(third.textEdit!.range.start.line, 0);847assert.strictEqual(third.textEdit!.range.start.character, 1);848assert.strictEqual(third.textEdit!.range.end.line, 0);849assert.strictEqual(third.textEdit!.range.end.character, 6);850assert.strictEqual(fourth.label, 'item4');851assert.strictEqual(fourth.textEdit, undefined);852const range: any = fourth.range!;853assert.ok(types.Range.isRange(range));854assert.strictEqual(range.start.line, 0);855assert.strictEqual(range.start.character, 1);856assert.strictEqual(range.end.line, 0);857assert.strictEqual(range.end.character, 4);858assert.ok(fourth.insertText instanceof types.SnippetString);859assert.strictEqual((<types.SnippetString>fourth.insertText).value, 'foo$0bar');860861});862863testApiCmd('Suggest, return CompletionList !array', async function () {864865disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{866provideCompletionItems(): any {867const a = new types.CompletionItem('item1');868const b = new types.CompletionItem('item2');869return new types.CompletionList(<any>[a, b], true);870}871}, []));872873await rpcProtocol.sync();874875const list = await commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4));876877assert.ok(list instanceof types.CompletionList);878assert.strictEqual(list.isIncomplete, true);879});880881testApiCmd('Suggest, resolve completion items', async function () {882883884let resolveCount = 0;885886disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{887provideCompletionItems(): any {888const a = new types.CompletionItem('item1');889const b = new types.CompletionItem('item2');890const c = new types.CompletionItem('item3');891const d = new types.CompletionItem('item4');892return new types.CompletionList([a, b, c, d], false);893},894resolveCompletionItem(item) {895resolveCount += 1;896return item;897}898}, []));899900await rpcProtocol.sync();901902const list = await commands.executeCommand<vscode.CompletionList>(903'vscode.executeCompletionItemProvider',904model.uri,905new types.Position(0, 4),906undefined,9072 // maxItemsToResolve908);909910assert.ok(list instanceof types.CompletionList);911assert.strictEqual(resolveCount, 2);912913});914915testApiCmd('"vscode.executeCompletionItemProvider" doesnot return a preselect field #53749', async function () {916917918919disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{920provideCompletionItems(): any {921const a = new types.CompletionItem('item1');922a.preselect = true;923const b = new types.CompletionItem('item2');924const c = new types.CompletionItem('item3');925c.preselect = true;926const d = new types.CompletionItem('item4');927return new types.CompletionList([a, b, c, d], false);928}929}, []));930931await rpcProtocol.sync();932933const list = await commands.executeCommand<vscode.CompletionList>(934'vscode.executeCompletionItemProvider',935model.uri,936new types.Position(0, 4),937undefined938);939940assert.ok(list instanceof types.CompletionList);941assert.strictEqual(list.items.length, 4);942943const [a, b, c, d] = list.items;944assert.strictEqual(a.preselect, true);945assert.strictEqual(b.preselect, undefined);946assert.strictEqual(c.preselect, true);947assert.strictEqual(d.preselect, undefined);948});949950testApiCmd('executeCompletionItemProvider doesn\'t capture commitCharacters #58228', async function () {951disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{952provideCompletionItems(): any {953const a = new types.CompletionItem('item1');954a.commitCharacters = ['a', 'b'];955const b = new types.CompletionItem('item2');956return new types.CompletionList([a, b], false);957}958}, []));959960await rpcProtocol.sync();961962const list = await commands.executeCommand<vscode.CompletionList>(963'vscode.executeCompletionItemProvider',964model.uri,965new types.Position(0, 4),966undefined967);968969assert.ok(list instanceof types.CompletionList);970assert.strictEqual(list.items.length, 2);971972const [a, b] = list.items;973assert.deepStrictEqual(a.commitCharacters, ['a', 'b']);974assert.strictEqual(b.commitCharacters, undefined);975});976977testApiCmd('vscode.executeCompletionItemProvider returns the wrong CompletionItemKinds in insiders #95715', async function () {978disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{979provideCompletionItems(): any {980return [981new types.CompletionItem('My Method', types.CompletionItemKind.Method),982new types.CompletionItem('My Property', types.CompletionItemKind.Property),983];984}985}, []));986987await rpcProtocol.sync();988989const list = await commands.executeCommand<vscode.CompletionList>(990'vscode.executeCompletionItemProvider',991model.uri,992new types.Position(0, 4),993undefined994);995996assert.ok(list instanceof types.CompletionList);997assert.strictEqual(list.items.length, 2);998999const [a, b] = list.items;1000assert.strictEqual(a.kind, types.CompletionItemKind.Method);1001assert.strictEqual(b.kind, types.CompletionItemKind.Property);1002});10031004// --- signatureHelp10051006test('Parameter Hints, back and forth', async () => {1007disposables.push(extHost.registerSignatureHelpProvider(nullExtensionDescription, defaultSelector, new class implements vscode.SignatureHelpProvider {1008provideSignatureHelp(_document: vscode.TextDocument, _position: vscode.Position, _token: vscode.CancellationToken, context: vscode.SignatureHelpContext): vscode.SignatureHelp {1009return {1010activeSignature: 0,1011activeParameter: 1,1012signatures: [1013{1014label: 'abc',1015documentation: `${context.triggerKind === 1 /* vscode.SignatureHelpTriggerKind.Invoke */ ? 'invoked' : 'unknown'} ${context.triggerCharacter}`,1016parameters: []1017}1018]1019};1020}1021}, []));10221023await rpcProtocol.sync();10241025const firstValue = await commands.executeCommand<vscode.SignatureHelp>('vscode.executeSignatureHelpProvider', model.uri, new types.Position(0, 1), ',');1026assert.strictEqual(firstValue.activeSignature, 0);1027assert.strictEqual(firstValue.activeParameter, 1);1028assert.strictEqual(firstValue.signatures.length, 1);1029assert.strictEqual(firstValue.signatures[0].label, 'abc');1030assert.strictEqual(firstValue.signatures[0].documentation, 'invoked ,');1031});10321033// --- quickfix10341035testApiCmd('QuickFix, back and forth', function () {1036disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1037provideCodeActions(): vscode.Command[] {1038return [{ command: 'testing', title: 'Title', arguments: [1, 2, true] }];1039}1040}));10411042return rpcProtocol.sync().then(() => {1043return commands.executeCommand<vscode.Command[]>('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => {1044assert.strictEqual(value.length, 1);1045const [first] = value;1046assert.strictEqual(first.title, 'Title');1047assert.strictEqual(first.command, 'testing');1048assert.deepStrictEqual(first.arguments, [1, 2, true]);1049});1050});1051});10521053testApiCmd('vscode.executeCodeActionProvider results seem to be missing their `command` property #45124', function () {1054disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1055provideCodeActions(document, range): vscode.CodeAction[] {1056return [{1057command: {1058arguments: [document, range],1059command: 'command',1060title: 'command_title',1061},1062kind: types.CodeActionKind.Empty.append('foo'),1063title: 'title',1064}];1065}1066}));10671068return rpcProtocol.sync().then(() => {1069return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => {1070assert.strictEqual(value.length, 1);1071const [first] = value;1072assert.ok(first.command);1073assert.strictEqual(first.command.command, 'command');1074assert.strictEqual(first.command.title, 'command_title');1075assert.strictEqual(first.kind!.value, 'foo');1076assert.strictEqual(first.title, 'title');10771078});1079});1080});10811082testApiCmd('vscode.executeCodeActionProvider passes Range to provider although Selection is passed in #77997', function () {1083disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1084provideCodeActions(document, rangeOrSelection): vscode.CodeAction[] {1085return [{1086command: {1087arguments: [document, rangeOrSelection],1088command: 'command',1089title: 'command_title',1090},1091kind: types.CodeActionKind.Empty.append('foo'),1092title: 'title',1093}];1094}1095}));10961097const selection = new types.Selection(0, 0, 1, 1);10981099return rpcProtocol.sync().then(() => {1100return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, selection).then(value => {1101assert.strictEqual(value.length, 1);1102const [first] = value;1103assert.ok(first.command);1104assert.ok(first.command.arguments![1] instanceof types.Selection);1105assert.ok(first.command.arguments![1].isEqual(selection));1106});1107});1108});11091110testApiCmd('vscode.executeCodeActionProvider results seem to be missing their `isPreferred` property #78098', function () {1111disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1112provideCodeActions(document, rangeOrSelection): vscode.CodeAction[] {1113return [{1114command: {1115arguments: [document, rangeOrSelection],1116command: 'command',1117title: 'command_title',1118},1119kind: types.CodeActionKind.Empty.append('foo'),1120title: 'title',1121isPreferred: true1122}];1123}1124}));11251126const selection = new types.Selection(0, 0, 1, 1);11271128return rpcProtocol.sync().then(() => {1129return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, selection).then(value => {1130assert.strictEqual(value.length, 1);1131const [first] = value;1132assert.strictEqual(first.isPreferred, true);1133});1134});1135});11361137testApiCmd('resolving code action', async function () {11381139let didCallResolve = 0;1140class MyAction extends types.CodeAction { }11411142disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {1143provideCodeActions(document, rangeOrSelection): vscode.CodeAction[] {1144return [new MyAction('title', types.CodeActionKind.Empty.append('foo'))];1145},1146resolveCodeAction(action): vscode.CodeAction {1147assert.ok(action instanceof MyAction);11481149didCallResolve += 1;1150action.title = 'resolved title';1151action.edit = new types.WorkspaceEdit();1152return action;1153}1154}));11551156const selection = new types.Selection(0, 0, 1, 1);11571158await rpcProtocol.sync();11591160const value = await commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, selection, undefined, 1000);1161assert.strictEqual(didCallResolve, 1);1162assert.strictEqual(value.length, 1);11631164const [first] = value;1165assert.strictEqual(first.title, 'title'); // does NOT change1166assert.ok(first.edit); // is set1167});11681169// --- code lens11701171testApiCmd('CodeLens, back and forth', function () {11721173const complexArg = {1174foo() { },1175bar() { },1176big: extHost1177};11781179disposables.push(extHost.registerCodeLensProvider(nullExtensionDescription, defaultSelector, <vscode.CodeLensProvider>{1180provideCodeLenses(): any {1181return [new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Title', command: 'cmd', arguments: [1, true, complexArg] })];1182}1183}));11841185return rpcProtocol.sync().then(() => {1186return commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri).then(value => {1187assert.strictEqual(value.length, 1);1188const [first] = value;11891190assert.strictEqual(first.command!.title, 'Title');1191assert.strictEqual(first.command!.command, 'cmd');1192assert.strictEqual(first.command!.arguments![0], 1);1193assert.strictEqual(first.command!.arguments![1], true);1194assert.strictEqual(first.command!.arguments![2], complexArg);1195});1196});1197});11981199testApiCmd('CodeLens, resolve', async function () {12001201let resolveCount = 0;12021203disposables.push(extHost.registerCodeLensProvider(nullExtensionDescription, defaultSelector, <vscode.CodeLensProvider>{1204provideCodeLenses(): any {1205return [1206new types.CodeLens(new types.Range(0, 0, 1, 1)),1207new types.CodeLens(new types.Range(0, 0, 1, 1)),1208new types.CodeLens(new types.Range(0, 0, 1, 1)),1209new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Already resolved', command: 'fff' })1210];1211},1212resolveCodeLens(codeLens: types.CodeLens) {1213codeLens.command = { title: resolveCount.toString(), command: 'resolved' };1214resolveCount += 1;1215return codeLens;1216}1217}));12181219await rpcProtocol.sync();12201221let value = await commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri, 2);12221223assert.strictEqual(value.length, 3); // the resolve argument defines the number of results being returned1224assert.strictEqual(resolveCount, 2);12251226resolveCount = 0;1227value = await commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri);12281229assert.strictEqual(value.length, 4);1230assert.strictEqual(resolveCount, 0);1231});12321233testApiCmd('Links, back and forth', function () {12341235disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{1236provideDocumentLinks(): any {1237return [new types.DocumentLink(new types.Range(0, 0, 0, 20), URI.parse('foo:bar'))];1238}1239}));12401241return rpcProtocol.sync().then(() => {1242return commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri).then(value => {1243assert.strictEqual(value.length, 1);1244const [first] = value;12451246assert.strictEqual(first.target + '', 'foo:bar');1247assert.strictEqual(first.range.start.line, 0);1248assert.strictEqual(first.range.start.character, 0);1249assert.strictEqual(first.range.end.line, 0);1250assert.strictEqual(first.range.end.character, 20);1251});1252});1253});12541255testApiCmd('What\'s the condition for DocumentLink target to be undefined? #106308', async function () {1256disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{1257provideDocumentLinks(): any {1258return [new types.DocumentLink(new types.Range(0, 0, 0, 20), undefined)];1259},1260resolveDocumentLink(link) {1261link.target = URI.parse('foo:bar');1262return link;1263}1264}));12651266await rpcProtocol.sync();12671268const links1 = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri);1269assert.strictEqual(links1.length, 1);1270assert.strictEqual(links1[0].target, undefined);12711272const links2 = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri, 1000);1273assert.strictEqual(links2.length, 1);1274assert.strictEqual(links2[0].target!.toString(), URI.parse('foo:bar').toString());12751276});12771278testApiCmd('DocumentLink[] vscode.executeLinkProvider returns lack tooltip #213970', async function () {1279disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{1280provideDocumentLinks(): any {1281const link = new types.DocumentLink(new types.Range(0, 0, 0, 20), URI.parse('foo:bar'));1282link.tooltip = 'Link Tooltip';1283return [link];1284}1285}));12861287await rpcProtocol.sync();12881289const links1 = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri);1290assert.strictEqual(links1.length, 1);1291assert.strictEqual(links1[0].tooltip, 'Link Tooltip');1292});129312941295test('Color provider', function () {12961297disposables.push(extHost.registerColorProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentColorProvider>{1298provideDocumentColors(): vscode.ColorInformation[] {1299return [new types.ColorInformation(new types.Range(0, 0, 0, 20), new types.Color(0.1, 0.2, 0.3, 0.4))];1300},1301provideColorPresentations(): vscode.ColorPresentation[] {1302const cp = new types.ColorPresentation('#ABC');1303cp.textEdit = types.TextEdit.replace(new types.Range(1, 0, 1, 20), '#ABC');1304cp.additionalTextEdits = [types.TextEdit.insert(new types.Position(2, 20), '*')];1305return [cp];1306}1307}));13081309return rpcProtocol.sync().then(() => {1310return commands.executeCommand<vscode.ColorInformation[]>('vscode.executeDocumentColorProvider', model.uri).then(value => {1311assert.strictEqual(value.length, 1);1312const [first] = value;13131314assert.strictEqual(first.color.red, 0.1);1315assert.strictEqual(first.color.green, 0.2);1316assert.strictEqual(first.color.blue, 0.3);1317assert.strictEqual(first.color.alpha, 0.4);1318assert.strictEqual(first.range.start.line, 0);1319assert.strictEqual(first.range.start.character, 0);1320assert.strictEqual(first.range.end.line, 0);1321assert.strictEqual(first.range.end.character, 20);1322});1323}).then(() => {1324const color = new types.Color(0.5, 0.6, 0.7, 0.8);1325const range = new types.Range(0, 0, 0, 20);1326return commands.executeCommand<vscode.ColorPresentation[]>('vscode.executeColorPresentationProvider', color, { uri: model.uri, range }).then(value => {1327assert.strictEqual(value.length, 1);1328const [first] = value;13291330assert.strictEqual(first.label, '#ABC');1331assert.strictEqual(first.textEdit!.newText, '#ABC');1332assert.strictEqual(first.textEdit!.range.start.line, 1);1333assert.strictEqual(first.textEdit!.range.start.character, 0);1334assert.strictEqual(first.textEdit!.range.end.line, 1);1335assert.strictEqual(first.textEdit!.range.end.character, 20);1336assert.strictEqual(first.additionalTextEdits!.length, 1);1337assert.strictEqual(first.additionalTextEdits![0].range.start.line, 2);1338assert.strictEqual(first.additionalTextEdits![0].range.start.character, 20);1339assert.strictEqual(first.additionalTextEdits![0].range.end.line, 2);1340assert.strictEqual(first.additionalTextEdits![0].range.end.character, 20);1341});1342});1343});13441345test('"TypeError: e.onCancellationRequested is not a function" calling hover provider in Insiders #54174', function () {13461347disposables.push(extHost.registerHoverProvider(nullExtensionDescription, defaultSelector, <vscode.HoverProvider>{1348provideHover(): any {1349return new types.Hover('fofofofo');1350}1351}));13521353return rpcProtocol.sync().then(() => {1354return commands.executeCommand<vscode.Hover[]>('vscode.executeHoverProvider', model.uri, new types.Position(1, 1)).then(value => {1355assert.strictEqual(value.length, 1);1356assert.strictEqual(value[0].contents.length, 1);1357});1358});1359});13601361// --- inline hints13621363testApiCmd('Inlay Hints, back and forth', async function () {1364disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1365provideInlayHints() {1366return [new types.InlayHint(new types.Position(0, 1), 'Foo')];1367}1368}));13691370await rpcProtocol.sync();13711372const value = await commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', model.uri, new types.Range(0, 0, 20, 20));1373assert.strictEqual(value.length, 1);13741375const [first] = value;1376assert.strictEqual(first.label, 'Foo');1377assert.strictEqual(first.position.line, 0);1378assert.strictEqual(first.position.character, 1);1379});13801381testApiCmd('Inline Hints, merge', async function () {1382disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1383provideInlayHints() {1384const part = new types.InlayHintLabelPart('Bar');1385part.tooltip = 'part_tooltip';1386part.command = { command: 'cmd', title: 'part' };1387const hint = new types.InlayHint(new types.Position(10, 11), [part]);1388hint.tooltip = 'hint_tooltip';1389hint.paddingLeft = true;1390hint.paddingRight = false;1391return [hint];1392}1393}));13941395disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1396provideInlayHints() {1397const hint = new types.InlayHint(new types.Position(0, 1), 'Foo', types.InlayHintKind.Parameter);1398hint.textEdits = [types.TextEdit.insert(new types.Position(0, 0), 'Hello')];1399return [hint];1400}1401}));14021403await rpcProtocol.sync();14041405const value = await commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', model.uri, new types.Range(0, 0, 20, 20));1406assert.strictEqual(value.length, 2);14071408const [first, second] = value;1409assert.strictEqual(first.label, 'Foo');1410assert.strictEqual(first.position.line, 0);1411assert.strictEqual(first.position.character, 1);1412assert.strictEqual(first.textEdits?.length, 1);1413assert.strictEqual(first.textEdits[0].newText, 'Hello');14141415assert.strictEqual(second.position.line, 10);1416assert.strictEqual(second.position.character, 11);1417assert.strictEqual(second.paddingLeft, true);1418assert.strictEqual(second.paddingRight, false);1419assert.strictEqual(second.tooltip, 'hint_tooltip');14201421const label = (<types.InlayHintLabelPart[]>second.label)[0];1422assertType(label instanceof types.InlayHintLabelPart);1423assert.strictEqual(label.value, 'Bar');1424assert.strictEqual(label.tooltip, 'part_tooltip');1425assert.strictEqual(label.command?.command, 'cmd');1426assert.strictEqual(label.command?.title, 'part');1427});14281429testApiCmd('Inline Hints, bad provider', async function () {1430disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1431provideInlayHints() {1432return [new types.InlayHint(new types.Position(0, 1), 'Foo')];1433}1434}));1435disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{1436provideInlayHints() {1437throw new Error();1438}1439}));14401441await rpcProtocol.sync();14421443const value = await commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', model.uri, new types.Range(0, 0, 20, 20));1444assert.strictEqual(value.length, 1);14451446const [first] = value;1447assert.strictEqual(first.label, 'Foo');1448assert.strictEqual(first.position.line, 0);1449assert.strictEqual(first.position.character, 1);1450});14511452// --- selection ranges14531454test('Selection Range, back and forth', async function () {14551456disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{1457provideSelectionRanges() {1458return [1459new types.SelectionRange(new types.Range(0, 10, 0, 18), new types.SelectionRange(new types.Range(0, 2, 0, 20))),1460];1461}1462}));14631464await rpcProtocol.sync();1465const value = await commands.executeCommand<vscode.SelectionRange[]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]);1466assert.strictEqual(value.length, 1);1467assert.ok(value[0].parent);1468});14691470// --- call hierarchy14711472test('CallHierarchy, back and forth', async function () {14731474disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyProvider {14751476prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.CallHierarchyItem> {1477return new types.CallHierarchyItem(types.SymbolKind.Constant, 'ROOT', 'ROOT', document.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0));1478}14791480provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyIncomingCall[]> {14811482return [new types.CallHierarchyIncomingCall(1483new types.CallHierarchyItem(types.SymbolKind.Constant, 'INCOMING', 'INCOMING', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0)),1484[new types.Range(0, 0, 0, 0)]1485)];1486}14871488provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyOutgoingCall[]> {1489return [new types.CallHierarchyOutgoingCall(1490new types.CallHierarchyItem(types.SymbolKind.Constant, 'OUTGOING', 'OUTGOING', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0)),1491[new types.Range(0, 0, 0, 0)]1492)];1493}1494}));14951496await rpcProtocol.sync();14971498const root = await commands.executeCommand<vscode.CallHierarchyItem[]>('vscode.prepareCallHierarchy', model.uri, new types.Position(0, 0));14991500assert.ok(Array.isArray(root));1501assert.strictEqual(root.length, 1);1502assert.strictEqual(root[0].name, 'ROOT');15031504const incoming = await commands.executeCommand<vscode.CallHierarchyIncomingCall[]>('vscode.provideIncomingCalls', root[0]);1505assert.strictEqual(incoming.length, 1);1506assert.strictEqual(incoming[0].from.name, 'INCOMING');15071508const outgoing = await commands.executeCommand<vscode.CallHierarchyOutgoingCall[]>('vscode.provideOutgoingCalls', root[0]);1509assert.strictEqual(outgoing.length, 1);1510assert.strictEqual(outgoing[0].to.name, 'OUTGOING');1511});15121513test('prepareCallHierarchy throws TypeError if clangd returns empty result #137415', async function () {15141515disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyProvider {1516prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult<vscode.CallHierarchyItem[]> {1517return [];1518}1519provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyIncomingCall[]> {1520return [];1521}1522provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyOutgoingCall[]> {1523return [];1524}1525}));15261527await rpcProtocol.sync();15281529const root = await commands.executeCommand<vscode.CallHierarchyItem[]>('vscode.prepareCallHierarchy', model.uri, new types.Position(0, 0));15301531assert.ok(Array.isArray(root));1532assert.strictEqual(root.length, 0);1533});15341535// --- type hierarchy15361537test('TypeHierarchy, back and forth', async function () {153815391540disposables.push(extHost.registerTypeHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.TypeHierarchyProvider {1541prepareTypeHierarchy(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TypeHierarchyItem[]> {1542return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'ROOT', 'ROOT', document.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))];1543}1544provideTypeHierarchySupertypes(item: vscode.TypeHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TypeHierarchyItem[]> {1545return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'SUPER', 'SUPER', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))];1546}1547provideTypeHierarchySubtypes(item: vscode.TypeHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.TypeHierarchyItem[]> {1548return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'SUB', 'SUB', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))];1549}1550}));15511552await rpcProtocol.sync();15531554const root = await commands.executeCommand<vscode.TypeHierarchyItem[]>('vscode.prepareTypeHierarchy', model.uri, new types.Position(0, 0));15551556assert.ok(Array.isArray(root));1557assert.strictEqual(root.length, 1);1558assert.strictEqual(root[0].name, 'ROOT');15591560const incoming = await commands.executeCommand<vscode.TypeHierarchyItem[]>('vscode.provideSupertypes', root[0]);1561assert.strictEqual(incoming.length, 1);1562assert.strictEqual(incoming[0].name, 'SUPER');15631564const outgoing = await commands.executeCommand<vscode.TypeHierarchyItem[]>('vscode.provideSubtypes', root[0]);1565assert.strictEqual(outgoing.length, 1);1566assert.strictEqual(outgoing[0].name, 'SUB');1567});15681569test('selectionRangeProvider on inner array always returns outer array #91852', async function () {15701571disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{1572provideSelectionRanges(_doc, positions) {1573const [first] = positions;1574return [1575new types.SelectionRange(new types.Range(first.line, first.character, first.line, first.character)),1576];1577}1578}));15791580await rpcProtocol.sync();1581const value = await commands.executeCommand<vscode.SelectionRange[]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]);1582assert.strictEqual(value.length, 1);1583assert.strictEqual(value[0].range.start.line, 0);1584assert.strictEqual(value[0].range.start.character, 10);1585assert.strictEqual(value[0].range.end.line, 0);1586assert.strictEqual(value[0].range.end.character, 10);1587});15881589test('more element test of selectionRangeProvider on inner array always returns outer array #91852', async function () {15901591disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{1592provideSelectionRanges(_doc, positions) {1593const [first, second] = positions;1594return [1595new types.SelectionRange(new types.Range(first.line, first.character, first.line, first.character)),1596new types.SelectionRange(new types.Range(second.line, second.character, second.line, second.character)),1597];1598}1599}));16001601await rpcProtocol.sync();1602const value = await commands.executeCommand<vscode.SelectionRange[]>(1603'vscode.executeSelectionRangeProvider',1604model.uri,1605[new types.Position(0, 0), new types.Position(0, 10)]1606);1607assert.strictEqual(value.length, 2);1608assert.strictEqual(value[0].range.start.line, 0);1609assert.strictEqual(value[0].range.start.character, 0);1610assert.strictEqual(value[0].range.end.line, 0);1611assert.strictEqual(value[0].range.end.character, 0);1612assert.strictEqual(value[1].range.start.line, 0);1613assert.strictEqual(value[1].range.start.character, 10);1614assert.strictEqual(value[1].range.end.line, 0);1615assert.strictEqual(value[1].range.end.character, 10);1616});1617});161816191620