82 lines
3.5 KiB
TypeScript
82 lines
3.5 KiB
TypeScript
import type * as lsp from "vscode-languageserver-protocol"
|
|
import { EditorView, Command, KeyBinding } from "@codemirror/view"
|
|
import { LSPPlugin } from "@codemirror/lsp-client";
|
|
|
|
import { addEditor } from "../editorgrid";
|
|
import { OpenFile } from "../filestate";
|
|
|
|
function getDefinition(plugin: LSPPlugin, pos: number) {
|
|
return plugin.client.request<lsp.DefinitionParams, lsp.Location | lsp.Location[] | null>("textDocument/definition", {
|
|
textDocument: { uri: plugin.uri },
|
|
position: plugin.toPosition(pos)
|
|
})
|
|
}
|
|
|
|
function getDeclaration(plugin: LSPPlugin, pos: number) {
|
|
return plugin.client.request<lsp.DeclarationParams, lsp.Location | lsp.Location[] | null>("textDocument/declaration", {
|
|
textDocument: { uri: plugin.uri },
|
|
position: plugin.toPosition(pos)
|
|
})
|
|
}
|
|
|
|
function getTypeDefinition(plugin: LSPPlugin, pos: number) {
|
|
return plugin.client.request<lsp.TypeDefinitionParams, lsp.Location | lsp.Location[] | null>("textDocument/typeDefinition", {
|
|
textDocument: { uri: plugin.uri },
|
|
position: plugin.toPosition(pos)
|
|
})
|
|
}
|
|
|
|
function getImplementation(plugin: LSPPlugin, pos: number) {
|
|
return plugin.client.request<lsp.ImplementationParams, lsp.Location | lsp.Location[] | null>("textDocument/implementation", {
|
|
textDocument: { uri: plugin.uri },
|
|
position: plugin.toPosition(pos)
|
|
})
|
|
}
|
|
|
|
function jumpToOrigin(view: EditorView, type: { get: typeof getDefinition, capability: keyof lsp.ServerCapabilities }): boolean {
|
|
const plugin = LSPPlugin.get(view);
|
|
const hasCapability = plugin.client.serverCapabilities ? !!plugin.client.serverCapabilities[type.capability] : null;
|
|
if (!plugin || !hasCapability) return false
|
|
plugin.client.sync()
|
|
plugin.client.withMapping(mapping => type.get(plugin, view.state.selection.main.head).then(async response => {
|
|
if (!response) return
|
|
let loc = Array.isArray(response) ? response[0] : response;
|
|
const path = new URL(loc.uri).pathname;
|
|
const target = addEditor(await OpenFile.openFile(path));
|
|
const pos = mapping.getMapping(loc.uri) ? mapping.mapPosition(loc.uri, loc.range.start) : plugin.fromPosition(loc.range.start, target.view.state.doc);
|
|
target.view.dispatch({selection: {anchor: pos}, scrollIntoView: true, userEvent: "select.definition"});
|
|
}, error => plugin.reportError("Find definition failed", error)))
|
|
return true
|
|
}
|
|
|
|
/// Jump to the definition of the symbol at the cursor. To support
|
|
/// cross-file jumps, you'll need to implement
|
|
/// [`Workspace.displayFile`](#lsp-client.Workspace.displayFile).
|
|
export const jumpToDefinition: Command = view => jumpToOrigin(view, {
|
|
get: getDefinition,
|
|
capability: "definitionProvider"
|
|
})
|
|
|
|
/// Jump to the declaration of the symbol at the cursor.
|
|
export const jumpToDeclaration: Command = view => jumpToOrigin(view, {
|
|
get: getDeclaration,
|
|
capability: "declarationProvider"
|
|
})
|
|
|
|
/// Jump to the type definition of the symbol at the cursor.
|
|
export const jumpToTypeDefinition: Command = view => jumpToOrigin(view, {
|
|
get: getTypeDefinition,
|
|
capability: "typeDefinitionProvider"
|
|
})
|
|
|
|
/// Jump to the implementation of the symbol at the cursor.
|
|
export const jumpToImplementation: Command = view => jumpToOrigin(view, {
|
|
get: getImplementation,
|
|
capability: "implementationProvider"
|
|
})
|
|
|
|
/// Binds F12 to [`jumpToDefinition`](#lsp-client.jumpToDefinition).
|
|
export const jumpToDefinitionKeymap: readonly KeyBinding[] = [
|
|
{ key: "F12", run: jumpToDefinition, preventDefault: true },
|
|
]
|