From 40adfc76a07869fdc570f919a48e9bdeb1748b7c Mon Sep 17 00:00:00 2001 From: Aidan Ton Date: Mon, 30 Jun 2025 15:23:58 -0700 Subject: [PATCH 1/2] fix: removing logic to calculate addedCharacterCount and deletedCharacterCount --- .../src/app/inline/EditRendering/diffUtils.ts | 57 ++----------------- .../app/inline/EditRendering/displayImage.ts | 8 +-- .../app/inline/EditRendering/imageRenderer.ts | 14 +---- .../app/inline/EditRendering/svgGenerator.ts | 6 -- .../inline/EditRendering/diffUtils.test.ts | 28 +-------- .../EditRendering/imageRenderer.test.ts | 6 +- 6 files changed, 12 insertions(+), 107 deletions(-) diff --git a/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts b/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts index 24014d692ea..7f9ca54b6aa 100644 --- a/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts +++ b/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts @@ -16,21 +16,13 @@ export type LineDiff = * @param unifiedDiff The unified diff content * @returns The modified code after applying the diff */ -export function applyUnifiedDiff( - docText: string, - unifiedDiff: string -): { appliedCode: string; addedCharacterCount: number; deletedCharacterCount: number } { +export function applyUnifiedDiff(docText: string, unifiedDiff: string): string { try { - const { addedCharacterCount, deletedCharacterCount } = getAddedAndDeletedCharCount(unifiedDiff) // First try the standard diff package try { const result = applyPatch(docText, unifiedDiff) if (result !== false) { - return { - appliedCode: result, - addedCharacterCount: addedCharacterCount, - deletedCharacterCount: deletedCharacterCount, - } + return result } } catch (error) {} @@ -94,49 +86,8 @@ export function applyUnifiedDiff( // Replace the text result = result.replace(textToReplace, newText) } - return { - appliedCode: result, - addedCharacterCount: addedCharacterCount, - deletedCharacterCount: deletedCharacterCount, - } + return result } catch (error) { - return { - appliedCode: docText, // Return original text if all methods fail - addedCharacterCount: 0, - deletedCharacterCount: 0, - } - } -} - -export function getAddedAndDeletedCharCount(diff: string): { - addedCharacterCount: number - deletedCharacterCount: number -} { - let addedCharacterCount = 0 - let deletedCharacterCount = 0 - let i = 0 - const lines = diff.split('\n') - while (i < lines.length) { - const line = lines[i] - if (line.startsWith('+') && !line.startsWith('+++')) { - addedCharacterCount += line.length - 1 - } else if (line.startsWith('-') && !line.startsWith('---')) { - const removedLine = line.substring(1) - deletedCharacterCount += removedLine.length - - // Check if this is a modified line rather than a pure deletion - const nextLine = lines[i + 1] - if (nextLine && nextLine.startsWith('+') && !nextLine.startsWith('+++') && nextLine.includes(removedLine)) { - // This is a modified line, not a pure deletion - // We've already counted the deletion, so we'll just increment i to skip the next line - // since we'll process the addition on the next iteration - i += 1 - } - } - i += 1 - } - return { - addedCharacterCount, - deletedCharacterCount, + return docText // Return original text if all methods fail } } diff --git a/packages/amazonq/src/app/inline/EditRendering/displayImage.ts b/packages/amazonq/src/app/inline/EditRendering/displayImage.ts index 80d5231f113..8b3473a3444 100644 --- a/packages/amazonq/src/app/inline/EditRendering/displayImage.ts +++ b/packages/amazonq/src/app/inline/EditRendering/displayImage.ts @@ -279,9 +279,7 @@ export async function displaySvgDecoration( originalCodeHighlightRanges: Array<{ line: number; start: number; end: number }>, session: CodeWhispererSession, languageClient: LanguageClient, - item: InlineCompletionItemWithReferences, - addedCharacterCount: number, - deletedCharacterCount: number + item: InlineCompletionItemWithReferences ) { const originalCode = editor.document.getText() @@ -315,8 +313,6 @@ export async function displaySvgDecoration( }, totalSessionDisplayTime: Date.now() - session.requestStartTime, firstCompletionDisplayLatency: session.firstCompletionDisplayLatency, - addedCharacterCount: addedCharacterCount, - deletedCharacterCount: deletedCharacterCount, } languageClient.sendNotification('aws/logInlineCompletionSessionResults', params) }, @@ -333,8 +329,6 @@ export async function displaySvgDecoration( discarded: false, }, }, - // addedCharacterCount: addedCharacterCount, - // deletedCharacterCount: deletedCharacterCount, } languageClient.sendNotification('aws/logInlineCompletionSessionResults', params) }, diff --git a/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts b/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts index 2dd6bd67712..b6eda159f75 100644 --- a/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts +++ b/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts @@ -24,14 +24,8 @@ export async function showEdits( const svgGenerationService = new SvgGenerationService() // Generate your SVG image with the file contents const currentFile = editor.document.uri.fsPath - const { - svgImage, - startLine, - newCode, - origionalCodeHighlightRange, - addedCharacterCount, - deletedCharacterCount, - } = await svgGenerationService.generateDiffSvg(currentFile, item.insertText as string) + const { svgImage, startLine, newCode, origionalCodeHighlightRange } = + await svgGenerationService.generateDiffSvg(currentFile, item.insertText as string) if (svgImage) { // display the SVG image @@ -43,9 +37,7 @@ export async function showEdits( origionalCodeHighlightRange, session, languageClient, - item, - addedCharacterCount, - deletedCharacterCount + item ) } else { getLogger('nextEditPrediction').error('SVG image generation returned an empty result.') diff --git a/packages/amazonq/src/app/inline/EditRendering/svgGenerator.ts b/packages/amazonq/src/app/inline/EditRendering/svgGenerator.ts index 8c7a9d57fd9..b9cf33e255d 100644 --- a/packages/amazonq/src/app/inline/EditRendering/svgGenerator.ts +++ b/packages/amazonq/src/app/inline/EditRendering/svgGenerator.ts @@ -7,7 +7,6 @@ import { diffChars } from 'diff' import * as vscode from 'vscode' import { ToolkitError, getLogger } from 'aws-core-vscode/shared' import { diffUtilities } from 'aws-core-vscode/shared' -import { applyUnifiedDiff } from './diffUtils' type Range = { line: number; start: number; end: number } const logger = getLogger('nextEditPrediction') @@ -29,8 +28,6 @@ export class SvgGenerationService { startLine: number newCode: string origionalCodeHighlightRange: Range[] - addedCharacterCount: number - deletedCharacterCount: number }> { const textDoc = await vscode.workspace.openTextDocument(filePath) const originalCode = textDoc.getText() @@ -38,7 +35,6 @@ export class SvgGenerationService { logger.error(`udiff format error`) throw new ToolkitError('udiff format error') } - const { addedCharacterCount, deletedCharacterCount } = applyUnifiedDiff(originalCode, udiff) const newCode = await diffUtilities.getPatchedCode(filePath, udiff) const modifiedLines = diffUtilities.getModifiedLinesFromUnifiedDiff(udiff) // TODO remove @@ -91,8 +87,6 @@ export class SvgGenerationService { startLine: editStartLine, newCode: newCode, origionalCodeHighlightRange: highlightRanges.removedRanges, - addedCharacterCount, - deletedCharacterCount, } } diff --git a/packages/amazonq/test/unit/app/inline/EditRendering/diffUtils.test.ts b/packages/amazonq/test/unit/app/inline/EditRendering/diffUtils.test.ts index 512092d53d3..dee096d7f57 100644 --- a/packages/amazonq/test/unit/app/inline/EditRendering/diffUtils.test.ts +++ b/packages/amazonq/test/unit/app/inline/EditRendering/diffUtils.test.ts @@ -4,7 +4,7 @@ */ import * as assert from 'assert' -import { applyUnifiedDiff, getAddedAndDeletedCharCount } from '../../../../../src/app/inline/EditRendering/diffUtils' +import { applyUnifiedDiff } from '../../../../../src/app/inline/EditRendering/diffUtils' describe('diffUtils', function () { describe('applyUnifiedDiff', function () { @@ -27,35 +27,13 @@ describe('diffUtils', function () { const expectedResult = 'function add(a, b) {\n // Add two numbers\n return a + b; // Return the sum\n}' // Apply the diff - const { appliedCode } = applyUnifiedDiff(originalCode, unifiedDiff) + const appliedCode = applyUnifiedDiff(originalCode, unifiedDiff) // Verify the result assert.strictEqual(appliedCode, expectedResult) }) }) - describe('getAddedAndDeletedCharCount', function () { - it('should correctly calculate added and deleted character counts', function () { - // Unified diff with additions and deletions - const unifiedDiff = - '--- a/file.js\n' + - '+++ b/file.js\n' + - '@@ -1,3 +1,4 @@\n' + - ' function add(a, b) {\n' + - '+ // Add two numbers\n' + - '- return a + b;\n' + - '+ return a + b; // Return the sum\n' + - ' }' - - // Calculate character counts - const { addedCharacterCount, deletedCharacterCount } = getAddedAndDeletedCharCount(unifiedDiff) - - // Verify the counts with the actual values from the implementation - assert.strictEqual(addedCharacterCount, 20) - assert.strictEqual(deletedCharacterCount, 15) - }) - }) - describe('applyUnifiedDiff with complex changes', function () { it('should handle multiple hunks in a diff', function () { // Original code with multiple functions @@ -96,7 +74,7 @@ describe('diffUtils', function () { '}' // Apply the diff - const { appliedCode } = applyUnifiedDiff(originalCode, unifiedDiff) + const appliedCode = applyUnifiedDiff(originalCode, unifiedDiff) // Verify the result assert.strictEqual(appliedCode, expectedResult) diff --git a/packages/amazonq/test/unit/app/inline/EditRendering/imageRenderer.test.ts b/packages/amazonq/test/unit/app/inline/EditRendering/imageRenderer.test.ts index 2a3db2af650..3160f69fa95 100644 --- a/packages/amazonq/test/unit/app/inline/EditRendering/imageRenderer.test.ts +++ b/packages/amazonq/test/unit/app/inline/EditRendering/imageRenderer.test.ts @@ -31,8 +31,6 @@ describe('showEdits', function () { startLine: 5, newCode: 'console.log("Hello World");', origionalCodeHighlightRange: [{ line: 5, start: 0, end: 10 }], - addedCharacterCount: 25, - deletedCharacterCount: 0, ...overrides, } } @@ -170,9 +168,7 @@ describe('showEdits', function () { mockSvgResult.origionalCodeHighlightRange, sessionStub, languageClientStub, - itemStub, - mockSvgResult.addedCharacterCount, - mockSvgResult.deletedCharacterCount + itemStub ) // Verify no errors were logged From 4a1b444c5e608db3942d13c58ab5371b3eb686c7 Mon Sep 17 00:00:00 2001 From: Aidan Ton Date: Tue, 1 Jul 2025 14:03:44 -0700 Subject: [PATCH 2/2] feat: trigger inline suggestion via acceptance for EDITS --- .../app/inline/EditRendering/displayImage.ts | 18 ++++++++++++++++-- .../app/inline/EditRendering/imageRenderer.ts | 7 +++++-- packages/amazonq/src/app/inline/completion.ts | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/amazonq/src/app/inline/EditRendering/displayImage.ts b/packages/amazonq/src/app/inline/EditRendering/displayImage.ts index 8b3473a3444..2c5986afa51 100644 --- a/packages/amazonq/src/app/inline/EditRendering/displayImage.ts +++ b/packages/amazonq/src/app/inline/EditRendering/displayImage.ts @@ -12,6 +12,7 @@ import { LogInlineCompletionSessionResultsParams } from '@aws/language-server-ru import { InlineCompletionItemWithReferences } from '@aws/language-server-runtimes/protocol' import path from 'path' import { imageVerticalOffset } from './svgGenerator' +import { AmazonQInlineCompletionItemProvider } from '../completion' export class EditDecorationManager { private imageDecorationType: vscode.TextEditorDecorationType @@ -279,7 +280,8 @@ export async function displaySvgDecoration( originalCodeHighlightRanges: Array<{ line: number; start: number; end: number }>, session: CodeWhispererSession, languageClient: LanguageClient, - item: InlineCompletionItemWithReferences + item: InlineCompletionItemWithReferences, + inlineCompletionProvider?: AmazonQInlineCompletionItemProvider ) { const originalCode = editor.document.getText() @@ -287,7 +289,7 @@ export async function displaySvgDecoration( editor, svgImage, startLine, - () => { + async () => { // Handle accept getLogger().info('Edit suggestion accepted') @@ -315,6 +317,18 @@ export async function displaySvgDecoration( firstCompletionDisplayLatency: session.firstCompletionDisplayLatency, } languageClient.sendNotification('aws/logInlineCompletionSessionResults', params) + if (inlineCompletionProvider) { + await inlineCompletionProvider.provideInlineCompletionItems( + editor.document, + endPosition, + { + triggerKind: vscode.InlineCompletionTriggerKind.Automatic, + selectedCompletionInfo: undefined, + }, + new vscode.CancellationTokenSource().token, + { emitTelemetry: false, showUi: false } + ) + } }, () => { // Handle reject diff --git a/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts b/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts index b6eda159f75..9af3878ef82 100644 --- a/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts +++ b/packages/amazonq/src/app/inline/EditRendering/imageRenderer.ts @@ -10,12 +10,14 @@ import { getLogger } from 'aws-core-vscode/shared' import { LanguageClient } from 'vscode-languageclient' import { InlineCompletionItemWithReferences } from '@aws/language-server-runtimes/protocol' import { CodeWhispererSession } from '../sessionManager' +import { AmazonQInlineCompletionItemProvider } from '../completion' export async function showEdits( item: InlineCompletionItemWithReferences, editor: vscode.TextEditor | undefined, session: CodeWhispererSession, - languageClient: LanguageClient + languageClient: LanguageClient, + inlineCompletionProvider?: AmazonQInlineCompletionItemProvider ) { if (!editor) { return @@ -37,7 +39,8 @@ export async function showEdits( origionalCodeHighlightRange, session, languageClient, - item + item, + inlineCompletionProvider ) } else { getLogger('nextEditPrediction').error('SVG image generation returned an empty result.') diff --git a/packages/amazonq/src/app/inline/completion.ts b/packages/amazonq/src/app/inline/completion.ts index 069a6bc5128..d7ce897d493 100644 --- a/packages/amazonq/src/app/inline/completion.ts +++ b/packages/amazonq/src/app/inline/completion.ts @@ -354,7 +354,7 @@ ${itemLog} if (item.isInlineEdit) { // Check if Next Edit Prediction feature flag is enabled if (Experiments.instance.isExperimentEnabled('amazonqLSPNEP')) { - void showEdits(item, editor, session, this.languageClient).then(() => { + void showEdits(item, editor, session, this.languageClient, this).then(() => { const t3 = performance.now() logstr = logstr + `- duration since trigger to NEP suggestion is displayed: ${t3 - t0}ms` this.logger.info(logstr)