Skip to content
This repository has been archived by the owner on Oct 16, 2020. It is now read-only.

Commit

Permalink
feat: Add goto type definition. (#475)
Browse files Browse the repository at this point in the history
Adds support to go directly to the type definition for the symbol under the cursor.
  • Loading branch information
teasp00n authored and felixfbecker committed Jun 19, 2018
1 parent fcc0ccb commit d107424
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This is a language server for JavaScript and TypeScript that adheres to the [Lan

- Hovers
- Goto definition
- Goto type definition
- Find all references
- Document symbols
- Workspace symbol search
Expand Down
64 changes: 64 additions & 0 deletions src/test/typescript-service-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export function describeTypeScriptService(
'let target = i.target;',
].join('\n'),
],
[rootUri + 'foo/f.ts', ['import {Foo} from "./b";', '', 'let foo: Foo = Object({});'].join('\n')],
[rootUri + 'foo/g.ts', ['class Foo = {}', '', 'let foo: Foo = Object({});'].join('\n')],
])
)
)
Expand Down Expand Up @@ -224,6 +226,68 @@ export function describeTypeScriptService(
])
})
})

describe('textDocumentTypeDefinition()', function(this: TestContext & ISuiteCallbackContext): void {
specify('in other file', async function(this: TestContext & ITestCallbackContext): Promise<void> {
const result: Location[] = await this.service
.textDocumentTypeDefinition({
textDocument: {
uri: rootUri + 'foo/f.ts',
},
position: {
line: 2,
character: 5,
},
})
.reduce<Operation, Location[]>(applyReducer, null as any)
.toPromise()
assert.deepEqual(result, [
{
uri: rootUri + 'foo/b.ts',
range: {
start: {
line: 1,
character: 13,
},
end: {
line: 1,
character: 16,
},
},
},
])
})
specify('in same file', async function(this: TestContext & ITestCallbackContext): Promise<void> {
const result: Location[] = await this.service
.textDocumentTypeDefinition({
textDocument: {
uri: rootUri + 'foo/g.ts',
},
position: {
line: 2,
character: 5,
},
})
.reduce<Operation, Location[]>(applyReducer, null as any)
.toPromise()
assert.deepEqual(result, [
{
uri: rootUri + 'foo/g.ts',
range: {
start: {
line: 0,
character: 6,
},
end: {
line: 0,
character: 9,
},
},
},
])
})
})

describe('textDocumentXdefinition()', function(this: TestContext & ISuiteCallbackContext): void {
specify('on interface field reference', async function(
this: TestContext & ITestCallbackContext
Expand Down
27 changes: 22 additions & 5 deletions src/typescript-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ export class TypeScriptService {
triggerCharacters: ['(', ','],
},
definitionProvider: true,
typeDefinitionProvider: true,
referencesProvider: true,
documentSymbolProvider: true,
workspaceSymbolProvider: true,
Expand Down Expand Up @@ -362,15 +363,31 @@ export class TypeScriptService {
*/

public textDocumentDefinition(params: TextDocumentPositionParams, span = new Span()): Observable<Operation> {
return this._getDefinitionLocations(params, span)
return this._getDefinitionLocations(params, span, false)
.map((location: Location): Operation => ({ op: 'add', path: '/-', value: location }))
.startWith({ op: 'add', path: '', value: [] })
}

/**
* The goto type definition request is sent from the client to the server to resolve the type
* location of a symbol at a given text document position.
*
* @return Observable of JSON Patches that build a `Location[]` result
*/
public textDocumentTypeDefinition(params: TextDocumentPositionParams, span = new Span()): Observable<Operation> {
return this._getDefinitionLocations(params, span, true)
.map((location: Location): Operation => ({ op: 'add', path: '/-', value: location }))
.startWith({ op: 'add', path: '', value: [] })
}

/**
* Returns an Observable of all definition locations found for a symbol.
*/
protected _getDefinitionLocations(params: TextDocumentPositionParams, span = new Span()): Observable<Location> {
protected _getDefinitionLocations(
params: TextDocumentPositionParams,
span = new Span(),
goToType = false
): Observable<Location> {
const uri = normalizeUri(params.textDocument.uri)

// Fetch files needed to resolve definition
Expand All @@ -392,9 +409,9 @@ export class TypeScriptService {
params.position.line,
params.position.character
)
const definitions: ts.DefinitionInfo[] | undefined = configuration
.getService()
.getDefinitionAtPosition(fileName, offset)
const definitions: ts.DefinitionInfo[] | undefined = goToType
? configuration.getService().getTypeDefinitionAtPosition(fileName, offset)
: configuration.getService().getDefinitionAtPosition(fileName, offset)

return Observable.from(definitions || []).map((definition): Location => {
const sourceFile = this._getSourceFile(configuration, definition.fileName, span)
Expand Down

0 comments on commit d107424

Please sign in to comment.