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
12 changes: 11 additions & 1 deletion packages/amazonq/src/app/inline/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ import {
CodeSuggestionsState,
vsCodeState,
inlineCompletionsDebounceDelay,
noInlineSuggestionsMsg,
} from 'aws-core-vscode/codewhisperer'
import { InlineGeneratingMessage } from './inlineGeneratingMessage'
import { LineTracker } from './stateTracker/lineTracker'
import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
import { TelemetryHelper } from './telemetryHelper'
import { getLogger } from 'aws-core-vscode/shared'
import { debounce } from 'aws-core-vscode/utils'
import { debounce, messageUtils } from 'aws-core-vscode/utils'

export class InlineCompletionManager implements Disposable {
private disposable: Disposable
Expand Down Expand Up @@ -241,7 +242,16 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
const items = this.sessionManager.getActiveRecommendation()
const session = this.sessionManager.getActiveSession()
const editor = window.activeTextEditor

// Show message to user when manual invoke fails to produce results.
if (items.length === 0 && context.triggerKind === InlineCompletionTriggerKind.Invoke) {
void messageUtils.showTimedMessage(noInlineSuggestionsMsg, 2000)
}

if (!session || !items.length || !editor) {
getLogger().debug(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log message can help us determine if results not showing are due to vscode quirks or backend issues.

`Failed to produce inline suggestion results. Received ${items.length} items from service`
)
return []
}

Expand Down
121 changes: 72 additions & 49 deletions packages/amazonq/test/unit/amazonq/apps/inline/completion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@
* SPDX-License-Identifier: Apache-2.0
*/
import sinon from 'sinon'
import { CancellationToken, commands, InlineCompletionItem, languages, Position, window, Range } from 'vscode'
import {
CancellationToken,
commands,
InlineCompletionItem,
languages,
Position,
window,
Range,
InlineCompletionTriggerKind,
} from 'vscode'
import assert from 'assert'
import { LanguageClient } from 'vscode-languageclient'
import { StringValue } from 'vscode-languageserver-types'
import { AmazonQInlineCompletionItemProvider, InlineCompletionManager } from '../../../../../src/app/inline/completion'
import { RecommendationService } from '../../../../../src/app/inline/recommendationService'
import { SessionManager } from '../../../../../src/app/inline/sessionManager'
import { createMockDocument, createMockTextEditor, installFakeClock } from 'aws-core-vscode/test'
import { createMockDocument, createMockTextEditor, getTestWindow, installFakeClock } from 'aws-core-vscode/test'
import {
noInlineSuggestionsMsg,
ReferenceHoverProvider,
ReferenceInlineProvider,
ReferenceLogViewProvider,
Expand Down Expand Up @@ -400,57 +410,70 @@ describe('InlineCompletionManager', () => {

assert.strictEqual(result[0].insertText, expectedText)
}),
describe('debounce behavior', function () {
let clock: ReturnType<typeof installFakeClock>

beforeEach(function () {
clock = installFakeClock()
})

after(function () {
clock.uninstall()
})

it('should only trigger once on rapid events', async () => {
provider = new AmazonQInlineCompletionItemProvider(
languageClient,
recommendationService,
mockSessionManager,
inlineTutorialAnnotation,
false
)
const p1 = provider.provideInlineCompletionItems(
mockDocument,
mockPosition,
mockContext,
mockToken
)
const p2 = provider.provideInlineCompletionItems(
mockDocument,
mockPosition,
mockContext,
mockToken
)
const p3 = provider.provideInlineCompletionItems(
mockDocument,
new Position(2, 2),
mockContext,
mockToken
)
it('shows message to user when manual invoke fails to produce results', async function () {
provider = new AmazonQInlineCompletionItemProvider(
languageClient,
recommendationService,
mockSessionManager,
inlineTutorialAnnotation,
true
)
getActiveRecommendationStub.returns([])
const messageShown = new Promise((resolve) =>
getTestWindow().onDidShowMessage((e) => {
assert.strictEqual(e.message, noInlineSuggestionsMsg)
resolve(true)
})
)
await provider.provideInlineCompletionItems(
mockDocument,
mockPosition,
{ triggerKind: InlineCompletionTriggerKind.Invoke, selectedCompletionInfo: undefined },
mockToken
)
await messageShown
})
describe('debounce behavior', function () {
let clock: ReturnType<typeof installFakeClock>

beforeEach(function () {
clock = installFakeClock()
})

after(function () {
clock.uninstall()
})

it('should only trigger once on rapid events', async () => {
provider = new AmazonQInlineCompletionItemProvider(
languageClient,
recommendationService,
mockSessionManager,
inlineTutorialAnnotation,
false
)
const p1 = provider.provideInlineCompletionItems(mockDocument, mockPosition, mockContext, mockToken)
const p2 = provider.provideInlineCompletionItems(mockDocument, mockPosition, mockContext, mockToken)
const p3 = provider.provideInlineCompletionItems(
mockDocument,
new Position(2, 2),
mockContext,
mockToken
)

await clock.tickAsync(1000)
await clock.tickAsync(1000)

// All promises should be the same object when debounced properly.
assert.strictEqual(p1, p2)
assert.strictEqual(p1, p3)
await p1
await p2
const r3 = await p3
// All promises should be the same object when debounced properly.
assert.strictEqual(p1, p2)
assert.strictEqual(p1, p3)
await p1
await p2
const r3 = await p3

// calls the function with the latest provided args.
assert.deepStrictEqual((r3 as InlineCompletionItem[])[0].range?.end, new Position(2, 2))
})
// calls the function with the latest provided args.
assert.deepStrictEqual((r3 as InlineCompletionItem[])[0].range?.end, new Position(2, 2))
})
})
})
})
})
2 changes: 1 addition & 1 deletion packages/core/src/codewhisperer/models/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export const runningSecurityScan = 'Reviewing project for code issues...'

export const runningFileScan = 'Reviewing current file for code issues...'

export const noSuggestions = 'No suggestions from Amazon Q'
export const noInlineSuggestionsMsg = 'No suggestions from Amazon Q'

export const licenseFilter = 'Amazon Q suggestions were filtered due to reference settings'

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/shared/utilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
export { isExtensionInstalled, isExtensionActive } from './vsCodeUtils'
export { VSCODE_EXTENSION_ID } from '../extensions'
export * from './functionUtils'
export * as messageUtils from './messages'