@@ -39,9 +39,15 @@ function getCandidateTargetFromDocumentPosition(
39
39
const linePrefix = document
40
40
. lineAt ( position )
41
41
. text . substring ( 0 , position . character ) ;
42
+ const atIndex = linePrefix . lastIndexOf ( "@" ) ;
42
43
const doubleSlashIndex = linePrefix . lastIndexOf ( "//" ) ;
43
44
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 ;
45
51
if ( index === - 1 ) {
46
52
return undefined ;
47
53
}
@@ -75,7 +81,7 @@ function getAbsoluteLabel(
75
81
target : string ,
76
82
document : vscode . TextDocument ,
77
83
) : string {
78
- if ( target . startsWith ( "//" ) ) {
84
+ if ( target . startsWith ( "//" ) || target . startsWith ( "@" ) ) {
79
85
return target ;
80
86
}
81
87
const workspace = BazelWorkspaceInfo . fromDocument ( document ) ;
@@ -89,16 +95,19 @@ function getAbsoluteLabel(
89
95
return `${ packageLabel } ${ target } ` ;
90
96
}
91
97
98
+ function getRepositoryName ( target : string ) : string {
99
+ const endOfRepo = target . indexOf ( "//" ) ;
100
+ return endOfRepo <= 0 ? "" : target . substring ( 1 , endOfRepo ) ;
101
+ }
102
+
92
103
export class BazelCompletionItemProvider
93
104
implements vscode . CompletionItemProvider {
94
- private targets : string [ ] = [ ] ;
105
+ private readonly targetsInRepo = new Map < string , Promise < string [ ] > > ( ) ;
95
106
96
107
/**
97
108
* Returns completion items matching the given prefix.
98
- *
99
- * Only label started with `//` or `:` is supported at the moment.
100
109
*/
101
- public provideCompletionItems (
110
+ public async provideCompletionItems (
102
111
document : vscode . TextDocument ,
103
112
position : vscode . Position ,
104
113
) {
@@ -111,13 +120,14 @@ export class BazelCompletionItemProvider
111
120
}
112
121
113
122
candidateTarget = getAbsoluteLabel ( candidateTarget , document ) ;
114
-
115
123
if ( ! candidateTarget . endsWith ( "/" ) && ! candidateTarget . endsWith ( ":" ) ) {
116
124
candidateTarget = stripLastPackageOrTargetName ( candidateTarget ) ;
117
125
}
118
126
127
+ const repo = getRepositoryName ( candidateTarget ) ;
128
+ const targets = await this . getTargetsDefinedInRepo ( repo ) ;
119
129
const completionItems = new Array < vscode . CompletionItem > ( ) ;
120
- this . targets . forEach ( ( target ) => {
130
+ targets . forEach ( ( target ) => {
121
131
if ( ! target . startsWith ( candidateTarget ) ) {
122
132
return ;
123
133
}
@@ -141,12 +151,27 @@ export class BazelCompletionItemProvider
141
151
* Runs a bazel query command to acquire labels of all the targets in the
142
152
* workspace.
143
153
*/
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 ;
150
163
}
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 ;
151
176
}
152
177
}
0 commit comments