Skip to content

Commit 60125d3

Browse files
committed
Support completion of external targets
1 parent 9c6de13 commit 60125d3

File tree

1 file changed

+39
-14
lines changed

1 file changed

+39
-14
lines changed

src/completion-provider/bazel_completion_provider.ts

+39-14
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,15 @@ function getCandidateTargetFromDocumentPosition(
3939
const linePrefix = document
4040
.lineAt(position)
4141
.text.substring(0, position.character);
42+
const atIndex = linePrefix.lastIndexOf("@");
4243
const doubleSlashIndex = linePrefix.lastIndexOf("//");
4344
const colonIndex = linePrefix.lastIndexOf(":");
44-
const index = doubleSlashIndex !== -1 ? doubleSlashIndex : colonIndex;
45+
const index =
46+
atIndex !== -1
47+
? atIndex
48+
: doubleSlashIndex !== -1
49+
? doubleSlashIndex
50+
: colonIndex;
4551
if (index === -1) {
4652
return undefined;
4753
}
@@ -75,7 +81,7 @@ function getAbsoluteLabel(
7581
target: string,
7682
document: vscode.TextDocument,
7783
): string {
78-
if (target.startsWith("//")) {
84+
if (target.startsWith("//") || target.startsWith("@")) {
7985
return target;
8086
}
8187
const workspace = BazelWorkspaceInfo.fromDocument(document);
@@ -89,16 +95,19 @@ function getAbsoluteLabel(
8995
return `${packageLabel}${target}`;
9096
}
9197

98+
function getRepositoryName(target: string): string {
99+
const endOfRepo = target.indexOf("//");
100+
return endOfRepo <= 0 ? "" : target.substring(1, endOfRepo);
101+
}
102+
92103
export class BazelCompletionItemProvider
93104
implements vscode.CompletionItemProvider {
94-
private targets: string[] = [];
105+
private readonly targetsInRepo = new Map<string, Promise<string[]>>();
95106

96107
/**
97108
* Returns completion items matching the given prefix.
98-
*
99-
* Only label started with `//` or `:` is supported at the moment.
100109
*/
101-
public provideCompletionItems(
110+
public async provideCompletionItems(
102111
document: vscode.TextDocument,
103112
position: vscode.Position,
104113
) {
@@ -111,13 +120,14 @@ export class BazelCompletionItemProvider
111120
}
112121

113122
candidateTarget = getAbsoluteLabel(candidateTarget, document);
114-
115123
if (!candidateTarget.endsWith("/") && !candidateTarget.endsWith(":")) {
116124
candidateTarget = stripLastPackageOrTargetName(candidateTarget);
117125
}
118126

127+
const repo = getRepositoryName(candidateTarget);
128+
const targets = await this.getTargetsDefinedInRepo(repo);
119129
const completionItems = new Array<vscode.CompletionItem>();
120-
this.targets.forEach((target) => {
130+
targets.forEach((target) => {
121131
if (!target.startsWith(candidateTarget)) {
122132
return;
123133
}
@@ -141,12 +151,27 @@ export class BazelCompletionItemProvider
141151
* Runs a bazel query command to acquire labels of all the targets in the
142152
* workspace.
143153
*/
144-
public async refresh() {
145-
const queryTargets = await queryQuickPickTargets("kind('.* rule', ...)");
146-
if (queryTargets.length !== 0) {
147-
this.targets = queryTargets.map((queryTarget) => {
148-
return queryTarget.label;
149-
});
154+
public async refresh(): Promise<void> {
155+
this.targetsInRepo.clear();
156+
await this.queryAndCacheTargets();
157+
}
158+
159+
private async getTargetsDefinedInRepo(repository = ""): Promise<string[]> {
160+
const deferred = this.targetsInRepo.get(repository);
161+
if (deferred) {
162+
return await deferred;
150163
}
164+
return await this.queryAndCacheTargets(repository);
165+
}
166+
167+
private async queryAndCacheTargets(repository = ""): Promise<string[]> {
168+
const queryTargets = async () => {
169+
const query = `kind('.* rule', @${repository}//...)`;
170+
const targets = await queryQuickPickTargets(query);
171+
return targets.map((target) => target.label);
172+
};
173+
const deferred = queryTargets();
174+
this.targetsInRepo.set(repository, deferred);
175+
return await deferred;
151176
}
152177
}

0 commit comments

Comments
 (0)