Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "Let Enter invoke auto completion more consistently"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "Use documentChangeEvent as auto trigger condition"
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export async function showEdits(
const { svgImage, startLine, newCode, origionalCodeHighlightRange } =
await svgGenerationService.generateDiffSvg(currentFile, item.insertText as string)

// TODO: To investigate why it fails and patch [generateDiffSvg]
if (newCode.length === 0) {
getLogger('nextEditPrediction').warn('not able to apply provided edit suggestion, skip rendering')
return
}

if (svgImage) {
// display the SVG image
await displaySvgDecoration(
Expand Down
15 changes: 8 additions & 7 deletions packages/amazonq/src/app/inline/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
return []
}

const isAutoTrigger = context.triggerKind === InlineCompletionTriggerKind.Automatic
if (isAutoTrigger && !CodeSuggestionsState.instance.isSuggestionsEnabled()) {
// return early when suggestions are disabled with auto trigger
return []
}

// yield event loop to let the document listen catch updates
await sleep(1)
// prevent user deletion invoking auto trigger
Expand All @@ -254,12 +260,6 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
try {
const t0 = performance.now()
vsCodeState.isRecommendationsActive = true
const isAutoTrigger = context.triggerKind === InlineCompletionTriggerKind.Automatic
if (isAutoTrigger && !CodeSuggestionsState.instance.isSuggestionsEnabled()) {
// return early when suggestions are disabled with auto trigger
return []
}

// handling previous session
const prevSession = this.sessionManager.getActiveSession()
const prevSessionId = prevSession?.sessionId
Expand Down Expand Up @@ -335,7 +335,8 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
context,
token,
isAutoTrigger,
getAllRecommendationsOptions
getAllRecommendationsOptions,
this.documentEventListener.getLastDocumentChangeEvent(document.uri.fsPath)?.event
)
// get active item from session for displaying
const items = this.sessionManager.getActiveRecommendation()
Expand Down
19 changes: 19 additions & 0 deletions packages/amazonq/src/app/inline/documentEventListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export class DocumentEventListener {
this.lastDocumentChangeEventMap.clear()
}
this.lastDocumentChangeEventMap.set(e.document.uri.fsPath, { event: e, timestamp: performance.now() })
// The VS Code provideInlineCompletionCallback may not trigger when Enter is pressed, especially in Python files
// manually make this trigger. In case of duplicate, the provideInlineCompletionCallback is already debounced
if (this.isEnter(e) && vscode.window.activeTextEditor) {
void vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
}
}
})
}
Expand All @@ -47,4 +52,18 @@ export class DocumentEventListener {
this.documentChangeListener.dispose()
}
}

private isEnter(e: vscode.TextDocumentChangeEvent): boolean {
if (e.contentChanges.length !== 1) {
return false
}
const str = e.contentChanges[0].text
if (str.length === 0) {
return false
}
return (
(str.startsWith('\r\n') && str.substring(2).trim() === '') ||
(str[0] === '\n' && str.substring(1).trim() === '')
)
}
}
15 changes: 14 additions & 1 deletion packages/amazonq/src/app/inline/recommendationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import * as vscode from 'vscode'
import {
InlineCompletionListWithReferences,
InlineCompletionWithReferencesParams,
inlineCompletionWithReferencesRequestType,
TextDocumentContentChangeEvent,
} from '@aws/language-server-runtimes/protocol'
import { CancellationToken, InlineCompletionContext, Position, TextDocument } from 'vscode'
import { LanguageClient } from 'vscode-languageclient'
Expand Down Expand Up @@ -40,17 +42,28 @@ export class RecommendationService {
context: InlineCompletionContext,
token: CancellationToken,
isAutoTrigger: boolean,
options: GetAllRecommendationsOptions = { emitTelemetry: true, showUi: true }
options: GetAllRecommendationsOptions = { emitTelemetry: true, showUi: true },
documentChangeEvent?: vscode.TextDocumentChangeEvent
) {
// Record that a regular request is being made
this.cursorUpdateRecorder?.recordCompletionRequest()
const documentChangeParams = documentChangeEvent
? {
textDocument: {
uri: document.uri.toString(),
version: document.version,
},
contentChanges: documentChangeEvent.contentChanges.map((x) => x as TextDocumentContentChangeEvent),
}
: undefined

let request: InlineCompletionWithReferencesParams = {
textDocument: {
uri: document.uri.toString(),
},
position,
context,
documentChangeParams: documentChangeParams,
}
if (options.editsStreakToken) {
request = { ...request, partialResultToken: options.editsStreakToken }
Expand Down
25 changes: 13 additions & 12 deletions packages/amazonq/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Auth, AuthUtils, CredentialsStore, LoginManager, initializeAuth } from 'aws-core-vscode/auth'
import { AuthUtils, CredentialsStore, LoginManager, initializeAuth } from 'aws-core-vscode/auth'
import { activate as activateCodeWhisperer, shutdown as shutdownCodeWhisperer } from 'aws-core-vscode/codewhisperer'
import { makeEndpointsProvider, registerGenericCommands } from 'aws-core-vscode'
import { CommonAuthWebview } from 'aws-core-vscode/login'
Expand Down Expand Up @@ -44,8 +44,8 @@ import * as vscode from 'vscode'
import { registerCommands } from './commands'
import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat'
import { activate as activateAmazonqLsp } from './lsp/activation'
import { activate as activateInlineCompletion } from './app/inline/activation'
import { hasGlibcPatch } from './lsp/client'
import { RotatingLogChannel } from './lsp/rotatingLogChannel'

export const amazonQContextPrefix = 'amazonq'

Expand Down Expand Up @@ -104,7 +104,12 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
globals.manifestPaths.endpoints = context.asAbsolutePath(join('resources', 'endpoints.json'))
globals.regionProvider = RegionProvider.fromEndpointsProvider(makeEndpointsProvider())

const qLogChannel = vscode.window.createOutputChannel('Amazon Q Logs', { log: true })
// Create rotating log channel for all Amazon Q logs
const qLogChannel = new RotatingLogChannel(
'Amazon Q Logs',
context,
vscode.window.createOutputChannel('Amazon Q Logs', { log: true })
)
await activateLogger(context, amazonQContextPrefix, qLogChannel)
globals.logOutputChannel = qLogChannel
globals.loginManager = new LoginManager(globals.awsContext, new CredentialsStore())
Expand All @@ -113,6 +118,8 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
getLogger().error('fs.init: invalid env vars found: %O', homeDirLogs)
}

getLogger().info('Rotating logger has been setup')

await activateTelemetry(context, globals.awsContext, Settings.instance, 'Amazon Q For VS Code')

await initializeAuth(globals.loginManager)
Expand All @@ -126,17 +133,11 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is

// This contains every lsp agnostic things (auth, security scan, code scan)
await activateCodeWhisperer(extContext as ExtContext)
if (
(Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) &&
(!isAmazonLinux2() || hasGlibcPatch())
) {
// start the Amazon Q LSP for internal users first
// for AL2, start LSP if glibc patch is found

if (!isAmazonLinux2() || hasGlibcPatch()) {
// Activate Amazon Q LSP for everyone unless they're using AL2 without the glibc patch
await activateAmazonqLsp(context)
}
if (!Experiments.instance.get('amazonqLSPInline', true)) {
await activateInlineCompletion()
}

// Generic extension commands
registerGenericCommands(context, amazonQContextPrefix)
Expand Down
17 changes: 13 additions & 4 deletions packages/amazonq/src/lsp/chat/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ import { decryptResponse, encryptRequest } from '../encryption'
import { getCursorState } from '../utils'
import { focusAmazonQPanel } from './commands'
import { ChatMessage } from '@aws/language-server-runtimes/server-interface'
import { CommentUtils } from 'aws-core-vscode/utils'

export function registerActiveEditorChangeListener(languageClient: LanguageClient) {
let debounceTimer: NodeJS.Timeout | undefined
Expand Down Expand Up @@ -701,7 +702,7 @@ async function handleCompleteResult<T extends ChatResult>(
) {
const decryptedMessage = await decryptResponse<T>(result, encryptionKey)

handleSecurityFindings(decryptedMessage, languageClient)
await handleSecurityFindings(decryptedMessage, languageClient)

void provider.webview?.postMessage({
command: chatRequestType.method,
Expand All @@ -716,10 +717,10 @@ async function handleCompleteResult<T extends ChatResult>(
disposable.dispose()
}

function handleSecurityFindings(
async function handleSecurityFindings(
decryptedMessage: { additionalMessages?: ChatMessage[] },
languageClient: LanguageClient
): void {
): Promise<void> {
if (decryptedMessage.additionalMessages === undefined || decryptedMessage.additionalMessages.length === 0) {
return
}
Expand All @@ -730,10 +731,18 @@ function handleSecurityFindings(
try {
const aggregatedCodeScanIssues: AggregatedCodeScanIssue[] = JSON.parse(message.body)
for (const aggregatedCodeScanIssue of aggregatedCodeScanIssues) {
const document = await vscode.workspace.openTextDocument(aggregatedCodeScanIssue.filePath)
for (const issue of aggregatedCodeScanIssue.issues) {
issue.visible = !CodeWhispererSettings.instance
const isIssueTitleIgnored = CodeWhispererSettings.instance
.getIgnoredSecurityIssues()
.includes(issue.title)
const isSingleIssueIgnored = CommentUtils.detectCommentAboveLine(
document,
issue.startLine,
CodeWhispererConstants.amazonqIgnoreNextLine
)

issue.visible = !isIssueTitleIgnored && !isSingleIssueIgnored
}
}
initSecurityScanRender(aggregatedCodeScanIssues, undefined, CodeAnalysisScope.PROJECT)
Expand Down
Loading
Loading