Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
},
"bazel.commandLine.queryExpression": {
"type": "string",
"default": "...:*",
"default": "",
"description": "A [query language expression](https://bazel.build/query/language) which determines the packages displayed in the workspace tree and quick picker. The default inspects the entire workspace, but you could narrow it. For example: `//part/you/want/...:*`"
},
"bazel.lsp.command": {
Expand Down
16 changes: 16 additions & 0 deletions src/bazel/bazel_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ import * as vscode from "vscode";
import { blaze_query } from "../protos";
import { BazelQuery } from "./bazel_query";

/**
* Get the absolute path for a queried label.
*
* The queried package path are without leading double slash, while we want to
* provide with leading slash.
*
* @param label The label.
* @returns The label in absolute path.
*/
export function labelFromQueriedToAbsolute(label: string): string {
// External packages are in form `@repo//foo/bar`.
// Main repo relative label are in form `foo/bar`.
// Main repo absolute label are in form `//foo/bar`.
return label.includes("//") ? label : `//${label}`;
}

/**
* Get the package label for a build file.
*
Expand Down
4 changes: 2 additions & 2 deletions src/bazel/bazel_workspace_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ export class BazelWorkspaceInfo {
* belong to a workspace folder (for example, a standalone file loaded
* into the editor).
*/
private constructor(
constructor(
public readonly bazelWorkspacePath: string,
public readonly workspaceFolder: vscode.WorkspaceFolder | undefined,
public readonly workspaceFolder?: vscode.WorkspaceFolder,
) {}
}
8 changes: 8 additions & 0 deletions src/extension/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ export function getDefaultBazelExecutablePath(): string {
}
return bazelExecutable;
}

export function getDefaultQueryExpression(): string {
return (
vscode.workspace
.getConfiguration("bazel.commandLine")
.get<string>("queryExpression") ?? "...:*"
);
}
16 changes: 10 additions & 6 deletions src/extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { activateWrapperCommands } from "./bazel_wrapper_commands";
*/
export async function activate(context: vscode.ExtensionContext) {
const workspaceTreeProvider =
BazelWorkspaceTreeProvider.fromExtensionContext(context);
await BazelWorkspaceTreeProvider.fromExtensionContext(context);
context.subscriptions.push(workspaceTreeProvider);

const codeLensProvider = new BazelBuildCodeLensProvider(context);
Expand Down Expand Up @@ -96,11 +96,15 @@ export async function activate(context: vscode.ExtensionContext) {
),
// Commands
...activateWrapperCommands(),
vscode.commands.registerCommand("bazel.refreshBazelBuildTargets", () => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
completionItemProvider.refresh();
workspaceTreeProvider.refresh();
}),
vscode.commands.registerCommand(
"bazel.refreshBazelBuildTargets",
async () => {
await Promise.allSettled([
completionItemProvider.refresh(),
workspaceTreeProvider.refresh(vscode.workspace.workspaceFolders),
]);
},
),
vscode.commands.registerCommand(
"bazel.copyTargetToClipboard",
bazelCopyTargetToClipboard,
Expand Down
58 changes: 31 additions & 27 deletions src/workspace-tree/bazel_package_tree_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,11 @@

import * as vscode from "vscode";
import { BazelWorkspaceInfo } from "../bazel";
import {
BazelQuery,
IBazelCommandAdapter,
IBazelCommandOptions,
} from "../bazel";
import { getDefaultBazelExecutablePath } from "../extension/configuration";
import { IBazelCommandAdapter, IBazelCommandOptions } from "../bazel";
import { blaze_query } from "../protos";
import { BazelTargetTreeItem } from "./bazel_target_tree_item";
import { IBazelTreeItem } from "./bazel_tree_item";
import { IBazelQuerier } from "./querier";
import { Resources } from "../extension/resources";

/** A tree item representing a build package. */
Expand All @@ -33,11 +29,12 @@ export class BazelPackageTreeItem
* The array of subpackages that should be shown directly under this package
* item.
*/
public directSubpackages: BazelPackageTreeItem[] = [];
public directSubpackages: IBazelTreeItem[] = [];

/**
* Initializes a new tree item with the given workspace path and package path.
*
* @param querier Querier for getting information inside a Bazel workspace.
* @param workspacePath The path to the VS Code workspace folder.
* @param packagePath The path to the build package that this item represents.
* @param parentPackagePath The path to the build package of the tree item
Expand All @@ -46,54 +43,61 @@ export class BazelPackageTreeItem
*/
constructor(
private readonly resources: Resources,
private readonly querier: IBazelQuerier,
private readonly workspaceInfo: BazelWorkspaceInfo,
private readonly packagePath: string,
private readonly parentPackagePath: string,
private readonly parentPackagePath?: string,
) {}

public mightHaveChildren(): boolean {
return true;
}

public async getChildren(): Promise<IBazelTreeItem[]> {
const queryResult = await new BazelQuery(
getDefaultBazelExecutablePath(),
this.workspaceInfo.bazelWorkspacePath,
).queryTargets(`//${this.packagePath}:all`, {
ignoresErrors: true,
sortByRuleName: true,
});
const queryResult = await this.querier.queryChildrenTargets(
this.workspaceInfo,
this.packagePath,
);
const targets = queryResult.target.map((target: blaze_query.ITarget) => {
return new BazelTargetTreeItem(
this.resources,
this.workspaceInfo,
target,
);
});
return (this.directSubpackages as IBazelTreeItem[]).concat(targets);
return this.directSubpackages.concat(targets);
}

public getLabel(): string {
// If this is a top-level package, include the leading double-slash on the
// label.
if (this.parentPackagePath.length === 0) {
return `//${this.packagePath}`;
if (this.parentPackagePath === undefined) {
return this.packagePath;
}
// Otherwise, strip off the part of the package path that came from the
// parent item (along with the slash).
return this.packagePath.substring(this.parentPackagePath.length + 1);
// Strip off the part of the package path that came from the
// parent item.
const parentLength = this.parentPackagePath.length;
// (null)
// //a
//
// @repo//foo
// @repo//foo/bar
//
// @repo//
// @repo//foo
const diffIsLeadingSlash = this.packagePath[parentLength] === "/";
const prefixLength = diffIsLeadingSlash ? parentLength + 1 : parentLength;
return this.packagePath.substring(prefixLength);
}

public getIcon(): vscode.ThemeIcon {
return vscode.ThemeIcon.Folder;
}

public getTooltip(): string {
return `//${this.packagePath}`;
return this.packagePath;
}

public getCommand(): vscode.Command | undefined {
return undefined;
public getCommand(): Promise<vscode.Command | undefined> {
return Promise.resolve<undefined>(undefined);
}

public getContextValue(): string {
Expand All @@ -103,7 +107,7 @@ export class BazelPackageTreeItem
public getBazelCommandOptions(): IBazelCommandOptions {
return {
options: [],
targets: [`//${this.packagePath}`],
targets: [this.packagePath],
workspaceInfo: this.workspaceInfo,
};
}
Expand Down
37 changes: 30 additions & 7 deletions src/workspace-tree/bazel_target_tree_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
// limitations under the License.

import * as vscode from "vscode";
import * as fs from "fs/promises";
import { BazelWorkspaceInfo, QueryLocation } from "../bazel";
import { IBazelCommandAdapter, IBazelCommandOptions } from "../bazel";
import { blaze_query } from "../protos";
import { IBazelTreeItem } from "./bazel_tree_item";
import { getBazelRuleIcon } from "./icons";
import { BazelInfo } from "../bazel/bazel_info";
import { getDefaultBazelExecutablePath } from "../extension/configuration";
import { Resources } from "../extension/resources";

/** A tree item representing a build target. */
Expand Down Expand Up @@ -61,16 +64,36 @@ export class BazelTargetTreeItem
}

public getTooltip(): string {
return `${this.target.rule.name}`;
return this.target.rule.name;
}

public getCommand(): vscode.Command | undefined {
public async getCommand(): Promise<vscode.Command | undefined> {
// Resolve the prefix if prefix is
// $(./prebuilts/bazel info output_base)/external/
const location = new QueryLocation(this.target.rule.location);
// Maybe we should cache this to prevent the repeating invocations.
const outputBase = await new BazelInfo(
getDefaultBazelExecutablePath(),
this.workspaceInfo.workspaceFolder.uri.fsPath,
).getOne("output_base");
let locationPath = location.path;
// If location is in pattern `${execRoot}/external/<repo>/...`, then it
// should be a file in local_repository(). Trying to remapping it back to
// the origin source folder by resolve the symlink
// ${execRoot}/external/<repo>.
const outputBaseExternalPath = `${outputBase}/external/`;
if (location.path.startsWith(outputBaseExternalPath)) {
const repoPath = location.path.substring(outputBaseExternalPath.length);
const repoPathMatch = repoPath.match(/^([^/]+)\/(.*)$/);
if (repoPathMatch.length === 3) {
const repo = repoPathMatch[1];
const rest = repoPathMatch[2];
const realRepo = await fs.realpath(`${outputBaseExternalPath}${repo}`);
locationPath = `${realRepo}/${rest}`;
}
}
return {
arguments: [
vscode.Uri.file(location.path),
{ selection: location.range },
],
arguments: [vscode.Uri.file(locationPath), { selection: location.range }],
command: "vscode.open",
title: "Jump to Build Target",
};
Expand All @@ -87,7 +110,7 @@ export class BazelTargetTreeItem
public getBazelCommandOptions(): IBazelCommandOptions {
return {
options: [],
targets: [`${this.target.rule.name}`],
targets: [this.target.rule.name],
workspaceInfo: this.workspaceInfo,
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/workspace-tree/bazel_tree_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface IBazelTreeItem {
getTooltip(): string | undefined;

/** Returns the command that should be executed when the item is selected. */
getCommand(): vscode.Command | undefined;
getCommand(): Promise<vscode.Command | undefined>;

/**
* Returns an identifying string that is used to filter which commands are
Expand Down
Loading
Loading