Skip to content

Commit

Permalink
feat: add URI handler for jumping to targets
Browse files Browse the repository at this point in the history
  • Loading branch information
catskul committed Jan 14, 2025
1 parent 3fa2595 commit 2fa1f1c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 23 deletions.
57 changes: 35 additions & 22 deletions src/definition/bazel_goto_definition_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<QueryLocation | undefined> {
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,
Expand All @@ -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,
},
];
Expand Down
26 changes: 25 additions & 1 deletion src/extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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" }],
Expand Down

0 comments on commit 2fa1f1c

Please sign in to comment.