Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Type Definition Provider API #19699

Merged
merged 5 commits into from
Feb 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion extensions/typescript/src/features/definitionProviderBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Location[] | null> {
protected getSymbolLocations(
definitionType: 'definition' | 'implementation' | 'typeDefinition',
document: TextDocument,
position: Position,
token: CancellationToken | boolean
): Promise<Location[] | null> {
const filepath = this.client.normalizePath(document.uri);
if (!filepath) {
return Promise.resolve(null);
Expand Down
21 changes: 21 additions & 0 deletions extensions/typescript/src/features/typeDefinitionProvider.ts
Original file line number Diff line number Diff line change
@@ -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<Definition | null> {
return this.getSymbolLocations('typeDefinition', document, position, token);
}
}
5 changes: 5 additions & 0 deletions extensions/typescript/src/typescriptMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions extensions/typescript/src/typescriptService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export interface ITypescriptServiceClient {
execute(commant: 'signatureHelp', args: Proto.SignatureHelpRequestArgs, token?: CancellationToken): Promise<Proto.SignatureHelpResponse>;
execute(command: 'definition', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.DefinitionResponse>;
execute(command: 'implementation', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.ImplementationResponse>;
execute(command: 'typeDefinition', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.TypeDefinitionResponse>;
execute(command: 'references', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.ReferencesResponse>;
execute(command: 'navto', args: Proto.NavtoRequestArgs, token?: CancellationToken): Promise<Proto.NavtoResponse>;
execute(command: 'navbar', args: Proto.FileRequestArgs, token?: CancellationToken): Promise<Proto.NavBarResponse>;
Expand Down
10 changes: 9 additions & 1 deletion src/vs/editor/browser/standalone/standaloneLanguages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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).
*/
Expand Down Expand Up @@ -682,6 +689,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
registerDocumentHighlightProvider: registerDocumentHighlightProvider,
registerDefinitionProvider: registerDefinitionProvider,
registerImplementationProvider: registerImplementationProvider,
registerTypeDefinitionProvider: registerTypeDefinitionProvider,
registerCodeLensProvider: registerCodeLensProvider,
registerCodeActionProvider: registerCodeActionProvider,
registerDocumentFormattingEditProvider: registerDocumentFormattingEditProvider,
Expand Down
4 changes: 4 additions & 0 deletions src/vs/editor/common/editorCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3146,6 +3146,10 @@ export namespace ModeContextKeys {
* @internal
*/
export const hasImplementationProvider = new RawContextKey<boolean>('editorHasImplementationProvider', undefined);
/**
* @internal
*/
export const hasTypeDefinitionProvider = new RawContextKey<boolean>('editorHasTypeDefinitionProvider', undefined);
/**
* @internal
*/
Expand Down
18 changes: 17 additions & 1 deletion src/vs/editor/common/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -439,6 +439,17 @@ export interface ImplementationProvider {
provideImplementation(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Definition | Thenable<Definition>;
}

/**
* 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<Definition>;
}

/**
* A symbol kind.
*/
Expand Down Expand Up @@ -751,6 +762,11 @@ export const DefinitionProviderRegistry = new LanguageFeatureRegistry<Definition
*/
export const ImplementationProviderRegistry = new LanguageFeatureRegistry<ImplementationProvider>();

/**
* @internal
*/
export const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry<TypeDefinitionProvider>();

/**
* @internal
*/
Expand Down
5 changes: 5 additions & 0 deletions src/vs/editor/common/modes/editorModeContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class EditorModeContext {
private _hasCodeLensProvider: IContextKey<boolean>;
private _hasDefinitionProvider: IContextKey<boolean>;
private _hasImplementationProvider: IContextKey<boolean>;
private _hasTypeDefinitionProvider: IContextKey<boolean>;
private _hasHoverProvider: IContextKey<boolean>;
private _hasDocumentHighlightProvider: IContextKey<boolean>;
private _hasDocumentSymbolProvider: IContextKey<boolean>;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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();
Expand All @@ -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));
Expand Down
63 changes: 57 additions & 6 deletions src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -106,7 +106,7 @@ export class DefinitionAction extends EditorAction {
}

protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise<Location[]> {
return getDeclarationsAtPosition(model, position);
return getDefinitionsAtPosition(model, position);
}

private _onResult(editorService: IEditorService, editor: editorCommon.ICommonCodeEditor, model: ReferencesModel) {
Expand Down Expand Up @@ -255,7 +255,7 @@ export class GoToImplementationAction extends DefinitionAction {
}

protected getDeclarationsAtPosition(model: editorCommon.IModel, position: corePosition.Position): TPromise<Location[]> {
return getImplementationAtPosition(model, position);
return getImplementationsAtPosition(model, position);
}
}

Expand All @@ -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<Location[]> {
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<Location[]> {
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<Location[]> {
return getTypeDefinitionsAtPosition(model, position);
}
}


// --- Editor Contribution to goto definition using the mouse and a modifier key

@editorContribution
Expand Down Expand Up @@ -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<any> {
Expand Down
47 changes: 28 additions & 19 deletions src/vs/editor/contrib/goToDeclaration/common/goToDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -27,14 +29,18 @@ function outputResults(promises: TPromise<Location[]>[]) {
});
}

export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> {

const provider = DefinitionProviderRegistry.ordered(model);
function getDefinitions<T>(
model: IReadOnlyModel,
position: Position,
registry: LanguageFeatureRegistry<T>,
provide: (provider: T, model: IReadOnlyModel, position: Position, token: CancellationToken) => Location | Location[] | Thenable<Location | Location[]>
): TPromise<Location[]> {
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 => {
Expand All @@ -44,22 +50,25 @@ export function getDeclarationsAtPosition(model: IReadOnlyModel, position: Posit
return outputResults(promises);
}

export function getImplementationAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> {

const provider = ImplementationProviderRegistry.ordered(model);
export function getDefinitionsAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> {
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<Location[]> {
return getDefinitions(model, position, ImplementationProviderRegistry, (provider, model, position, token) => {
return provider.provideImplementation(model, position, token);
});
}

export function getTypeDefinitionsAtPosition(model: IReadOnlyModel, position: Position): TPromise<Location[]> {
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);
CommonEditorRegistry.registerDefaultLanguageCommand('_executeDefinitionProvider', getDefinitionsAtPosition);
CommonEditorRegistry.registerDefaultLanguageCommand('_executeImplementationProvider', getImplementationsAtPosition);
CommonEditorRegistry.registerDefaultLanguageCommand('_executeTypeDefinitionProvider', getTypeDefinitionsAtPosition);
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class ReferenceAction extends EditorAction {
},
menuOpts: {
group: 'navigation',
order: 1.3
order: 1.5
}
});
}
Expand Down
Loading