@@ -29,12 +29,18 @@ import {
29
29
QueryRepomapIndexRequestType ,
30
30
GetRepomapIndexJSONRequestType ,
31
31
Usage ,
32
+ GetContextCommandItemsRequestType ,
33
+ ContextCommandItem ,
34
+ GetIndexSequenceNumberRequestType ,
35
+ GetContextCommandPromptRequestType ,
36
+ AdditionalContextPrompt ,
32
37
} from './types'
33
38
import { Writable } from 'stream'
34
39
import { CodeWhispererSettings } from '../../codewhisperer/util/codewhispererSettings'
35
40
import { fs } from '../../shared/fs/fs'
36
41
import { getLogger } from '../../shared/logger/logger'
37
42
import globals from '../../shared/extensionGlobals'
43
+ import { waitUntil } from '../../shared/utilities/timeoutUtils'
38
44
39
45
const localize = nls . loadMessageBundle ( )
40
46
@@ -168,6 +174,66 @@ export class LspClient {
168
174
throw e
169
175
}
170
176
}
177
+
178
+ async getContextCommandItems ( ) : Promise < ContextCommandItem [ ] > {
179
+ try {
180
+ const workspaceFolders = vscode . workspace . workspaceFolders || [ ]
181
+ const request = JSON . stringify ( {
182
+ workspaceFolders : workspaceFolders . map ( ( it ) => it . uri . fsPath ) ,
183
+ } )
184
+ const resp : any = await this . client ?. sendRequest (
185
+ GetContextCommandItemsRequestType ,
186
+ await this . encrypt ( request )
187
+ )
188
+ return resp
189
+ } catch ( e ) {
190
+ getLogger ( ) . error ( `LspClient: getContextCommandItems error: ${ e } ` )
191
+ throw e
192
+ }
193
+ }
194
+
195
+ async getContextCommandPrompt ( contextCommandItems : ContextCommandItem [ ] ) : Promise < AdditionalContextPrompt [ ] > {
196
+ try {
197
+ const request = JSON . stringify ( {
198
+ contextCommands : contextCommandItems ,
199
+ } )
200
+ const resp : any = await this . client ?. sendRequest (
201
+ GetContextCommandPromptRequestType ,
202
+ await this . encrypt ( request )
203
+ )
204
+ return resp
205
+ } catch ( e ) {
206
+ getLogger ( ) . error ( `LspClient: getContextCommandPrompt error: ${ e } ` )
207
+ throw e
208
+ }
209
+ }
210
+
211
+ async getIndexSequenceNumber ( ) : Promise < number > {
212
+ try {
213
+ const request = JSON . stringify ( { } )
214
+ const resp : any = await this . client ?. sendRequest (
215
+ GetIndexSequenceNumberRequestType ,
216
+ await this . encrypt ( request )
217
+ )
218
+ return resp
219
+ } catch ( e ) {
220
+ getLogger ( ) . error ( `LspClient: getIndexSequenceNumber error: ${ e } ` )
221
+ throw e
222
+ }
223
+ }
224
+
225
+ async waitUntilReady ( ) {
226
+ return waitUntil (
227
+ async ( ) => {
228
+ if ( this . client === undefined ) {
229
+ return false
230
+ }
231
+ await this . client . onReady ( )
232
+ return true
233
+ } ,
234
+ { interval : 500 , timeout : 60_000 * 3 , truthy : true }
235
+ )
236
+ }
171
237
}
172
238
/**
173
239
* Activates the language server, this will start LSP server running over IPC protocol.
@@ -249,6 +315,37 @@ export async function activate(extensionContext: ExtensionContext) {
249
315
250
316
let savedDocument : vscode . Uri | undefined = undefined
251
317
318
+ const onAdd = async ( filePaths : string [ ] ) => {
319
+ const indexSeqNum = await LspClient . instance . getIndexSequenceNumber ( )
320
+ await LspClient . instance . updateIndex ( filePaths , 'add' )
321
+ await waitUntil (
322
+ async ( ) => {
323
+ const newIndexSeqNum = await LspClient . instance . getIndexSequenceNumber ( )
324
+ if ( newIndexSeqNum > indexSeqNum ) {
325
+ await vscode . commands . executeCommand ( `aws.amazonq.updateContextCommandItems` )
326
+ return true
327
+ }
328
+ return false
329
+ } ,
330
+ { interval : 500 , timeout : 5_000 , truthy : true }
331
+ )
332
+ }
333
+ const onRemove = async ( filePaths : string [ ] ) => {
334
+ const indexSeqNum = await LspClient . instance . getIndexSequenceNumber ( )
335
+ await LspClient . instance . updateIndex ( filePaths , 'remove' )
336
+ await waitUntil (
337
+ async ( ) => {
338
+ const newIndexSeqNum = await LspClient . instance . getIndexSequenceNumber ( )
339
+ if ( newIndexSeqNum > indexSeqNum ) {
340
+ await vscode . commands . executeCommand ( `aws.amazonq.updateContextCommandItems` )
341
+ return true
342
+ }
343
+ return false
344
+ } ,
345
+ { interval : 500 , timeout : 5_000 , truthy : true }
346
+ )
347
+ }
348
+
252
349
toDispose . push (
253
350
vscode . workspace . onDidSaveTextDocument ( ( document ) => {
254
351
if ( document . uri . scheme !== 'file' ) {
@@ -260,18 +357,23 @@ export async function activate(extensionContext: ExtensionContext) {
260
357
if ( savedDocument && editor && editor . document . uri . fsPath !== savedDocument . fsPath ) {
261
358
void LspClient . instance . updateIndex ( [ savedDocument . fsPath ] , 'update' )
262
359
}
360
+ // user created a new empty file using File -> New File
361
+ // these events will not be captured by vscode.workspace.onDidCreateFiles
362
+ // because it was created by File Explorer(Win) or Finder(MacOS)
363
+ // TODO: consider using a high performance fs watcher
364
+ if ( editor ?. document . getText ( ) . length === 0 ) {
365
+ void onAdd ( [ editor . document . uri . fsPath ] )
366
+ }
263
367
} ) ,
264
- vscode . workspace . onDidCreateFiles ( ( e ) => {
265
- void LspClient . instance . updateIndex (
266
- e . files . map ( ( f ) => f . fsPath ) ,
267
- 'add'
268
- )
368
+ vscode . workspace . onDidCreateFiles ( async ( e ) => {
369
+ await onAdd ( e . files . map ( ( f ) => f . fsPath ) )
269
370
} ) ,
270
- vscode . workspace . onDidDeleteFiles ( ( e ) => {
271
- void LspClient . instance . updateIndex (
272
- e . files . map ( ( f ) => f . fsPath ) ,
273
- 'remove'
274
- )
371
+ vscode . workspace . onDidDeleteFiles ( async ( e ) => {
372
+ await onRemove ( e . files . map ( ( f ) => f . fsPath ) )
373
+ } ) ,
374
+ vscode . workspace . onDidRenameFiles ( async ( e ) => {
375
+ await onRemove ( e . files . map ( ( f ) => f . oldUri . fsPath ) )
376
+ await onAdd ( e . files . map ( ( f ) => f . newUri . fsPath ) )
275
377
} )
276
378
)
277
379
0 commit comments