diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript/src/features/definitionProviderBase.ts index 27f3bccfd54c3..3cf6690101571 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript/src/features/definitionProviderBase.ts @@ -14,7 +14,12 @@ export default class TypeScriptDefinitionProviderBase { constructor( private client: ITypescriptServiceClient) { } - protected getSymbolLocations(definitionType: 'definition' | 'implementation', document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { + protected getSymbolLocations( + definitionType: 'definition' | 'implementation' | 'typeDefinition', + document: TextDocument, + position: Position, + token: CancellationToken | boolean + ): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { return Promise.resolve(null); diff --git a/extensions/typescript/src/features/typeDefinitionProvider.ts b/extensions/typescript/src/features/typeDefinitionProvider.ts new file mode 100644 index 0000000000000..edaccf0bf3330 --- /dev/null +++ b/extensions/typescript/src/features/typeDefinitionProvider.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { TypeDefinitionProvider, TextDocument, Position, CancellationToken, Definition } from 'vscode'; + +import { ITypescriptServiceClient } from '../typescriptService'; +import DefinitionProviderBase from './definitionProviderBase'; + +export default class TypeScriptTypeDefinitionProvider extends DefinitionProviderBase implements TypeDefinitionProvider { + constructor(client: ITypescriptServiceClient) { + super(client); + } + + public provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { + return this.getSymbolLocations('typeDefinition', document, position, token); + } +} \ No newline at end of file diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index b30325e5427d0..2fe25d90d57f6 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -26,6 +26,7 @@ import { ITypescriptServiceClientHost } from './typescriptService'; import HoverProvider from './features/hoverProvider'; import DefinitionProvider from './features/definitionProvider'; import ImplementationProvider from './features/ImplementationProvider'; +import TypeDefintionProvider from './features/typeDefinitionProvider'; import DocumentHighlightProvider from './features/documentHighlightProvider'; import ReferenceProvider from './features/referenceProvider'; import DocumentSymbolProvider from './features/documentSymbolProvider'; @@ -155,6 +156,7 @@ class LanguageProvider { let hoverProvider = new HoverProvider(client); let definitionProvider = new DefinitionProvider(client); let implementationProvider = new ImplementationProvider(client); + const typeDefinitionProvider = new TypeDefintionProvider(client); let documentHighlightProvider = new DocumentHighlightProvider(client); let referenceProvider = new ReferenceProvider(client); let documentSymbolProvider = new DocumentSymbolProvider(client); @@ -181,6 +183,9 @@ class LanguageProvider { // TODO: TS 2.1.5 returns incorrect results for implementation locations. languages.registerImplementationProvider(selector, implementationProvider); } + if (client.apiVersion.has213Features()) { + languages.registerTypeDefinitionProvider(selector, typeDefinitionProvider); + } languages.registerDocumentHighlightProvider(selector, documentHighlightProvider); languages.registerReferenceProvider(selector, referenceProvider); languages.registerDocumentSymbolProvider(selector, documentSymbolProvider); diff --git a/extensions/typescript/src/typescriptService.ts b/extensions/typescript/src/typescriptService.ts index cdaf4777a8b87..7316240dc073e 100644 --- a/extensions/typescript/src/typescriptService.ts +++ b/extensions/typescript/src/typescriptService.ts @@ -88,6 +88,7 @@ export interface ITypescriptServiceClient { execute(commant: 'signatureHelp', args: Proto.SignatureHelpRequestArgs, token?: CancellationToken): Promise; execute(command: 'definition', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; execute(command: 'implementation', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; + execute(command: 'typeDefinition', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; execute(command: 'references', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; execute(command: 'navto', args: Proto.NavtoRequestArgs, token?: CancellationToken): Promise; execute(command: 'navbar', args: Proto.FileRequestArgs, token?: CancellationToken): Promise; diff --git a/src/vs/editor/browser/standalone/standaloneLanguages.ts b/src/vs/editor/browser/standalone/standaloneLanguages.ts index 7a9eb227618ba..3a6bf37eabe05 100644 --- a/src/vs/editor/browser/standalone/standaloneLanguages.ts +++ b/src/vs/editor/browser/standalone/standaloneLanguages.ts @@ -275,12 +275,19 @@ export function registerDefinitionProvider(languageId: string, provider: modes.D } /** - * Register a type implementation provider (used by e.g. go to implementation). + * Register a implementation provider (used by e.g. go to implementation). */ export function registerImplementationProvider(languageId: string, provider: modes.ImplementationProvider): IDisposable { return modes.ImplementationProviderRegistry.register(languageId, provider); } +/** + * Register a type definition provider (used by e.g. go to type definition). + */ +export function registerTypeDefinitionProvider(languageId: string, provider: modes.TypeDefinitionProvider): IDisposable { + return modes.TypeDefinitionProviderRegistry.register(languageId, provider); +} + /** * Register a code lens provider (used by e.g. inline code lenses). */ @@ -682,6 +689,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages { registerDocumentHighlightProvider: registerDocumentHighlightProvider, registerDefinitionProvider: registerDefinitionProvider, registerImplementationProvider: registerImplementationProvider, + registerTypeDefinitionProvider: registerTypeDefinitionProvider, registerCodeLensProvider: registerCodeLensProvider, registerCodeActionProvider: registerCodeActionProvider, registerDocumentFormattingEditProvider: registerDocumentFormattingEditProvider, diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 0a862e0fd7069..7fe393ab654a3 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -3146,6 +3146,10 @@ export namespace ModeContextKeys { * @internal */ export const hasImplementationProvider = new RawContextKey('editorHasImplementationProvider', undefined); + /** + * @internal + */ + export const hasTypeDefinitionProvider = new RawContextKey('editorHasTypeDefinitionProvider', undefined); /** * @internal */ diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index d08cbfa7eb105..4ca070f66c29c 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -429,7 +429,7 @@ export interface DefinitionProvider { } /** - * The type definition provider interface defines the contract between extensions and + * The implementation provider interface defines the contract between extensions and * the go to implementation feature. */ export interface ImplementationProvider { @@ -439,6 +439,17 @@ export interface ImplementationProvider { provideImplementation(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable; } +/** + * The type definition provider interface defines the contract between extensions and + * the go to type definition feature. + */ +export interface TypeDefinitionProvider { + /** + * Provide the type definition of the symbol at the given position and document. + */ + provideTypeDefinition(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable; +} + /** * A symbol kind. */ @@ -751,6 +762,11 @@ export const DefinitionProviderRegistry = new LanguageFeatureRegistry(); +/** + * @internal + */ +export const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry(); + /** * @internal */ diff --git a/src/vs/editor/common/modes/editorModeContext.ts b/src/vs/editor/common/modes/editorModeContext.ts index ce020fb7bb469..9fc1a3e989806 100644 --- a/src/vs/editor/common/modes/editorModeContext.ts +++ b/src/vs/editor/common/modes/editorModeContext.ts @@ -21,6 +21,7 @@ export class EditorModeContext { private _hasCodeLensProvider: IContextKey; private _hasDefinitionProvider: IContextKey; private _hasImplementationProvider: IContextKey; + private _hasTypeDefinitionProvider: IContextKey; private _hasHoverProvider: IContextKey; private _hasDocumentHighlightProvider: IContextKey; private _hasDocumentSymbolProvider: IContextKey; @@ -43,6 +44,7 @@ export class EditorModeContext { this._hasCodeLensProvider = ModeContextKeys.hasCodeLensProvider.bindTo(contextKeyService); this._hasDefinitionProvider = ModeContextKeys.hasDefinitionProvider.bindTo(contextKeyService); this._hasImplementationProvider = ModeContextKeys.hasImplementationProvider.bindTo(contextKeyService); + this._hasTypeDefinitionProvider = ModeContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService); this._hasHoverProvider = ModeContextKeys.hasHoverProvider.bindTo(contextKeyService); this._hasDocumentHighlightProvider = ModeContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService); this._hasDocumentSymbolProvider = ModeContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService); @@ -63,6 +65,7 @@ export class EditorModeContext { modes.CodeLensProviderRegistry.onDidChange(this._update, this, this._disposables); modes.DefinitionProviderRegistry.onDidChange(this._update, this, this._disposables); modes.ImplementationProviderRegistry.onDidChange(this._update, this, this._disposables); + modes.TypeDefinitionProviderRegistry.onDidChange(this._update, this, this._disposables); modes.HoverProviderRegistry.onDidChange(this._update, this, this._disposables); modes.DocumentHighlightProviderRegistry.onDidChange(this._update, this, this._disposables); modes.DocumentSymbolProviderRegistry.onDidChange(this._update, this, this._disposables); @@ -86,6 +89,7 @@ export class EditorModeContext { this._hasCodeLensProvider.reset(); this._hasDefinitionProvider.reset(); this._hasImplementationProvider.reset(); + this._hasTypeDefinitionProvider.reset(); this._hasHoverProvider.reset(); this._hasDocumentHighlightProvider.reset(); this._hasDocumentSymbolProvider.reset(); @@ -109,6 +113,7 @@ export class EditorModeContext { this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model)); this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model)); + this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model)); this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model)); this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model)); this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model)); diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts index e4a0bb2647b86..18e0271ade810 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts @@ -26,7 +26,7 @@ import { editorAction, IActionOptions, ServicesAccessor, EditorAction } from 'vs import { Location, DefinitionProviderRegistry } from 'vs/editor/common/modes'; import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { getDeclarationsAtPosition, getImplementationAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; +import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/referencesController'; import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/referencesModel'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -106,7 +106,7 @@ export class DefinitionAction extends EditorAction { } protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise { - return getDeclarationsAtPosition(model, position); + return getDefinitionsAtPosition(model, position); } private _onResult(editorService: IEditorService, editor: editorCommon.ICommonCodeEditor, model: ReferencesModel) { @@ -255,7 +255,7 @@ export class GoToImplementationAction extends DefinitionAction { } protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise { - return getImplementationAtPosition(model, position); + return getImplementationsAtPosition(model, position); } } @@ -275,19 +275,70 @@ export class PeekImplementationAction extends DefinitionAction { kbOpts: { kbExpr: EditorContextKeys.TextFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F12 + } + }); + } + + protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise { + return getImplementationsAtPosition(model, position); + } +} + +@editorAction +export class GoToTypeDefintionAction extends DefinitionAction { + + public static ID = 'editor.action.goToTypeDefinition'; + + constructor() { + super(new DefinitionActionConfig(), { + id: GoToTypeDefintionAction.ID, + label: nls.localize('actions.goToTypeDefinition.label', "Go to Type Definition"), + alias: 'Go to Type Definition', + precondition: ContextKeyExpr.and( + ModeContextKeys.hasTypeDefinitionProvider, + ModeContextKeys.isInEmbeddedEditor.toNegated()), + kbOpts: { + kbExpr: EditorContextKeys.TextFocus, + primary: 0 }, menuOpts: { group: 'navigation', - order: 1.3 + order: 1.4 } }); } protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise { - return getImplementationAtPosition(model, position); + return getTypeDefinitionsAtPosition(model, position); } } +@editorAction +export class PeekTypeDefinitionAction extends DefinitionAction { + + public static ID = 'editor.action.peekTypeDefinition'; + + constructor() { + super(new DefinitionActionConfig(false, true, false), { + id: PeekTypeDefinitionAction.ID, + label: nls.localize('actions.peekTypeDefinition.label', "Peek Type Definition"), + alias: 'Peek Type Definition', + precondition: ContextKeyExpr.and( + ModeContextKeys.hasTypeDefinitionProvider, + ModeContextKeys.isInEmbeddedEditor.toNegated()), + kbOpts: { + kbExpr: EditorContextKeys.TextFocus, + primary: 0 + } + }); + } + + protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise { + return getTypeDefinitionsAtPosition(model, position); + } +} + + // --- Editor Contribution to goto definition using the mouse and a modifier key @editorContribution @@ -541,7 +592,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC return TPromise.as(null); } - return getDeclarationsAtPosition(this.editor.getModel(), target.position); + return getDefinitionsAtPosition(this.editor.getModel(), target.position); } private gotoDefinition(target: IMouseTarget, sideBySide: boolean): TPromise { diff --git a/src/vs/editor/contrib/goToDeclaration/common/goToDeclaration.ts b/src/vs/editor/contrib/goToDeclaration/common/goToDeclaration.ts index de1ea6a641ec2..61afed811363f 100644 --- a/src/vs/editor/contrib/goToDeclaration/common/goToDeclaration.ts +++ b/src/vs/editor/contrib/goToDeclaration/common/goToDeclaration.ts @@ -9,7 +9,9 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IReadOnlyModel } from 'vs/editor/common/editorCommon'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; -import { DefinitionProviderRegistry, ImplementationProviderRegistry, Location } from 'vs/editor/common/modes'; +import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry'; +import { DefinitionProviderRegistry, ImplementationProviderRegistry, TypeDefinitionProviderRegistry, Location } from 'vs/editor/common/modes'; +import { CancellationToken } from 'vs/base/common/cancellation'; import { asWinJsPromise } from 'vs/base/common/async'; import { Position } from 'vs/editor/common/core/position'; @@ -27,14 +29,18 @@ function outputResults(promises: TPromise[]) { }); } -export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Position): TPromise { - - const provider = DefinitionProviderRegistry.ordered(model); +function getDefinitions( + model: IReadOnlyModel, + position: Position, + registry: LanguageFeatureRegistry, + provide: (provider: T, model: IReadOnlyModel, position: Position, token: CancellationToken) => Location | Location[] | Thenable +): TPromise { + const provider = registry.ordered(model); // get results const promises = provider.map((provider, idx) => { return asWinJsPromise((token) => { - return provider.provideDefinition(model, position, token); + return provide(provider, model, position, token); }).then(result => { return result; }, err => { @@ -44,22 +50,25 @@ export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Posit return outputResults(promises); } -export function getImplementationAtPosition(model: IReadOnlyModel, position: Position): TPromise { - const provider = ImplementationProviderRegistry.ordered(model); +export function getDefinitionsAtPosition(model: IReadOnlyModel, position: Position): TPromise { + return getDefinitions(model, position, DefinitionProviderRegistry, (provider, model, position, token) => { + return provider.provideDefinition(model, position, token); + }); +} - // get results - const promises = provider.map((provider, idx) => { - return asWinJsPromise((token) => { - return provider.provideImplementation(model, position, token); - }).then(result => { - return result; - }, err => { - onUnexpectedExternalError(err); - }); +export function getImplementationsAtPosition(model: IReadOnlyModel, position: Position): TPromise { + return getDefinitions(model, position, ImplementationProviderRegistry, (provider, model, position, token) => { + return provider.provideImplementation(model, position, token); + }); +} + +export function getTypeDefinitionsAtPosition(model: IReadOnlyModel, position: Position): TPromise { + return getDefinitions(model, position, TypeDefinitionProviderRegistry, (provider, model, position, token) => { + return provider.provideTypeDefinition(model, position, token); }); - return outputResults(promises); } -CommonEditorRegistry.registerDefaultLanguageCommand('_executeDefinitionProvider', getDeclarationsAtPosition); -CommonEditorRegistry.registerDefaultLanguageCommand('_executeImplementationProvider', getImplementationAtPosition); \ No newline at end of file +CommonEditorRegistry.registerDefaultLanguageCommand('_executeDefinitionProvider', getDefinitionsAtPosition); +CommonEditorRegistry.registerDefaultLanguageCommand('_executeImplementationProvider', getImplementationsAtPosition); +CommonEditorRegistry.registerDefaultLanguageCommand('_executeTypeDefinitionProvider', getTypeDefinitionsAtPosition); \ No newline at end of file diff --git a/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts b/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts index f9eebeabc3731..c0f9851597b98 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts @@ -73,7 +73,7 @@ export class ReferenceAction extends EditorAction { }, menuOpts: { group: 'navigation', - order: 1.3 + order: 1.5 } }); } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 2be64bae096b5..832a15a0f1195 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3953,10 +3953,15 @@ declare module monaco.languages { export function registerDefinitionProvider(languageId: string, provider: DefinitionProvider): IDisposable; /** - * Register a type implementation provider (used by e.g. go to implementation). + * Register a implementation provider (used by e.g. go to implementation). */ export function registerImplementationProvider(languageId: string, provider: ImplementationProvider): IDisposable; + /** + * Register a type definition provider (used by e.g. go to type definition). + */ + export function registerTypeDefinitionProvider(languageId: string, provider: TypeDefinitionProvider): IDisposable; + /** * Register a code lens provider (used by e.g. inline code lenses). */ @@ -4570,7 +4575,7 @@ declare module monaco.languages { } /** - * The type definition provider interface defines the contract between extensions and + * The implementation provider interface defines the contract between extensions and * the go to implementation feature. */ export interface ImplementationProvider { @@ -4580,6 +4585,17 @@ declare module monaco.languages { provideImplementation(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable; } + /** + * The type definition provider interface defines the contract between extensions and + * the go to type definition feature. + */ + export interface TypeDefinitionProvider { + /** + * Provide the type definition of the symbol at the given position and document. + */ + provideTypeDefinition(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable; + } + /** * A symbol kind. */ diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 97d981ba5308a..bc15b0e4420ec 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1650,7 +1650,7 @@ declare module 'vscode' { } /** - * The type implemenetation provider interface defines the contract between extensions and + * The implemenetation provider interface defines the contract between extensions and * the go to implementation feature. */ export interface ImplementationProvider { @@ -1667,6 +1667,24 @@ declare module 'vscode' { provideImplementation(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; } + /** + * The type definition provider defines the contract between extensions and + * the go to type definition feature. + */ + export interface TypeDefinitionProvider { + + /** + * Provide the type definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + /** * MarkedString can be used to render human readable text. It is either a markdown string * or a code-block that provides a language and a code snippet. Note that @@ -4173,6 +4191,19 @@ declare module 'vscode' { */ export function registerImplementationProvider(selector: DocumentSelector, provider: ImplementationProvider): Disposable; + /** + * Register a type definition provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A type definition provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTypeDefinitionProvider(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable; + /** * Register a hover provider. * diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 510beaa0ba739..1837c23b996d2 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -215,6 +215,9 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable { return languageFeatures.registerImplementationProvider(selector, provider); }, + registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable { + return languageFeatures.registerTypeDefinitionProvider(selector, provider); + }, registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { return languageFeatures.registerHoverProvider(selector, provider); }, diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index f08c649838502..9246fe5d4d949 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -156,6 +156,7 @@ export abstract class MainThreadLanguageFeaturesShape { $emitCodeLensEvent(eventHandle: number, event?: any): TPromise { throw ni(); } $registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise { throw ni(); } $registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise { throw ni(); } + $registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): TPromise { throw ni(); } $registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise { throw ni(); } $registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise { throw ni(); } $registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise { throw ni(); } @@ -361,6 +362,7 @@ export abstract class ExtHostLanguageFeaturesShape { $resolveCodeLens(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise { throw ni(); } $provideDefinition(handle: number, resource: URI, position: editorCommon.IPosition): TPromise { throw ni(); } $provideImplementation(handle: number, resource: URI, position: editorCommon.IPosition): TPromise { throw ni(); } + $provideTypeDefinition(handle: number, resource: URI, position: editorCommon.IPosition): TPromise { throw ni(); } $provideHover(handle: number, resource: URI, position: editorCommon.IPosition): TPromise { throw ni(); } $provideDocumentHighlights(handle: number, resource: URI, position: editorCommon.IPosition): TPromise { throw ni(); } $provideReferences(handle: number, resource: URI, position: editorCommon.IPosition, context: modes.ReferenceContext): TPromise { throw ni(); } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 0e93f692636a4..dd5673ff7ede7 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -101,7 +101,6 @@ class CodeLensAdapter { } class DefinitionAdapter { - private _documents: ExtHostDocuments; private _provider: vscode.DefinitionProvider; @@ -125,7 +124,6 @@ class DefinitionAdapter { } class ImplementationAdapter { - private _documents: ExtHostDocuments; private _provider: vscode.ImplementationProvider; @@ -148,6 +146,30 @@ class ImplementationAdapter { } } +class TypeDefinitionAdapter { + private _documents: ExtHostDocuments; + private _provider: vscode.TypeDefinitionProvider; + + constructor(documents: ExtHostDocuments, provider: vscode.TypeDefinitionProvider) { + this._documents = documents; + this._provider = provider; + } + + provideTypeDefinition(resource: URI, position: IPosition): TPromise { + const doc = this._documents.getDocumentData(resource).document; + const pos = TypeConverters.toPosition(position); + return asWinJsPromise(token => this._provider.provideTypeDefinition(doc, pos, token)).then(value => { + if (Array.isArray(value)) { + return value.map(TypeConverters.location.from); + } else if (value) { + return TypeConverters.location.from(value); + } + return undefined; + }); + } +} + + class HoverAdapter { private _documents: ExtHostDocuments; @@ -650,7 +672,7 @@ class LinkProviderAdapter { type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter | DocumentHighlightAdapter | ReferenceAdapter | QuickFixAdapter | DocumentFormattingAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter - | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter; + | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter; export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape { @@ -760,6 +782,17 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape { return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(resource, position)); } + registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable { + const handle = this._nextHandle(); + this._adapter.set(handle, new TypeDefinitionAdapter(this._documents, provider)); + this._proxy.$registerTypeDefinitionSupport(handle, selector); + return this._createDisposable(handle); + } + + $provideTypeDefinition(handle: number, resource: URI, position: IPosition): TPromise { + return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(resource, position)); + } + // --- extra info registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { diff --git a/src/vs/workbench/api/node/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/node/mainThreadLanguageFeatures.ts index fc66a29931bdb..4a57ebc458ae0 100644 --- a/src/vs/workbench/api/node/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/node/mainThreadLanguageFeatures.ts @@ -111,6 +111,15 @@ export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape return undefined; } + $registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): TPromise { + this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, { + provideTypeDefinition: (model, position, token): Thenable => { + return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position)); + } + }); + return undefined; + } + // --- extra info $registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise { diff --git a/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts index 2ba63517c3ac9..61e03db9d9f4a 100644 --- a/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts @@ -27,7 +27,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/common/quickOpen'; import { DocumentSymbolProviderRegistry, DocumentHighlightKind } from 'vs/editor/common/modes'; import { getCodeLensData } from 'vs/editor/contrib/codelens/common/codelens'; -import { getDeclarationsAtPosition, getImplementationAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; +import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; import { getHover } from 'vs/editor/contrib/hover/common/hover'; import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; import { provideReferences } from 'vs/editor/contrib/referenceSearch/common/referenceSearch'; @@ -275,7 +275,7 @@ suite('ExtHostLanguageFeatures', function () { return threadService.sync().then(() => { - return getDeclarationsAtPosition(model, new EditorPosition(1, 1)).then(value => { + return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => { assert.equal(value.length, 1); let [entry] = value; assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); @@ -299,7 +299,7 @@ suite('ExtHostLanguageFeatures', function () { return threadService.sync().then(() => { - return getDeclarationsAtPosition(model, new EditorPosition(1, 1)).then(value => { + return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => { assert.equal(value.length, 2); }); }); @@ -321,7 +321,7 @@ suite('ExtHostLanguageFeatures', function () { return threadService.sync().then(() => { - return getDeclarationsAtPosition(model, new EditorPosition(1, 1)).then(value => { + return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => { assert.equal(value.length, 2); // let [first, second] = value; @@ -346,13 +346,13 @@ suite('ExtHostLanguageFeatures', function () { return threadService.sync().then(() => { - return getDeclarationsAtPosition(model, new EditorPosition(1, 1)).then(value => { + return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => { assert.equal(value.length, 1); }); }); }); - // --- type implementation + // --- implementation test('Implementation, data conversion', function () { @@ -363,7 +363,27 @@ suite('ExtHostLanguageFeatures', function () { })); return threadService.sync().then(() => { - return getImplementationAtPosition(model, new EditorPosition(1, 1)).then(value => { + return getImplementationsAtPosition(model, new EditorPosition(1, 1)).then(value => { + assert.equal(value.length, 1); + let [entry] = value; + assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); + assert.equal(entry.uri.toString(), model.uri.toString()); + }); + }); + }); + + // --- type definition + + test('Type Definition, data conversion', function () { + + disposables.push(extHost.registerTypeDefinitionProvider(defaultSelector, { + provideTypeDefinition(): any { + return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))]; + } + })); + + return threadService.sync().then(() => { + return getTypeDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => { assert.equal(value.length, 1); let [entry] = value; assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });