Skip to content

Commit c61ae4e

Browse files
kon72jfirebaugh
authored andcommitted
Support completion of repository names
1 parent d2e2017 commit c61ae4e

File tree

4 files changed

+109
-7
lines changed

4 files changed

+109
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2023 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import * as vscode from "vscode";
16+
import { queryQuickPickTargets } from "../bazel";
17+
18+
function isCompletingInsideRepositoryLabel(
19+
document: vscode.TextDocument,
20+
position: vscode.Position,
21+
) {
22+
const linePrefix = document
23+
.lineAt(position)
24+
.text.substring(0, position.character);
25+
const startOfRepo = linePrefix.lastIndexOf("@");
26+
const endOfRepo = linePrefix.lastIndexOf("//");
27+
return startOfRepo !== -1 && (endOfRepo === -1 || endOfRepo < startOfRepo);
28+
}
29+
30+
function getTargetName(label: string) {
31+
const colonIndex = label.lastIndexOf(":");
32+
if (colonIndex === -1) {
33+
return undefined;
34+
}
35+
return label.substring(colonIndex + 1);
36+
}
37+
38+
export class BazelRepositoryCompletionItemProvider
39+
implements vscode.CompletionItemProvider {
40+
private repositories?: Promise<string[]>;
41+
42+
/**
43+
* Returns completion items matching the given prefix.
44+
*/
45+
public async provideCompletionItems(
46+
document: vscode.TextDocument,
47+
position: vscode.Position,
48+
) {
49+
if (!isCompletingInsideRepositoryLabel(document, position)) {
50+
return [];
51+
}
52+
53+
const repos = await this.getRepos();
54+
const completionItems = repos.map(
55+
(repo) =>
56+
new vscode.CompletionItem(repo, vscode.CompletionItemKind.Folder),
57+
);
58+
return completionItems;
59+
}
60+
61+
/**
62+
* Runs a bazel query command to acquire all the repositories in the
63+
* workspace.
64+
*/
65+
public async refresh(): Promise<void> {
66+
await this.queryAndCacheRepos();
67+
}
68+
69+
private async getRepos(): Promise<string[]> {
70+
if (this.repositories) {
71+
return await this.repositories;
72+
}
73+
return await this.queryAndCacheRepos();
74+
}
75+
76+
private async queryAndCacheRepos(): Promise<string[]> {
77+
const queryRepos = async () => {
78+
const targets = await queryQuickPickTargets(
79+
"kind('.* rule', //external:*)",
80+
);
81+
return targets.map((target) => getTargetName(target.label));
82+
};
83+
const deferred = queryRepos();
84+
this.repositories = deferred;
85+
return await deferred;
86+
}
87+
}

src/completion-provider/bazel_completion_provider.ts src/completion-provider/bazel_target_completion_provider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function getRepositoryName(target: string): string {
100100
return endOfRepo <= 0 ? "" : target.substring(1, endOfRepo);
101101
}
102102

103-
export class BazelCompletionItemProvider
103+
export class BazelTargetCompletionItemProvider
104104
implements vscode.CompletionItemProvider {
105105
private readonly targetsInRepo = new Map<string, Promise<string[]>>();
106106

src/completion-provider/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
export * from "./bazel_completion_provider";
15+
export * from "./bazel_repository_completion_provider";
16+
export * from "./bazel_target_completion_provider";

src/extension/extension.ts

+19-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ import {
3535
checkBuildifierIsAvailable,
3636
} from "../buildifier";
3737
import { BazelBuildCodeLensProvider } from "../codelens";
38-
import { BazelCompletionItemProvider } from "../completion-provider";
38+
import {
39+
BazelRepositoryCompletionItemProvider,
40+
BazelTargetCompletionItemProvider,
41+
} from "../completion-provider";
3942
import { BazelGotoDefinitionProvider } from "../definition/bazel_goto_definition_provider";
4043
import { BazelTargetSymbolProvider } from "../symbols";
4144
import { BazelWorkspaceTreeProvider } from "../workspace-tree";
@@ -51,15 +54,24 @@ export function activate(context: vscode.ExtensionContext) {
5154
const workspaceTreeProvider = new BazelWorkspaceTreeProvider(context);
5255
const codeLensProvider = new BazelBuildCodeLensProvider(context);
5356
const buildifierDiagnostics = new BuildifierDiagnosticsManager();
54-
const completionItemProvider = new BazelCompletionItemProvider();
57+
const repositoryCompletionItemProvider =
58+
new BazelRepositoryCompletionItemProvider();
59+
const targetCompletionItemProvider = new BazelTargetCompletionItemProvider();
5560

5661
// tslint:disable-next-line:no-floating-promises
57-
completionItemProvider.refresh();
62+
repositoryCompletionItemProvider.refresh();
63+
// tslint:disable-next-line:no-floating-promises
64+
targetCompletionItemProvider.refresh();
5865

5966
context.subscriptions.push(
6067
vscode.languages.registerCompletionItemProvider(
6168
[{ pattern: "**/BUILD" }, { pattern: "**/BUILD.bazel" }],
62-
completionItemProvider,
69+
repositoryCompletionItemProvider,
70+
"@",
71+
),
72+
vscode.languages.registerCompletionItemProvider(
73+
[{ pattern: "**/BUILD" }, { pattern: "**/BUILD.bazel" }],
74+
targetCompletionItemProvider,
6375
"/",
6476
":",
6577
),
@@ -88,7 +100,9 @@ export function activate(context: vscode.ExtensionContext) {
88100
vscode.commands.registerCommand("bazel.clean", bazelClean),
89101
vscode.commands.registerCommand("bazel.refreshBazelBuildTargets", () => {
90102
// tslint:disable-next-line:no-floating-promises
91-
completionItemProvider.refresh();
103+
repositoryCompletionItemProvider.refresh();
104+
// tslint:disable-next-line:no-floating-promises
105+
targetCompletionItemProvider.refresh();
92106
workspaceTreeProvider.refresh();
93107
}),
94108
vscode.commands.registerCommand(

0 commit comments

Comments
 (0)