Skip to content

Commit 00d9971

Browse files
authored
Extend CodeLens to build and run more targets (#404)
Previously, `_binary` targets could only be run, `_test` taregets could only be tested, and all other targets could only be built. This change allows all targets to be built and all non-`_library` targets to be run. Additionally, this change shortens the names of the targets in codelens, as otherwise the additional commands caused a lot of clutter: `Run //foo/bar/baz:flubber Build //foo/bar/baz:flubber` etc.
1 parent 2f9d49c commit 00d9971

File tree

1 file changed

+67
-28
lines changed

1 file changed

+67
-28
lines changed

src/codelens/bazel_build_code_lens_provider.ts

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,25 @@ import { getDefaultBazelExecutablePath } from "../extension/configuration";
2020
import { blaze_query } from "../protos";
2121
import { CodeLensCommandAdapter } from "./code_lens_command_adapter";
2222

23+
/** Computes the shortened name of a Bazel target.
24+
*
25+
* For example, if the target name starts with `//foo/bar/baz:fizbuzz`,
26+
* the target's short name will be `fizzbuzz`.
27+
*
28+
* This allows our code lens suggestions to avoid filling users' screen with
29+
* redundant path information.
30+
*
31+
* @param targetName The unshortened name of the target.
32+
* @returns The shortened name of the target.
33+
*/
34+
function getTargetShortName(targetName: string): string {
35+
const colonFragments = targetName.split(":");
36+
if (colonFragments.length !== 2) {
37+
return targetName;
38+
}
39+
return colonFragments[1];
40+
}
41+
2342
/** Provids CodeLenses for targets in Bazel BUILD files. */
2443
export class BazelBuildCodeLensProvider implements vscode.CodeLensProvider {
2544
public onDidChangeCodeLenses: vscode.Event<void>;
@@ -107,40 +126,60 @@ export class BazelBuildCodeLensProvider implements vscode.CodeLensProvider {
107126
): vscode.CodeLens[] {
108127
const result: vscode.CodeLens[] = [];
109128

129+
interface LensCommand {
130+
commandString: string;
131+
name: string;
132+
}
133+
110134
for (const target of queryResult.target) {
111135
const location = new QueryLocation(target.rule.location);
112136
const targetName = target.rule.name;
113137
const ruleClass = target.rule.ruleClass;
114-
let cmd: vscode.Command;
138+
const targetShortName = getTargetShortName(targetName);
139+
140+
const commands: LensCommand[] = [];
141+
142+
// Only test targets support testing.
115143
if (ruleClass.endsWith("_test") || ruleClass === "test_suite") {
116-
cmd = {
117-
arguments: [
118-
new CodeLensCommandAdapter(bazelWorkspaceInfo, [targetName]),
119-
],
120-
command: "bazel.testTarget",
121-
title: `Test ${targetName}`,
122-
tooltip: `Test ${targetName}`,
123-
};
124-
} else if (ruleClass.endsWith("_binary")) {
125-
cmd = {
126-
arguments: [
127-
new CodeLensCommandAdapter(bazelWorkspaceInfo, [targetName]),
128-
],
129-
command: "bazel.runTarget",
130-
title: `Run ${targetName}`,
131-
tooltip: `Run ${targetName}`,
132-
};
133-
} else {
134-
cmd = {
135-
arguments: [
136-
new CodeLensCommandAdapter(bazelWorkspaceInfo, [targetName]),
137-
],
138-
command: "bazel.buildTarget",
139-
title: `Build ${targetName}`,
140-
tooltip: `Build ${targetName}`,
141-
};
144+
commands.push({
145+
commandString: "bazel.testTarget",
146+
name: "Test",
147+
});
148+
}
149+
150+
// Targets which are not libraries may support running.
151+
//
152+
// Without checking the Bazel rule's `executable` attribute we can't know
153+
// for sure which targets can be run. This could be calculated by running
154+
// `bazel cquery`, but this would introduce significant costs due to
155+
// first running the `analysis` phase, so we use a heuristic instead.
156+
const ruleIsLibrary = ruleClass.endsWith("_library");
157+
if (!ruleIsLibrary) {
158+
commands.push({
159+
commandString: "bazel.runTarget",
160+
name: "Run",
161+
});
162+
}
163+
164+
// All targets support building.
165+
commands.push({
166+
commandString: "bazel.buildTarget",
167+
name: "Build",
168+
});
169+
170+
for (const command of commands) {
171+
const title = `${command.name} ${targetShortName}`;
172+
result.push(
173+
new vscode.CodeLens(location.range, {
174+
arguments: [
175+
new CodeLensCommandAdapter(bazelWorkspaceInfo, [targetName]),
176+
],
177+
command: command.commandString,
178+
title,
179+
tooltip: title,
180+
}),
181+
);
142182
}
143-
result.push(new vscode.CodeLens(location.range, cmd));
144183
}
145184

146185
return result;

0 commit comments

Comments
 (0)