@@ -8,14 +8,15 @@ import {
88 InlineCompletionContext ,
99 InlineCompletionItem ,
1010 InlineCompletionItemProvider ,
11- InlineCompletionList ,
1211 Position ,
1312 TextDocument ,
1413 commands ,
1514 languages ,
1615 Disposable ,
1716 window ,
1817 TextEditor ,
18+ InlineCompletionTriggerKind ,
19+ Range ,
1920} from 'vscode'
2021import { LanguageClient } from 'vscode-languageclient'
2122import {
@@ -27,37 +28,63 @@ import { RecommendationService } from './recommendationService'
2728import {
2829 CodeWhispererConstants ,
2930 ReferenceHoverProvider ,
30- ReferenceInlineProvider ,
3131 ReferenceLogViewProvider ,
3232 ImportAdderProvider ,
33+ CodeSuggestionsState ,
34+ vsCodeState ,
35+ inlineCompletionsDebounceDelay ,
36+ noInlineSuggestionsMsg ,
37+ ReferenceInlineProvider ,
3338} from 'aws-core-vscode/codewhisperer'
39+ import { InlineGeneratingMessage } from './inlineGeneratingMessage'
40+ import { LineTracker } from './stateTracker/lineTracker'
41+ import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
42+ import { TelemetryHelper } from './telemetryHelper'
43+ import { getLogger } from 'aws-core-vscode/shared'
44+ import { debounce , messageUtils } from 'aws-core-vscode/utils'
3445
3546export class InlineCompletionManager implements Disposable {
3647 private disposable : Disposable
3748 private inlineCompletionProvider : AmazonQInlineCompletionItemProvider
3849 private languageClient : LanguageClient
3950 private sessionManager : SessionManager
4051 private recommendationService : RecommendationService
52+ private lineTracker : LineTracker
53+ private incomingGeneratingMessage : InlineGeneratingMessage
54+ private inlineTutorialAnnotation : InlineTutorialAnnotation
4155 private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
4256
43- constructor ( languageClient : LanguageClient ) {
57+ constructor (
58+ languageClient : LanguageClient ,
59+ sessionManager : SessionManager ,
60+ lineTracker : LineTracker ,
61+ inlineTutorialAnnotation : InlineTutorialAnnotation
62+ ) {
4463 this . languageClient = languageClient
45- this . sessionManager = new SessionManager ( )
46- this . recommendationService = new RecommendationService ( this . sessionManager )
64+ this . sessionManager = sessionManager
65+ this . lineTracker = lineTracker
66+ this . incomingGeneratingMessage = new InlineGeneratingMessage ( this . lineTracker )
67+ this . recommendationService = new RecommendationService ( this . sessionManager , this . incomingGeneratingMessage )
68+ this . inlineTutorialAnnotation = inlineTutorialAnnotation
4769 this . inlineCompletionProvider = new AmazonQInlineCompletionItemProvider (
4870 languageClient ,
4971 this . recommendationService ,
50- this . sessionManager
72+ this . sessionManager ,
73+ this . inlineTutorialAnnotation
5174 )
5275 this . disposable = languages . registerInlineCompletionItemProvider (
5376 CodeWhispererConstants . platformLanguageIds ,
5477 this . inlineCompletionProvider
5578 )
79+
80+ this . lineTracker . ready ( )
5681 }
5782
5883 public dispose ( ) : void {
5984 if ( this . disposable ) {
6085 this . disposable . dispose ( )
86+ this . incomingGeneratingMessage . dispose ( )
87+ this . lineTracker . dispose ( )
6188 }
6289 }
6390
@@ -97,10 +124,21 @@ export class InlineCompletionManager implements Disposable {
97124 )
98125 ReferenceLogViewProvider . instance . addReferenceLog ( referenceLog )
99126 ReferenceHoverProvider . instance . addCodeReferences ( item . insertText as string , item . references )
127+
128+ // Show codelense for 5 seconds.
129+ ReferenceInlineProvider . instance . setInlineReference (
130+ startLine ,
131+ item . insertText as string ,
132+ item . references
133+ )
134+ setTimeout ( ( ) => {
135+ ReferenceInlineProvider . instance . removeInlineReference ( )
136+ } , 5000 )
100137 }
101138 if ( item . mostRelevantMissingImports ?. length ) {
102139 await ImportAdderProvider . instance . onAcceptRecommendation ( editor , item , startLine )
103140 }
141+ this . sessionManager . incrementSuggestionCount ( )
104142 }
105143 commands . registerCommand ( 'aws.amazonq.acceptInline' , onInlineAcceptance )
106144
@@ -130,38 +168,6 @@ export class InlineCompletionManager implements Disposable {
130168 this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
131169 }
132170 commands . registerCommand ( 'aws.amazonq.rejectCodeSuggestion' , onInlineRejection )
133-
134- /*
135- We have to overwrite the prev. and next. commands because the inlineCompletionProvider only contained the current item
136- To show prev. and next. recommendation we need to re-register a new provider with the previous or next item
137- */
138-
139- const swapProviderAndShow = async ( ) => {
140- await commands . executeCommand ( 'editor.action.inlineSuggest.hide' )
141- this . disposable . dispose ( )
142- this . disposable = languages . registerInlineCompletionItemProvider (
143- CodeWhispererConstants . platformLanguageIds ,
144- new AmazonQInlineCompletionItemProvider (
145- this . languageClient ,
146- this . recommendationService ,
147- this . sessionManager ,
148- false
149- )
150- )
151- await commands . executeCommand ( 'editor.action.inlineSuggest.trigger' )
152- }
153-
154- const prevCommandHandler = async ( ) => {
155- this . sessionManager . decrementActiveIndex ( )
156- await swapProviderAndShow ( )
157- }
158- commands . registerCommand ( 'editor.action.inlineSuggest.showPrevious' , prevCommandHandler )
159-
160- const nextCommandHandler = async ( ) => {
161- this . sessionManager . incrementActiveIndex ( )
162- await swapProviderAndShow ( )
163- }
164- commands . registerCommand ( 'editor.action.inlineSuggest.showNext' , nextCommandHandler )
165171 }
166172}
167173
@@ -170,52 +176,82 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
170176 private readonly languageClient : LanguageClient ,
171177 private readonly recommendationService : RecommendationService ,
172178 private readonly sessionManager : SessionManager ,
173- private readonly isNewSession : boolean = true
179+ private readonly inlineTutorialAnnotation : InlineTutorialAnnotation
174180 ) { }
175181
176- async provideInlineCompletionItems (
182+ provideInlineCompletionItems = debounce (
183+ this . _provideInlineCompletionItems . bind ( this ) ,
184+ inlineCompletionsDebounceDelay ,
185+ true
186+ )
187+
188+ private async _provideInlineCompletionItems (
177189 document : TextDocument ,
178190 position : Position ,
179191 context : InlineCompletionContext ,
180192 token : CancellationToken
181- ) : Promise < InlineCompletionItem [ ] | InlineCompletionList > {
182- if ( this . isNewSession ) {
183- // make service requests if it's a new session
193+ ) : Promise < InlineCompletionItem [ ] > {
194+ try {
195+ vsCodeState . isRecommendationsActive = true
196+ const isAutoTrigger = context . triggerKind === InlineCompletionTriggerKind . Automatic
197+ if ( isAutoTrigger && ! CodeSuggestionsState . instance . isSuggestionsEnabled ( ) ) {
198+ // return early when suggestions are disabled with auto trigger
199+ return [ ]
200+ }
201+
202+ // tell the tutorial that completions has been triggered
203+ await this . inlineTutorialAnnotation . triggered ( context . triggerKind )
204+ TelemetryHelper . instance . setInvokeSuggestionStartTime ( )
205+ TelemetryHelper . instance . setTriggerType ( context . triggerKind )
206+
184207 await this . recommendationService . getAllRecommendations (
185208 this . languageClient ,
186209 document ,
187210 position ,
188211 context ,
189212 token
190213 )
191- }
192- // get active item from session for displaying
193- const items = this . sessionManager . getActiveRecommendation ( )
194- const session = this . sessionManager . getActiveSession ( )
195- if ( ! session || ! items . length ) {
196- return [ ]
197- }
198- const editor = window . activeTextEditor
199- for ( const item of items ) {
200- item . command = {
201- command : 'aws.amazonq.acceptInline' ,
202- title : 'On acceptance' ,
203- arguments : [
204- session . sessionId ,
205- item ,
206- editor ,
207- session . requestStartTime ,
208- position . line ,
209- session . firstCompletionDisplayLatency ,
210- ] ,
214+ // get active item from session for displaying
215+ const items = this . sessionManager . getActiveRecommendation ( )
216+ const session = this . sessionManager . getActiveSession ( )
217+ const editor = window . activeTextEditor
218+
219+ // Show message to user when manual invoke fails to produce results.
220+ if ( items . length === 0 && context . triggerKind === InlineCompletionTriggerKind . Invoke ) {
221+ void messageUtils . showTimedMessage ( noInlineSuggestionsMsg , 2000 )
211222 }
212- ReferenceInlineProvider . instance . setInlineReference (
213- position . line ,
214- item . insertText as string ,
215- item . references
216- )
217- ImportAdderProvider . instance . onShowRecommendation ( document , position . line , item )
223+
224+ if ( ! session || ! items . length || ! editor ) {
225+ getLogger ( ) . debug (
226+ `Failed to produce inline suggestion results. Received ${ items . length } items from service`
227+ )
228+ return [ ]
229+ }
230+
231+ const cursorPosition = document . validatePosition ( position )
232+ for ( const item of items ) {
233+ item . command = {
234+ command : 'aws.amazonq.acceptInline' ,
235+ title : 'On acceptance' ,
236+ arguments : [
237+ session . sessionId ,
238+ item ,
239+ editor ,
240+ session . requestStartTime ,
241+ cursorPosition . line ,
242+ session . firstCompletionDisplayLatency ,
243+ ] ,
244+ }
245+ item . range = new Range ( cursorPosition , cursorPosition )
246+ item . insertText = typeof item . insertText === 'string' ? item . insertText : item . insertText . value
247+ ImportAdderProvider . instance . onShowRecommendation ( document , cursorPosition . line , item )
248+ }
249+ return items as InlineCompletionItem [ ]
250+ } catch ( e ) {
251+ getLogger ( 'amazonqLsp' ) . error ( 'Failed to provide completion items: %O' , e )
252+ return [ ]
253+ } finally {
254+ vsCodeState . isRecommendationsActive = false
218255 }
219- return items as InlineCompletionItem [ ]
220256 }
221257}
0 commit comments