Skip to content

Commit 40ae84a

Browse files
committed
Merge remote-tracking branch 'upstream/master' into disable-inline-tutorial
2 parents e4feefb + b980406 commit 40ae84a

31 files changed

+1027
-148
lines changed

package-lock.json

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"skippedTestReport": "ts-node ./scripts/skippedTestReport.ts ./packages/amazonq/test/e2e/"
4242
},
4343
"devDependencies": {
44-
"@aws-toolkits/telemetry": "^1.0.328",
44+
"@aws-toolkits/telemetry": "^1.0.329",
4545
"@playwright/browser-chromium": "^1.43.1",
4646
"@stylistic/eslint-plugin": "^2.11.0",
4747
"@types/he": "^1.2.3",
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Let Enter invoke auto completion more consistently"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Use documentChangeEvent as auto trigger condition"
4+
}

packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ export async function showEdits(
2929
const { svgImage, startLine, newCode, origionalCodeHighlightRange } =
3030
await svgGenerationService.generateDiffSvg(currentFile, item.insertText as string)
3131

32+
// TODO: To investigate why it fails and patch [generateDiffSvg]
33+
if (newCode.length === 0) {
34+
getLogger('nextEditPrediction').warn('not able to apply provided edit suggestion, skip rendering')
35+
return
36+
}
37+
3238
if (svgImage) {
3339
// display the SVG image
3440
await displaySvgDecoration(

packages/amazonq/src/app/inline/completion.ts

Lines changed: 82 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
vsCodeState,
3535
inlineCompletionsDebounceDelay,
3636
noInlineSuggestionsMsg,
37-
ReferenceInlineProvider,
3837
getDiagnosticsDifferences,
3938
getDiagnosticsOfCurrentFile,
4039
toIdeDiagnostics,
@@ -111,88 +110,88 @@ export class InlineCompletionManager implements Disposable {
111110
startLine: number,
112111
firstCompletionDisplayLatency?: number
113112
) => {
114-
// TODO: also log the seen state for other suggestions in session
115-
// Calculate timing metrics before diagnostic delay
116-
const totalSessionDisplayTime = performance.now() - requestStartTime
117-
await sleep(1000)
118-
const diagnosticDiff = getDiagnosticsDifferences(
119-
this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept,
120-
getDiagnosticsOfCurrentFile()
121-
)
122-
const params: LogInlineCompletionSessionResultsParams = {
123-
sessionId: sessionId,
124-
completionSessionResult: {
125-
[item.itemId]: {
126-
seen: true,
127-
accepted: true,
128-
discarded: false,
129-
},
130-
},
131-
totalSessionDisplayTime: totalSessionDisplayTime,
132-
firstCompletionDisplayLatency: firstCompletionDisplayLatency,
133-
addedDiagnostics: diagnosticDiff.added.map((it) => toIdeDiagnostics(it)),
134-
removedDiagnostics: diagnosticDiff.removed.map((it) => toIdeDiagnostics(it)),
135-
}
136-
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
137-
this.disposable.dispose()
138-
this.disposable = languages.registerInlineCompletionItemProvider(
139-
CodeWhispererConstants.platformLanguageIds,
140-
this.inlineCompletionProvider
141-
)
142-
if (item.references && item.references.length) {
143-
const referenceLog = ReferenceLogViewProvider.getReferenceLog(
144-
item.insertText as string,
145-
item.references,
146-
editor
113+
try {
114+
vsCodeState.isCodeWhispererEditing = true
115+
// TODO: also log the seen state for other suggestions in session
116+
// Calculate timing metrics before diagnostic delay
117+
const totalSessionDisplayTime = performance.now() - requestStartTime
118+
await sleep(500)
119+
const diagnosticDiff = getDiagnosticsDifferences(
120+
this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept,
121+
getDiagnosticsOfCurrentFile()
147122
)
148-
ReferenceLogViewProvider.instance.addReferenceLog(referenceLog)
149-
ReferenceHoverProvider.instance.addCodeReferences(item.insertText as string, item.references)
150-
151-
// Show codelense for 5 seconds.
152-
ReferenceInlineProvider.instance.setInlineReference(
153-
startLine,
154-
item.insertText as string,
155-
item.references
123+
const params: LogInlineCompletionSessionResultsParams = {
124+
sessionId: sessionId,
125+
completionSessionResult: {
126+
[item.itemId]: {
127+
seen: true,
128+
accepted: true,
129+
discarded: false,
130+
},
131+
},
132+
totalSessionDisplayTime: totalSessionDisplayTime,
133+
firstCompletionDisplayLatency: firstCompletionDisplayLatency,
134+
addedDiagnostics: diagnosticDiff.added.map((it) => toIdeDiagnostics(it)),
135+
removedDiagnostics: diagnosticDiff.removed.map((it) => toIdeDiagnostics(it)),
136+
}
137+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
138+
this.disposable.dispose()
139+
this.disposable = languages.registerInlineCompletionItemProvider(
140+
CodeWhispererConstants.platformLanguageIds,
141+
this.inlineCompletionProvider
156142
)
157-
setTimeout(() => {
158-
ReferenceInlineProvider.instance.removeInlineReference()
159-
}, 5000)
160-
}
161-
if (item.mostRelevantMissingImports?.length) {
162-
await ImportAdderProvider.instance.onAcceptRecommendation(editor, item, startLine)
143+
if (item.references && item.references.length) {
144+
const referenceLog = ReferenceLogViewProvider.getReferenceLog(
145+
item.insertText as string,
146+
item.references,
147+
editor
148+
)
149+
ReferenceLogViewProvider.instance.addReferenceLog(referenceLog)
150+
ReferenceHoverProvider.instance.addCodeReferences(item.insertText as string, item.references)
151+
}
152+
if (item.mostRelevantMissingImports?.length) {
153+
await ImportAdderProvider.instance.onAcceptRecommendation(editor, item, startLine)
154+
}
155+
this.sessionManager.incrementSuggestionCount()
156+
// clear session manager states once accepted
157+
this.sessionManager.clear()
158+
} finally {
159+
vsCodeState.isCodeWhispererEditing = false
163160
}
164-
this.sessionManager.incrementSuggestionCount()
165-
// clear session manager states once accepted
166-
this.sessionManager.clear()
167161
}
168162
commands.registerCommand('aws.amazonq.acceptInline', onInlineAcceptance)
169163

170164
const onInlineRejection = async () => {
171-
await commands.executeCommand('editor.action.inlineSuggest.hide')
172-
// TODO: also log the seen state for other suggestions in session
173-
this.disposable.dispose()
174-
this.disposable = languages.registerInlineCompletionItemProvider(
175-
CodeWhispererConstants.platformLanguageIds,
176-
this.inlineCompletionProvider
177-
)
178-
const sessionId = this.sessionManager.getActiveSession()?.sessionId
179-
const itemId = this.sessionManager.getActiveRecommendation()[0]?.itemId
180-
if (!sessionId || !itemId) {
181-
return
182-
}
183-
const params: LogInlineCompletionSessionResultsParams = {
184-
sessionId: sessionId,
185-
completionSessionResult: {
186-
[itemId]: {
187-
seen: true,
188-
accepted: false,
189-
discarded: false,
165+
try {
166+
vsCodeState.isCodeWhispererEditing = true
167+
await commands.executeCommand('editor.action.inlineSuggest.hide')
168+
// TODO: also log the seen state for other suggestions in session
169+
this.disposable.dispose()
170+
this.disposable = languages.registerInlineCompletionItemProvider(
171+
CodeWhispererConstants.platformLanguageIds,
172+
this.inlineCompletionProvider
173+
)
174+
const sessionId = this.sessionManager.getActiveSession()?.sessionId
175+
const itemId = this.sessionManager.getActiveRecommendation()[0]?.itemId
176+
if (!sessionId || !itemId) {
177+
return
178+
}
179+
const params: LogInlineCompletionSessionResultsParams = {
180+
sessionId: sessionId,
181+
completionSessionResult: {
182+
[itemId]: {
183+
seen: true,
184+
accepted: false,
185+
discarded: false,
186+
},
190187
},
191-
},
188+
}
189+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
190+
// clear session manager states once rejected
191+
this.sessionManager.clear()
192+
} finally {
193+
vsCodeState.isCodeWhispererEditing = false
192194
}
193-
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
194-
// clear session manager states once rejected
195-
this.sessionManager.clear()
196195
}
197196
commands.registerCommand('aws.amazonq.rejectCodeSuggestion', onInlineRejection)
198197
}
@@ -241,6 +240,12 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
241240
return []
242241
}
243242

243+
const isAutoTrigger = context.triggerKind === InlineCompletionTriggerKind.Automatic
244+
if (isAutoTrigger && !CodeSuggestionsState.instance.isSuggestionsEnabled()) {
245+
// return early when suggestions are disabled with auto trigger
246+
return []
247+
}
248+
244249
// yield event loop to let the document listen catch updates
245250
await sleep(1)
246251
// prevent user deletion invoking auto trigger
@@ -254,12 +259,6 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
254259
try {
255260
const t0 = performance.now()
256261
vsCodeState.isRecommendationsActive = true
257-
const isAutoTrigger = context.triggerKind === InlineCompletionTriggerKind.Automatic
258-
if (isAutoTrigger && !CodeSuggestionsState.instance.isSuggestionsEnabled()) {
259-
// return early when suggestions are disabled with auto trigger
260-
return []
261-
}
262-
263262
// handling previous session
264263
const prevSession = this.sessionManager.getActiveSession()
265264
const prevSessionId = prevSession?.sessionId
@@ -335,7 +334,8 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
335334
context,
336335
token,
337336
isAutoTrigger,
338-
getAllRecommendationsOptions
337+
getAllRecommendationsOptions,
338+
this.documentEventListener.getLastDocumentChangeEvent(document.uri.fsPath)?.event
339339
)
340340
// get active item from session for displaying
341341
const items = this.sessionManager.getActiveRecommendation()
@@ -430,7 +430,6 @@ ${itemLog}
430430
}
431431
item.range = new Range(cursorPosition, cursorPosition)
432432
itemsMatchingTypeahead.push(item)
433-
ImportAdderProvider.instance.onShowRecommendation(document, cursorPosition.line, item)
434433
}
435434
}
436435

@@ -452,6 +451,7 @@ ${itemLog}
452451
return []
453452
}
454453

454+
this.sessionManager.updateCodeReferenceAndImports()
455455
// suggestions returned here will be displayed on screen
456456
logstr += `- duration between trigger to completion suggestion is displayed: ${performance.now() - t0}ms`
457457
return itemsMatchingTypeahead as InlineCompletionItem[]

packages/amazonq/src/app/inline/documentEventListener.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export class DocumentEventListener {
2121
this.lastDocumentChangeEventMap.clear()
2222
}
2323
this.lastDocumentChangeEventMap.set(e.document.uri.fsPath, { event: e, timestamp: performance.now() })
24+
// The VS Code provideInlineCompletionCallback may not trigger when Enter is pressed, especially in Python files
25+
// manually make this trigger. In case of duplicate, the provideInlineCompletionCallback is already debounced
26+
if (this.isEnter(e) && vscode.window.activeTextEditor) {
27+
void vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
28+
}
2429
}
2530
})
2631
}
@@ -47,4 +52,18 @@ export class DocumentEventListener {
4752
this.documentChangeListener.dispose()
4853
}
4954
}
55+
56+
private isEnter(e: vscode.TextDocumentChangeEvent): boolean {
57+
if (e.contentChanges.length !== 1) {
58+
return false
59+
}
60+
const str = e.contentChanges[0].text
61+
if (str.length === 0) {
62+
return false
63+
}
64+
return (
65+
(str.startsWith('\r\n') && str.substring(2).trim() === '') ||
66+
(str[0] === '\n' && str.substring(1).trim() === '')
67+
)
68+
}
5069
}

packages/amazonq/src/app/inline/recommendationService.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5+
import * as vscode from 'vscode'
56
import {
67
InlineCompletionListWithReferences,
78
InlineCompletionWithReferencesParams,
89
inlineCompletionWithReferencesRequestType,
10+
TextDocumentContentChangeEvent,
911
} from '@aws/language-server-runtimes/protocol'
1012
import { CancellationToken, InlineCompletionContext, Position, TextDocument } from 'vscode'
1113
import { LanguageClient } from 'vscode-languageclient'
@@ -40,17 +42,28 @@ export class RecommendationService {
4042
context: InlineCompletionContext,
4143
token: CancellationToken,
4244
isAutoTrigger: boolean,
43-
options: GetAllRecommendationsOptions = { emitTelemetry: true, showUi: true }
45+
options: GetAllRecommendationsOptions = { emitTelemetry: true, showUi: true },
46+
documentChangeEvent?: vscode.TextDocumentChangeEvent
4447
) {
4548
// Record that a regular request is being made
4649
this.cursorUpdateRecorder?.recordCompletionRequest()
50+
const documentChangeParams = documentChangeEvent
51+
? {
52+
textDocument: {
53+
uri: document.uri.toString(),
54+
version: document.version,
55+
},
56+
contentChanges: documentChangeEvent.contentChanges.map((x) => x as TextDocumentContentChangeEvent),
57+
}
58+
: undefined
4759

4860
let request: InlineCompletionWithReferencesParams = {
4961
textDocument: {
5062
uri: document.uri.toString(),
5163
},
5264
position,
5365
context,
66+
documentChangeParams: documentChangeParams,
5467
}
5568
if (options.editsStreakToken) {
5669
request = { ...request, partialResultToken: options.editsStreakToken }

0 commit comments

Comments
 (0)