@@ -8,14 +8,15 @@ import {
8
8
InlineCompletionContext ,
9
9
InlineCompletionItem ,
10
10
InlineCompletionItemProvider ,
11
- InlineCompletionList ,
12
11
Position ,
13
12
TextDocument ,
14
13
commands ,
15
14
languages ,
16
15
Disposable ,
17
16
window ,
18
17
TextEditor ,
18
+ InlineCompletionTriggerKind ,
19
+ Range ,
19
20
} from 'vscode'
20
21
import { LanguageClient } from 'vscode-languageclient'
21
22
import {
@@ -27,37 +28,63 @@ import { RecommendationService } from './recommendationService'
27
28
import {
28
29
CodeWhispererConstants ,
29
30
ReferenceHoverProvider ,
30
- ReferenceInlineProvider ,
31
31
ReferenceLogViewProvider ,
32
32
ImportAdderProvider ,
33
+ CodeSuggestionsState ,
34
+ vsCodeState ,
35
+ inlineCompletionsDebounceDelay ,
36
+ noInlineSuggestionsMsg ,
37
+ ReferenceInlineProvider ,
33
38
} 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'
34
45
35
46
export class InlineCompletionManager implements Disposable {
36
47
private disposable : Disposable
37
48
private inlineCompletionProvider : AmazonQInlineCompletionItemProvider
38
49
private languageClient : LanguageClient
39
50
private sessionManager : SessionManager
40
51
private recommendationService : RecommendationService
52
+ private lineTracker : LineTracker
53
+ private incomingGeneratingMessage : InlineGeneratingMessage
54
+ private inlineTutorialAnnotation : InlineTutorialAnnotation
41
55
private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
42
56
43
- constructor ( languageClient : LanguageClient ) {
57
+ constructor (
58
+ languageClient : LanguageClient ,
59
+ sessionManager : SessionManager ,
60
+ lineTracker : LineTracker ,
61
+ inlineTutorialAnnotation : InlineTutorialAnnotation
62
+ ) {
44
63
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
47
69
this . inlineCompletionProvider = new AmazonQInlineCompletionItemProvider (
48
70
languageClient ,
49
71
this . recommendationService ,
50
- this . sessionManager
72
+ this . sessionManager ,
73
+ this . inlineTutorialAnnotation
51
74
)
52
75
this . disposable = languages . registerInlineCompletionItemProvider (
53
76
CodeWhispererConstants . platformLanguageIds ,
54
77
this . inlineCompletionProvider
55
78
)
79
+
80
+ this . lineTracker . ready ( )
56
81
}
57
82
58
83
public dispose ( ) : void {
59
84
if ( this . disposable ) {
60
85
this . disposable . dispose ( )
86
+ this . incomingGeneratingMessage . dispose ( )
87
+ this . lineTracker . dispose ( )
61
88
}
62
89
}
63
90
@@ -97,10 +124,21 @@ export class InlineCompletionManager implements Disposable {
97
124
)
98
125
ReferenceLogViewProvider . instance . addReferenceLog ( referenceLog )
99
126
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 )
100
137
}
101
138
if ( item . mostRelevantMissingImports ?. length ) {
102
139
await ImportAdderProvider . instance . onAcceptRecommendation ( editor , item , startLine )
103
140
}
141
+ this . sessionManager . incrementSuggestionCount ( )
104
142
}
105
143
commands . registerCommand ( 'aws.amazonq.acceptInline' , onInlineAcceptance )
106
144
@@ -130,38 +168,6 @@ export class InlineCompletionManager implements Disposable {
130
168
this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
131
169
}
132
170
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 )
165
171
}
166
172
}
167
173
@@ -170,52 +176,82 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
170
176
private readonly languageClient : LanguageClient ,
171
177
private readonly recommendationService : RecommendationService ,
172
178
private readonly sessionManager : SessionManager ,
173
- private readonly isNewSession : boolean = true
179
+ private readonly inlineTutorialAnnotation : InlineTutorialAnnotation
174
180
) { }
175
181
176
- async provideInlineCompletionItems (
182
+ provideInlineCompletionItems = debounce (
183
+ this . _provideInlineCompletionItems . bind ( this ) ,
184
+ inlineCompletionsDebounceDelay ,
185
+ true
186
+ )
187
+
188
+ private async _provideInlineCompletionItems (
177
189
document : TextDocument ,
178
190
position : Position ,
179
191
context : InlineCompletionContext ,
180
192
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
+
184
207
await this . recommendationService . getAllRecommendations (
185
208
this . languageClient ,
186
209
document ,
187
210
position ,
188
211
context ,
189
212
token
190
213
)
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 )
211
222
}
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
218
255
}
219
- return items as InlineCompletionItem [ ]
220
256
}
221
257
}
0 commit comments