Skip to content

Commit aa5405d

Browse files
authored
Merge branch 'aws:master' into master
2 parents cee9380 + 187f27a commit aa5405d

File tree

21 files changed

+438
-202
lines changed

21 files changed

+438
-202
lines changed

buildspec/linuxTests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ phases:
4848
- VCS_COMMIT_ID="${CODEBUILD_RESOLVED_SOURCE_VERSION}"
4949
- CI_BUILD_URL=$(echo $CODEBUILD_BUILD_URL | sed 's/#/%23/g') # Encode `#` in the URL because otherwise the url is clipped in the Codecov.io site
5050
- CI_BUILD_ID="${CODEBUILD_BUILD_ID}"
51-
- test -n "${CODECOV_TOKEN}" && [ "$TARGET_BRANCH" = "master" ] && ./codecov --token=${CODECOV_TOKEN} --branch=${CODEBUILD_RESOLVED_SOURCE_VERSION} --repository=${CODEBUILD_SOURCE_REPO_URL} --file=./coverage/amazonq/lcov.info --file=./coverage/toolkit/lcov.info
51+
- test -n "${CODECOV_TOKEN}" && [ "$TARGET_BRANCH" = "master" ] && ./codecov --token=${CODECOV_TOKEN} --branch=${CODEBUILD_RESOLVED_SOURCE_VERSION} --repository=${CODEBUILD_SOURCE_REPO_URL} --file=./coverage/amazonq/lcov.info --file=./coverage/toolkit/lcov.info || true
5252

5353
reports:
5454
unit-test:

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"date": "2025-07-31",
3+
"version": "1.87.0",
4+
"entries": []
5+
}

packages/amazonq/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.87.0 2025-07-31
2+
3+
- Miscellaneous non-user-facing changes
4+
15
## 1.86.0 2025-07-30
26

37
- **Bug Fix** Let Enter invoke auto completion more consistently

packages/amazonq/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "amazon-q-vscode",
33
"displayName": "Amazon Q",
44
"description": "The most capable generative AI–powered assistant for software development.",
5-
"version": "1.87.0-SNAPSHOT",
5+
"version": "1.88.0-SNAPSHOT",
66
"extensionKind": [
77
"workspace"
88
],

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

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { diffWordsWithSpace } from 'diff'
6+
import { diffWordsWithSpace, diffLines } from 'diff'
77
import * as vscode from 'vscode'
88
import { ToolkitError, getLogger } from 'aws-core-vscode/shared'
99
import { diffUtilities } from 'aws-core-vscode/shared'
@@ -42,10 +42,6 @@ export class SvgGenerationService {
4242
throw new ToolkitError('udiff format error')
4343
}
4444
const newCode = await diffUtilities.getPatchedCode(filePath, udiff)
45-
const modifiedLines = diffUtilities.getModifiedLinesFromUnifiedDiff(udiff)
46-
// TODO remove
47-
// eslint-disable-next-line aws-toolkits/no-json-stringify-in-log
48-
logger.info(`Line mapping: ${JSON.stringify(modifiedLines)}`)
4945

5046
const { createSVGWindow } = await import('svgdom')
5147

@@ -57,7 +53,12 @@ export class SvgGenerationService {
5753
const currentTheme = this.getEditorTheme()
5854

5955
// Get edit diffs with highlight
60-
const { addedLines, removedLines } = this.getEditedLinesFromDiff(udiff)
56+
const { addedLines, removedLines } = this.getEditedLinesFromCode(originalCode, newCode)
57+
58+
const modifiedLines = diffUtilities.getModifiedLinesFromCode(addedLines, removedLines)
59+
// TODO remove
60+
// eslint-disable-next-line aws-toolkits/no-json-stringify-in-log
61+
logger.info(`Line mapping: ${JSON.stringify(modifiedLines)}`)
6162

6263
// Calculate dimensions based on code content
6364
const { offset, editStartLine, isPositionValid } = this.calculatePosition(
@@ -175,43 +176,25 @@ export class SvgGenerationService {
175176
}
176177

177178
/**
178-
* Extract added and removed lines from the unified diff
179-
* @param unifiedDiff The unified diff string
179+
* Extract added and removed lines by comparing original and new code
180+
* @param originalCode The original code string
181+
* @param newCode The new code string
180182
* @returns Object containing arrays of added and removed lines
181183
*/
182-
private getEditedLinesFromDiff(unifiedDiff: string): { addedLines: string[]; removedLines: string[] } {
184+
private getEditedLinesFromCode(
185+
originalCode: string,
186+
newCode: string
187+
): { addedLines: string[]; removedLines: string[] } {
183188
const addedLines: string[] = []
184189
const removedLines: string[] = []
185-
const diffLines = unifiedDiff.split('\n')
186-
187-
// Find all hunks in the diff
188-
const hunkStarts = diffLines
189-
.map((line, index) => (line.startsWith('@@ ') ? index : -1))
190-
.filter((index) => index !== -1)
191190

192-
// Process each hunk to find added and removed lines
193-
for (const hunkStart of hunkStarts) {
194-
const hunkHeader = diffLines[hunkStart]
195-
const match = hunkHeader.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/)
191+
const changes = diffLines(originalCode, newCode)
196192

197-
if (!match) {
198-
continue
199-
}
200-
201-
// Extract the content lines for this hunk
202-
let i = hunkStart + 1
203-
while (i < diffLines.length && !diffLines[i].startsWith('@@')) {
204-
// Include lines that were added (start with '+')
205-
if (diffLines[i].startsWith('+') && !diffLines[i].startsWith('+++')) {
206-
const lineContent = diffLines[i].substring(1)
207-
addedLines.push(lineContent)
208-
}
209-
// Include lines that were removed (start with '-')
210-
else if (diffLines[i].startsWith('-') && !diffLines[i].startsWith('---')) {
211-
const lineContent = diffLines[i].substring(1)
212-
removedLines.push(lineContent)
213-
}
214-
i++
193+
for (const change of changes) {
194+
if (change.added) {
195+
addedLines.push(...change.value.split('\n').filter((line) => line.length > 0))
196+
} else if (change.removed) {
197+
removedLines.push(...change.value.split('\n').filter((line) => line.length > 0))
215198
}
216199
}
217200

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
getDiagnosticsDifferences,
3737
getDiagnosticsOfCurrentFile,
3838
toIdeDiagnostics,
39+
handleExtraBrackets,
3940
} from 'aws-core-vscode/codewhisperer'
4041
import { LineTracker } from './stateTracker/lineTracker'
4142
import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
@@ -106,11 +107,12 @@ export class InlineCompletionManager implements Disposable {
106107
item: InlineCompletionItemWithReferences,
107108
editor: TextEditor,
108109
requestStartTime: number,
109-
startLine: number,
110+
position: vscode.Position,
110111
firstCompletionDisplayLatency?: number
111112
) => {
112113
try {
113114
vsCodeState.isCodeWhispererEditing = true
115+
const startLine = position.line
114116
// TODO: also log the seen state for other suggestions in session
115117
// Calculate timing metrics before diagnostic delay
116118
const totalSessionDisplayTime = performance.now() - requestStartTime
@@ -119,6 +121,11 @@ export class InlineCompletionManager implements Disposable {
119121
this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept,
120122
getDiagnosticsOfCurrentFile()
121123
)
124+
// try remove the extra } ) ' " if there is a new reported problem
125+
// the extra } will cause syntax error
126+
if (diagnosticDiff.added.length > 0) {
127+
await handleExtraBrackets(editor, editor.selection.active, position)
128+
}
122129
const params: LogInlineCompletionSessionResultsParams = {
123130
sessionId: sessionId,
124131
completionSessionResult: {
@@ -255,7 +262,11 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
255262
return []
256263
}
257264

258-
const isAutoTrigger = context.triggerKind === InlineCompletionTriggerKind.Automatic
265+
// there is a bug in VS Code, when hitting Enter, the context.triggerKind is Invoke (0)
266+
// when hitting other keystrokes, the context.triggerKind is Automatic (1)
267+
// we only mark option + C as manual trigger
268+
// this is a workaround since the inlineSuggest.trigger command take no params
269+
const isAutoTrigger = performance.now() - vsCodeState.lastManualTriggerTime > 50
259270
if (isAutoTrigger && !CodeSuggestionsState.instance.isSuggestionsEnabled()) {
260271
// return early when suggestions are disabled with auto trigger
261272
return []
@@ -304,7 +315,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
304315
item,
305316
editor,
306317
prevSession?.requestStartTime,
307-
position.line,
318+
position,
308319
prevSession?.firstCompletionDisplayLatency,
309320
],
310321
}
@@ -348,7 +359,10 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
348359
this.languageClient,
349360
document,
350361
position,
351-
context,
362+
{
363+
triggerKind: isAutoTrigger ? 1 : 0,
364+
selectedCompletionInfo: context.selectedCompletionInfo,
365+
},
352366
token,
353367
isAutoTrigger,
354368
getAllRecommendationsOptions,
@@ -441,7 +455,7 @@ ${itemLog}
441455
item,
442456
editor,
443457
session.requestStartTime,
444-
cursorPosition.line,
458+
cursorPosition,
445459
session.firstCompletionDisplayLatency,
446460
],
447461
}

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

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,16 @@ import {
1212
import { CancellationToken, InlineCompletionContext, Position, TextDocument } from 'vscode'
1313
import { LanguageClient } from 'vscode-languageclient'
1414
import { SessionManager } from './sessionManager'
15-
import { AuthUtil, CodeWhispererStatusBarManager, vsCodeState } from 'aws-core-vscode/codewhisperer'
15+
import {
16+
AuthUtil,
17+
CodeWhispererConstants,
18+
CodeWhispererStatusBarManager,
19+
vsCodeState,
20+
} from 'aws-core-vscode/codewhisperer'
1621
import { TelemetryHelper } from './telemetryHelper'
1722
import { ICursorUpdateRecorder } from './cursorUpdateManager'
1823
import { getLogger } from 'aws-core-vscode/shared'
24+
import { asyncCallWithTimeout } from '../../util/timeoutUtil'
1925

2026
export interface GetAllRecommendationsOptions {
2127
emitTelemetry?: boolean
@@ -35,6 +41,23 @@ export class RecommendationService {
3541
this.cursorUpdateRecorder = recorder
3642
}
3743

44+
async getRecommendationsWithTimeout(
45+
languageClient: LanguageClient,
46+
request: InlineCompletionWithReferencesParams,
47+
token: CancellationToken
48+
) {
49+
const resultPromise: Promise<InlineCompletionListWithReferences> = languageClient.sendRequest(
50+
inlineCompletionWithReferencesRequestType.method,
51+
request,
52+
token
53+
)
54+
return await asyncCallWithTimeout<InlineCompletionListWithReferences>(
55+
resultPromise,
56+
`${inlineCompletionWithReferencesRequestType.method} time out`,
57+
CodeWhispererConstants.promiseTimeoutLimit * 1000
58+
)
59+
}
60+
3861
async getAllRecommendations(
3962
languageClient: LanguageClient,
4063
document: TextDocument,
@@ -93,11 +116,9 @@ export class RecommendationService {
93116
},
94117
})
95118
const t0 = performance.now()
96-
const result: InlineCompletionListWithReferences = await languageClient.sendRequest(
97-
inlineCompletionWithReferencesRequestType.method,
98-
request,
99-
token
100-
)
119+
120+
const result = await this.getRecommendationsWithTimeout(languageClient, request, token)
121+
101122
getLogger().info('Received inline completion response from LSP: %O', {
102123
sessionId: result.sessionId,
103124
latency: performance.now() - t0,
@@ -181,11 +202,7 @@ export class RecommendationService {
181202
while (nextToken) {
182203
const request = { ...initialRequest, partialResultToken: nextToken }
183204

184-
const result: InlineCompletionListWithReferences = await languageClient.sendRequest(
185-
inlineCompletionWithReferencesRequestType.method,
186-
request,
187-
token
188-
)
205+
const result = await this.getRecommendationsWithTimeout(languageClient, request, token)
189206
// when pagination is in progress, but user has already accepted or rejected an inline completion
190207
// then stop pagination
191208
if (this.sessionManager.getActiveSession() === undefined || vsCodeState.isCodeWhispererEditing) {

packages/amazonq/src/lsp/client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
CodeWhispererSettings,
2424
getSelectedCustomization,
2525
TelemetryHelper,
26+
vsCodeState,
2627
} from 'aws-core-vscode/codewhisperer'
2728
import {
2829
Settings,
@@ -367,6 +368,7 @@ async function onLanguageServerReady(
367368
sessionManager.checkInlineSuggestionVisibility()
368369
}),
369370
Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => {
371+
vsCodeState.lastManualTriggerTime = performance.now()
370372
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
371373
}),
372374
Commands.register('aws.amazonq.refreshAnnotation', async (forceProceed: boolean) => {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export function asyncCallWithTimeout<T>(asyncPromise: Promise<T>, message: string, timeLimit: number): Promise<T> {
7+
let timeoutHandle: NodeJS.Timeout
8+
const timeoutPromise = new Promise((_resolve, reject) => {
9+
timeoutHandle = setTimeout(() => reject(new Error(message)), timeLimit)
10+
})
11+
return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
12+
clearTimeout(timeoutHandle)
13+
return result as T
14+
})
15+
}

0 commit comments

Comments
 (0)