diff --git a/package.json b/package.json index 749c97c..c8b6b4c 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,10 @@ "onLanguage:jsx-tags", "onLanguage:jsonc", "onCommand:_typescript.configurePlugin", - "onCommand:typescript.reloadProjects", - "onCommand:javascript.reloadProjects", - "onCommand:javascript.goToProjectConfig", - "onCommand:typescript.goToProjectConfig", - "onCommand:typescript.openTsServerLog", + "onCommand:tsserver.reloadProjects", + "onCommand:tsserver.goToProjectConfig", + "onCommand:tsserver.openTsServerLog", + "onCommand:tsserver.goToSourceDefinition", "onCommand:tsserver.watchBuild" ], "contributes": { @@ -94,6 +93,11 @@ "category": "TSServer", "command": "tsserver.findAllFileReferences" }, + { + "command": "tsserver.goToSourceDefinition", + "title": "Go to Source Definition", + "category": "TSServer" + }, { "title": "Run `tsc --watch` for current project by use vim's job feature.", "category": "TSServer", diff --git a/src/server/commands.ts b/src/server/commands.ts index 6d99712..3e50184 100644 --- a/src/server/commands.ts +++ b/src/server/commands.ts @@ -218,6 +218,56 @@ export class FileReferencesCommand implements Command { } } +export class SourceDefinitionCommand implements Command { + public static readonly context = 'tsSupportsSourceDefinition' + public static readonly minVersion = API.v470 + + public readonly id = 'tsserver.goToSourceDefinition' + + public constructor(private readonly service: TsserverService) {} + + public async execute() { + const client = await this.service.getClientHost() + if (client.serviceClient.apiVersion.lt(SourceDefinitionCommand.minVersion)) { + window.showErrorMessage('Go to Source Definition failed. Requires TypeScript 4.7+.') + return + } + + const { document, position } = await workspace.getCurrentState() + if (client.serviceClient.modeIds.indexOf(document.languageId) == -1) { + window.showErrorMessage('Go to Source Definition failed. Unsupported file type.') + return + } + const openedFiledPath = client.serviceClient.toOpenedFilePath(document.uri) + if (!openedFiledPath) { + window.showErrorMessage('Go to Source Definition failed. Unknown file type.') + return + } + + await window.withProgress({ title: 'Finding source definitions' }, async (_progress, token) => { + + const args = typeConverters.Position.toFileLocationRequestArgs(openedFiledPath, position) + const response = await client.serviceClient.execute('findSourceDefinition', args, token) + if (response.type === 'response' && response.body) { + const locations: Location[] = (response as Proto.DefinitionResponse).body.map(reference => + typeConverters.Location.fromTextSpan(client.serviceClient.toResource(reference.file), reference)) + + if (locations.length) { + commands.executeCommand('editor.action.showReferences', document.uri, position, locations) + // if (locations.length === 1) { + // commands.executeCommand('vscode.open', locations[0].uri) + // } else { + // commands.executeCommand('editor.action.showReferences', document.uri, position, locations) + // } + return + } + } + + window.showErrorMessage('No source definitions found.') + }) + } +} + export function registCommand(cmd: Command): Disposable { let { id, execute } = cmd return commands.registerCommand(id as string, execute, cmd) diff --git a/src/server/index.ts b/src/server/index.ts index 2d42456..108bf75 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -1,7 +1,7 @@ import { commands, disposeAll, IServiceProvider, ServiceStat, workspace, WorkspaceConfiguration } from 'coc.nvim' import { Disposable, DocumentSelector, Emitter, Event } from 'vscode-languageserver-protocol' import { PluginManager } from '../utils/plugins' -import { AutoFixCommand, Command, ConfigurePluginCommand, FileReferencesCommand, OpenTsServerLogCommand, ReloadProjectsCommand, TypeScriptGoToProjectConfigCommand } from './commands' +import { AutoFixCommand, Command, ConfigurePluginCommand, FileReferencesCommand, OpenTsServerLogCommand, ReloadProjectsCommand, SourceDefinitionCommand, TypeScriptGoToProjectConfigCommand } from './commands' import { OrganizeImportsCommand, SourceImportsCommand } from './organizeImports' import TypeScriptServiceClientHost from './typescriptServiceClientHost' import { LanguageDescription, standardLanguageDescriptions } from './utils/languageDescription' @@ -69,6 +69,7 @@ export default class TsserverService implements IServiceProvider { registCommand(new TypeScriptGoToProjectConfigCommand(this)) registCommand(new OrganizeImportsCommand(this)) registCommand(new SourceImportsCommand(this)) + registCommand(new SourceDefinitionCommand(this)) registCommand({ id: 'tsserver.restart', execute: (): void => { diff --git a/src/server/utils/api.ts b/src/server/utils/api.ts index 0dce70a..8331a5a 100644 --- a/src/server/utils/api.ts +++ b/src/server/utils/api.ts @@ -44,6 +44,7 @@ export default class API { public static readonly v420 = API.fromSimpleString('4.2.0') public static readonly v430 = API.fromSimpleString('4.3.0') public static readonly v440 = API.fromSimpleString('4.4.0') + public static readonly v470 = API.fromSimpleString('4.7.0') public static fromVersionString(versionString: string): API { let version = semver.valid(versionString)