@@ -13,7 +13,7 @@ import { IVSCodeExtensionContext } from '../../../platform/extContext/common/ext
1313import { JointCompletionsProviderStrategy , JointCompletionsProviderTriggerChangeStrategy } from '../../../platform/inlineEdits/common/dataTypes/jointCompletionsProviderOptions' ;
1414import { InlineEditRequestLogContext } from '../../../platform/inlineEdits/common/inlineEditLogContext' ;
1515import { ObservableGit } from '../../../platform/inlineEdits/common/observableGit' ;
16- import { shortenOpportunityId } from '../../../platform/inlineEdits/common/utils/utils' ;
16+ import { checkIfCursorAtEndOfLine , shortenOpportunityId } from '../../../platform/inlineEdits/common/utils/utils' ;
1717import { NesHistoryContextProvider } from '../../../platform/inlineEdits/common/workspaceEditTracker/nesHistoryContextProvider' ;
1818import { ILogService } from '../../../platform/log/common/logService' ;
1919import * as errors from '../../../util/common/errors' ;
@@ -239,6 +239,7 @@ type LastNesSuggestion = {
239239 docUri : vscode . Uri ;
240240 docVersionId : number ;
241241 docWithNesEditApplied : StringText ;
242+ completionItem : NesCompletionItem ;
242243} ;
243244
244245class JointCompletionsProvider extends Disposable implements vscode . InlineCompletionItemProvider {
@@ -317,11 +318,57 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
317318 switch ( strategy ) {
318319 case JointCompletionsProviderStrategy . Regular :
319320 return this . provideInlineCompletionItemsRegular ( document , position , context , token , tracer ) ;
321+ case JointCompletionsProviderStrategy . CursorEndOfLine :
322+ return this . provideInlineCompletionItemsCursorEndOfLine ( document , position , context , token , tracer ) ;
320323 default :
321324 assertNever ( strategy ) ;
322325 }
323326 }
324327
328+ private async provideInlineCompletionItemsCursorEndOfLine ( document : vscode . TextDocument , position : vscode . Position , context : vscode . InlineCompletionContext , token : vscode . CancellationToken , tracer : ITracer ) : Promise < SingularCompletionList | undefined > {
329+ const sw = new StopWatch ( ) ;
330+
331+ this . _requestsInFlight . add ( token ) ;
332+ const disp = token . onCancellationRequested ( ( ) => {
333+ this . _requestsInFlight . delete ( token ) ;
334+ } ) ;
335+ try {
336+ if ( this . _completionsProvider === undefined && this . _inlineEditProvider === undefined ) {
337+ tracer . returns ( 'neither completions nor NES provider available' ) ;
338+ return undefined ;
339+
340+ } else if ( this . _completionsProvider === undefined && this . _inlineEditProvider !== undefined ) {
341+ tracer . trace ( 'only NES provider is available, invoking it' ) ;
342+ const r = await this . _invokeNESProvider ( tracer , document , position , false , context , token , sw ) ;
343+ return r ? toInlineEditsList ( r ) : undefined ;
344+
345+ } else if ( this . _completionsProvider !== undefined && this . _inlineEditProvider === undefined ) {
346+ tracer . trace ( 'only completions provider is available, invoking it' ) ;
347+ const r = await this . _invokeCompletionsProvider ( tracer , document , position , context , token , sw ) ;
348+ return r ? toCompletionsList ( r ) : undefined ;
349+ } else {
350+
351+ const cursorLine = document . lineAt ( position . line ) . text ;
352+ const isCursorAtEndOfLine = checkIfCursorAtEndOfLine ( cursorLine , position . character ) ;
353+
354+ if ( isCursorAtEndOfLine ) {
355+ tracer . trace ( 'cursor is at end of line, invoking ghost-text provider only' ) ;
356+ const r = await this . _invokeCompletionsProvider ( tracer , document , position , context , token , sw ) ;
357+ return r ? toCompletionsList ( r ) : undefined ;
358+ }
359+
360+ const r = await this . _invokeNESProvider ( tracer , document , position , false , context , token , sw ) ;
361+ return r ? toInlineEditsList ( r ) : undefined ;
362+ }
363+ } finally {
364+ if ( ! token . isCancellationRequested ) {
365+ this . _tracer . trace ( 'request in flight: false -- due to provider finishing' ) ;
366+ this . _requestsInFlight . delete ( token ) ;
367+ }
368+ disp . dispose ( ) ;
369+ }
370+ }
371+
325372 private lastNesSuggestion : null | LastNesSuggestion = null ;
326373 private provideInlineCompletionItemsInvocationCount = 0 ;
327374
@@ -358,7 +405,7 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
358405 return list ;
359406 }
360407
361- const firstItem = list . items [ 0 ] ;
408+ const firstItem = ( list . items as NesCompletionItem [ ] ) [ 0 ] ;
362409 if ( ! firstItem . range || typeof firstItem . insertText !== 'string' ) {
363410 return list ;
364411 }
@@ -373,6 +420,7 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
373420 docUri : document . uri ,
374421 docVersionId,
375422 docWithNesEditApplied : new StringText ( applied ) ,
423+ completionItem : firstItem ,
376424 } ;
377425
378426 return list ;
@@ -418,21 +466,21 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
418466
419467 tracer . trace ( 'requesting completions and/or NES' ) ;
420468
421- if ( ! lastNesSuggestion ) {
469+ if ( ! lastNesSuggestion || ! lastNesSuggestion . completionItem . wasShown ) {
422470 // prefer completions unless there are none
423- tracer . trace ( `no last NES suggestion to consider ` ) ;
424- const completionsP = this . _invokeCompletionsProvider ( tracer , document , position , context , tokens , sw ) ;
425- const nesP = this . _invokeNESProvider ( tracer , document , position , true , context , tokens , sw ) ;
471+ tracer . trace ( `defaulting to yielding to completions; last NES suggestion is ${ lastNesSuggestion ? 'not shown' : 'not available' } ` ) ;
472+ const completionsP = this . _invokeCompletionsProvider ( tracer , document , position , context , tokens . completionsCts . token , sw ) ;
473+ const nesP = this . _invokeNESProvider ( tracer , document , position , true , context , tokens . nesCts . token , sw ) ;
426474 return this . _returnCompletionsOrOtherwiseNES ( completionsP , nesP , docSnapshot , sw , tracer , tokens ) ;
427475 }
428476
429477 tracer . trace ( `last NES suggestion is for the current document, checking if it agrees with the current suggestion` ) ;
430478
431479 const enforceCacheDelay = ( lastNesSuggestion . docVersionId !== document . version ) ;
432- const nesP = this . _invokeNESProvider ( tracer , document , position , enforceCacheDelay , context , tokens , sw ) ;
480+ const nesP = this . _invokeNESProvider ( tracer , document , position , enforceCacheDelay , context , tokens . nesCts . token , sw ) ;
433481 if ( ! nesP ) {
434482 tracer . trace ( `no NES provider` ) ;
435- const completionsP = this . _invokeCompletionsProvider ( tracer , document , position , context , tokens , sw ) ;
483+ const completionsP = this . _invokeCompletionsProvider ( tracer , document , position , context , tokens . completionsCts . token , sw ) ;
436484 return this . _returnCompletionsOrOtherwiseNES ( completionsP , nesP , docSnapshot , sw , tracer , tokens ) ;
437485 }
438486
@@ -467,7 +515,7 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
467515 }
468516
469517 tracer . trace ( `the NES provider did not return in ${ NES_CACHE_WAIT_MS } ms so we are triggering the completions provider too` ) ;
470- const completionsP = this . _invokeCompletionsProvider ( tracer , document , position , context , tokens , sw ) ;
518+ const completionsP = this . _invokeCompletionsProvider ( tracer , document , position , context , tokens . completionsCts . token , sw ) ;
471519
472520 const suggestionsList = await raceCancellation (
473521 Promise . race ( coalesce ( [
@@ -497,12 +545,12 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
497545 return this . _returnCompletionsOrOtherwiseNES ( completionsP , nesP , docSnapshot , sw , tracer , tokens ) ;
498546 }
499547
500- private _invokeNESProvider ( tracer : ITracer , document : vscode . TextDocument , position : vscode . Position , enforceCacheDelay : boolean , context : vscode . InlineCompletionContext , tokens : { coreToken : CancellationToken ; completionsCts : CancellationTokenSource ; nesCts : CancellationTokenSource } , sw : StopWatch ) {
548+ private _invokeNESProvider ( tracer : ITracer , document : vscode . TextDocument , position : vscode . Position , enforceCacheDelay : boolean , context : vscode . InlineCompletionContext , ct : CancellationToken , sw : StopWatch ) {
501549 const nesContext : NESInlineCompletionContext = { ...context , enforceCacheDelay } ;
502550 let nesP : Promise < NesCompletionList | undefined > | undefined ;
503551 if ( this . _inlineEditProvider ) {
504552 tracer . trace ( `- requesting NES provideInlineCompletionItems` ) ;
505- nesP = this . _inlineEditProvider . provideInlineCompletionItems ( document , position , nesContext , tokens . nesCts . token ) ;
553+ nesP = this . _inlineEditProvider . provideInlineCompletionItems ( document , position , nesContext , ct ) ;
506554 nesP . then ( ( nesR ) => {
507555 tracer . trace ( `got NES response in ${ sw . elapsed ( ) } ms -- ${ nesR === undefined ? 'undefined' : `with ${ nesR . items . length } items` } ` ) ;
508556 } ) . catch ( ( e ) => {
@@ -515,18 +563,18 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
515563 return nesP ;
516564 }
517565
518- private _invokeCompletionsProvider ( tracer : ITracer , document : vscode . TextDocument , position : vscode . Position , context : vscode . InlineCompletionContext , tokens : { coreToken : CancellationToken ; completionsCts : CancellationTokenSource ; nesCts : CancellationTokenSource } , sw : StopWatch ) {
566+ private _invokeCompletionsProvider ( tracer : ITracer , document : vscode . TextDocument , position : vscode . Position , context : vscode . InlineCompletionContext , ct : CancellationToken , sw : StopWatch ) {
519567 let completionsP : Promise < vscode . InlineCompletionList | undefined > | undefined ;
520568 if ( this . _completionsProvider ) {
521- this . _completionsRequestsInFlight . add ( tokens . completionsCts . token ) ;
522- const disp = tokens . completionsCts . token . onCancellationRequested ( ( ) => this . _completionsRequestsInFlight . delete ( tokens . completionsCts . token ) ) ;
569+ this . _completionsRequestsInFlight . add ( ct ) ;
570+ const disp = ct . onCancellationRequested ( ( ) => this . _completionsRequestsInFlight . delete ( ct ) ) ;
523571 const cleanup = ( ) => {
524- this . _completionsRequestsInFlight . delete ( tokens . completionsCts . token ) ;
572+ this . _completionsRequestsInFlight . delete ( ct ) ;
525573 disp . dispose ( ) ;
526574 } ;
527575 try { // in case the provider throws synchronously
528576 tracer . trace ( `- requesting completions provideInlineCompletionItems` ) ;
529- completionsP = this . _completionsProvider . provideInlineCompletionItems ( document , position , context , tokens . completionsCts . token ) ;
577+ completionsP = this . _completionsProvider . provideInlineCompletionItems ( document , position , context , ct ) ;
530578 completionsP . then ( ( completionsR ) => {
531579 tracer . trace ( `got completions response in ${ sw . elapsed ( ) } ms -- ${ completionsR === undefined ? 'undefined' : `with ${ completionsR . items . length } items` } ` ) ;
532580 } ) . catch ( ( e ) => {
0 commit comments