@@ -18,13 +18,16 @@ import { getLogger } from '../../shared/logger/logger'
18
18
import { TelemetryHelper } from '../util/telemetryHelper'
19
19
import { runtimeLanguageContext } from '../util/runtimeLanguageContext'
20
20
import { Commands } from '../../shared/vscode/commands2'
21
- import { getPrefixSuffixOverlap } from '../util/commonUtil'
21
+ import { getPrefixSuffixOverlap , isVscHavingRegressionInlineCompletionApi } from '../util/commonUtil'
22
22
import globals from '../../shared/extensionGlobals'
23
23
import { AuthUtil } from '../util/authUtil'
24
24
import { shared } from '../../shared/utilities/functionUtils'
25
25
import { ImportAdderProvider } from './importAdderProvider'
26
+ import * as AsyncLock from 'async-lock'
27
+ import { updateInlineLockKey } from '../models/constants'
26
28
27
29
const performance = globalThis . performance ?? require ( 'perf_hooks' ) . performance
30
+ const lock = new AsyncLock ( { maxPending : 1 } )
28
31
29
32
export class CWInlineCompletionItemProvider implements vscode . InlineCompletionItemProvider {
30
33
private activeItemIndex : number | undefined
@@ -219,8 +222,8 @@ const nextCommand = Commands.declare(
219
222
}
220
223
)
221
224
222
- const hideCommand = Commands . declare (
223
- 'editor.action.inlineSuggest.hide ' ,
225
+ const rejectCommand = Commands . declare (
226
+ 'aws.codeWhisperer.rejectCodeSuggestion ' ,
224
227
( service : InlineCompletionService ) => async ( ) => {
225
228
await service . clearInlineCompletionStates ( vscode . window . activeTextEditor )
226
229
}
@@ -234,15 +237,15 @@ export class InlineCompletionService {
234
237
private _timer ?: NodeJS . Timer
235
238
private _showRecommendationTimer ?: NodeJS . Timer
236
239
private documentUri : vscode . Uri | undefined = undefined
237
- private hide : vscode . Disposable
240
+ private reject : vscode . Disposable
238
241
private next : vscode . Disposable
239
242
private prev : vscode . Disposable
240
243
private _isPaginationRunning = false
241
244
242
245
constructor ( ) {
243
246
this . prev = prevCommand . register ( this )
244
247
this . next = nextCommand . register ( this )
245
- this . hide = hideCommand . register ( this )
248
+ this . reject = rejectCommand . register ( this )
246
249
RecommendationHandler . instance . onDidReceiveRecommendation ( e => {
247
250
this . startShowRecommendationTimer ( )
248
251
} )
@@ -287,20 +290,20 @@ export class InlineCompletionService {
287
290
private registerCommandOverrides ( ) {
288
291
this . prev = prevCommand . register ( this )
289
292
this . next = nextCommand . register ( this )
290
- this . hide = hideCommand . register ( this )
293
+ this . reject = rejectCommand . register ( this )
291
294
}
292
295
293
296
subscribeSuggestionCommands ( ) {
294
297
this . disposeCommandOverrides ( )
295
298
this . registerCommandOverrides ( )
296
299
globals . context . subscriptions . push ( this . prev )
297
300
globals . context . subscriptions . push ( this . next )
298
- globals . context . subscriptions . push ( this . hide )
301
+ globals . context . subscriptions . push ( this . reject )
299
302
}
300
303
301
304
private disposeCommandOverrides ( ) {
302
305
this . prev . dispose ( )
303
- this . hide . dispose ( )
306
+ this . reject . dispose ( )
304
307
this . next . dispose ( )
305
308
}
306
309
@@ -347,6 +350,11 @@ export class InlineCompletionService {
347
350
this . disposeInlineCompletion ( )
348
351
vscode . commands . executeCommand ( 'aws.codeWhisperer.refreshStatusBar' )
349
352
this . disposeCommandOverrides ( )
353
+ // fix a regression that requires user to hit Esc twice to clear inline ghost text
354
+ // because disposing a provider does not clear the UX
355
+ if ( isVscHavingRegressionInlineCompletionApi ( ) ) {
356
+ await vscode . commands . executeCommand ( 'editor.action.inlineSuggest.hide' )
357
+ }
350
358
} finally {
351
359
this . clearRejectionTimer ( )
352
360
}
@@ -360,7 +368,7 @@ export class InlineCompletionService {
360
368
if ( this . isSuggestionVisible ( ) ) {
361
369
// to force refresh the visual cue so that the total recommendation count can be updated
362
370
const index = this . inlineCompletionProvider ?. getActiveItemIndex
363
- await this . showRecommendation ( index ? index : 0 , true )
371
+ await this . showRecommendation ( index ? index : 0 , false )
364
372
return
365
373
}
366
374
if (
@@ -440,34 +448,49 @@ export class InlineCompletionService {
440
448
TelemetryHelper . instance . tryRecordClientComponentLatency ( editor . document . languageId )
441
449
}
442
450
443
- async showRecommendation ( indexShift : number , isFirstRecommendation : boolean = false ) {
444
- this . inlineCompletionProvider = new CWInlineCompletionItemProvider (
445
- this . inlineCompletionProvider ?. getActiveItemIndex ,
446
- indexShift
447
- )
448
- this . inlineCompletionProviderDisposable ?. dispose ( )
449
- // when suggestion is active, registering a new provider will let VS Code invoke inline API automatically
450
- this . inlineCompletionProviderDisposable = vscode . languages . registerInlineCompletionItemProvider (
451
- Object . assign ( [ ] , CodeWhispererConstants . supportedLanguages ) ,
452
- this . inlineCompletionProvider
453
- )
454
- if ( isFirstRecommendation ) {
455
- await vscode . commands . executeCommand ( `editor.action.inlineSuggest.trigger` )
456
- if ( vscode . window . activeTextEditor ) {
457
- const languageContext = runtimeLanguageContext . getLanguageContext (
458
- vscode . window . activeTextEditor . document . languageId
459
- )
460
- telemetry . codewhisperer_perceivedLatency . emit ( {
461
- codewhispererRequestId : RecommendationHandler . instance . requestId ,
462
- codewhispererSessionId : RecommendationHandler . instance . sessionId ,
463
- codewhispererTriggerType : TelemetryHelper . instance . triggerType ,
464
- codewhispererCompletionType : TelemetryHelper . instance . completionType ,
465
- codewhispererLanguage : languageContext . language ,
466
- duration : performance . now ( ) - RecommendationHandler . instance . lastInvocationTime ,
467
- passive : true ,
468
- credentialStartUrl : TelemetryHelper . instance . startUrl ,
469
- } )
451
+ async showRecommendation ( indexShift : number , noSuggestionVisible : boolean = false ) {
452
+ await lock . acquire ( updateInlineLockKey , async ( ) => {
453
+ const inlineCompletionProvider = new CWInlineCompletionItemProvider (
454
+ this . inlineCompletionProvider ?. getActiveItemIndex ,
455
+ indexShift
456
+ )
457
+ this . inlineCompletionProviderDisposable ?. dispose ( )
458
+ // when suggestion is active, registering a new provider will let VS Code invoke inline API automatically
459
+ this . inlineCompletionProviderDisposable = vscode . languages . registerInlineCompletionItemProvider (
460
+ Object . assign ( [ ] , CodeWhispererConstants . supportedLanguages ) ,
461
+ inlineCompletionProvider
462
+ )
463
+ this . inlineCompletionProvider = inlineCompletionProvider
464
+
465
+ if ( isVscHavingRegressionInlineCompletionApi ( ) && ! noSuggestionVisible ) {
466
+ // fix a regression in new VS Code when disposing and re-registering
467
+ // a new provider does not auto refresh the inline suggestion widget
468
+ // by manually refresh it
469
+ await vscode . commands . executeCommand ( 'editor.action.inlineSuggest.hide' )
470
+ await vscode . commands . executeCommand ( 'editor.action.inlineSuggest.trigger' )
471
+ }
472
+ if ( noSuggestionVisible ) {
473
+ await vscode . commands . executeCommand ( `editor.action.inlineSuggest.trigger` )
474
+ this . sendPerceivedLatencyTelemetry ( )
470
475
}
476
+ } )
477
+ }
478
+
479
+ private sendPerceivedLatencyTelemetry ( ) {
480
+ if ( vscode . window . activeTextEditor ) {
481
+ const languageContext = runtimeLanguageContext . getLanguageContext (
482
+ vscode . window . activeTextEditor . document . languageId
483
+ )
484
+ telemetry . codewhisperer_perceivedLatency . emit ( {
485
+ codewhispererRequestId : RecommendationHandler . instance . requestId ,
486
+ codewhispererSessionId : RecommendationHandler . instance . sessionId ,
487
+ codewhispererTriggerType : TelemetryHelper . instance . triggerType ,
488
+ codewhispererCompletionType : TelemetryHelper . instance . completionType ,
489
+ codewhispererLanguage : languageContext . language ,
490
+ duration : performance . now ( ) - RecommendationHandler . instance . lastInvocationTime ,
491
+ passive : true ,
492
+ credentialStartUrl : TelemetryHelper . instance . startUrl ,
493
+ } )
471
494
}
472
495
}
473
496
0 commit comments