diff --git a/src/definition/bazel_goto_definition_provider.ts b/src/definition/bazel_goto_definition_provider.ts index a0090404..80c010fd 100644 --- a/src/definition/bazel_goto_definition_provider.ts +++ b/src/definition/bazel_goto_definition_provider.ts @@ -19,15 +19,48 @@ import { Position, TextDocument, Uri, + window, } from "vscode"; import { Utils } from "vscode-uri"; import { BazelQuery, BazelWorkspaceInfo, QueryLocation } from "../bazel"; import { getDefaultBazelExecutablePath } from "../extension/configuration"; import { blaze_query } from "../protos"; +import { uriToFsPath } from "vscode-uri/lib/umd/uri"; // LABEL_REGEX matches label strings, e.g. @r//x/y/z:abc const LABEL_REGEX = /"((?:@\w+)?\/\/|(?:.+\/)?[^:]*(?::[^:]+)?)"/; +export async function targetToUri( + targetText: string, + workingDirectory: Uri, +): Promise { + const match = LABEL_REGEX.exec(targetText); + + const targetName = match[1]; + // don't try to process visibility targets. + if (targetName.startsWith("//visibility")) { + return null; + } + + const queryResult = await new BazelQuery( + getDefaultBazelExecutablePath(), + workingDirectory.fsPath, + ).queryTargets(`kind(rule, "${targetName}") + kind(file, "${targetName}")`); + + if (!queryResult.target.length) { + return null; + } + const result = queryResult.target[0]; + let location; + if (result.type === blaze_query.Target.Discriminator.RULE) { + location = new QueryLocation(result.rule.location); + } else { + location = new QueryLocation(result.sourceFile.location); + } + + return location; +} + export class BazelGotoDefinitionProvider implements DefinitionProvider { public async provideDefinition( document: TextDocument, @@ -41,33 +74,13 @@ export class BazelGotoDefinitionProvider implements DefinitionProvider { const range = document.getWordRangeAtPosition(position, LABEL_REGEX); const targetText = document.getText(range); - const match = LABEL_REGEX.exec(targetText); - - const targetName = match[1]; - // don't try to process visibility targets. - if (targetName.startsWith("//visibility")) { - return null; - } - const queryResult = await new BazelQuery( - getDefaultBazelExecutablePath(), - Utils.dirname(document.uri).fsPath, - ).queryTargets(`kind(rule, "${targetName}") + kind(file, "${targetName}")`); + const location = await targetToUri(targetText, Utils.dirname(document.uri)); - if (!queryResult.target.length) { - return null; - } - const result = queryResult.target[0]; - let location; - if (result.type === blaze_query.Target.Discriminator.RULE) { - location = new QueryLocation(result.rule.location); - } else { - location = new QueryLocation(result.sourceFile.location); - } return [ { originSelectionRange: range, - targetUri: Uri.file(location.path), + targetUri: Uri.file(location.path + `:$location.line:$location.column`), targetRange: location.range, }, ]; diff --git a/src/extension/extension.ts b/src/extension/extension.ts index d69bc049..67769567 100644 --- a/src/extension/extension.ts +++ b/src/extension/extension.ts @@ -27,7 +27,7 @@ import { } from "../buildifier"; import { BazelBuildCodeLensProvider } from "../codelens"; import { BazelCompletionItemProvider } from "../completion-provider"; -import { BazelGotoDefinitionProvider } from "../definition/bazel_goto_definition_provider"; +import { BazelGotoDefinitionProvider, targetToUri } from "../definition/bazel_goto_definition_provider"; import { BazelTargetSymbolProvider } from "../symbols"; import { BazelWorkspaceTreeProvider } from "../workspace-tree"; import { activateCommandVariables } from "./command_variables"; @@ -105,6 +105,30 @@ export async function activate(context: vscode.ExtensionContext) { "bazel.copyTargetToClipboard", bazelCopyTargetToClipboard, ), + // URI handler + vscode.window.registerUriHandler({ + async handleUri(uri: vscode.Uri) { + try { + const workspace = vscode.workspace.workspaceFolders[0]; + const quotedUriPath = `"${uri.path}"`; + const location = await targetToUri(quotedUriPath, workspace.uri); + + vscode.commands.executeCommand( + "vscode.open", + vscode.Uri.file(location.path).with({fragment: `${location.line}:${location.column}`}) + ).then(undefined, err => { + void vscode.window.showErrorMessage( + `Could not open file: ${location.path} Error: ${err}` + ); + }); + } + catch (err: any) { + void vscode.window.showErrorMessage( + `While handling URI: ${JSON.stringify(uri)} Error: ${err}` + ); + } + } + }), // CodeLens provider for BUILD files vscode.languages.registerCodeLensProvider( [{ pattern: "**/BUILD" }, { pattern: "**/BUILD.bazel" }],