Skip to content

Commit 271f592

Browse files
committed
fix(amazonq): update cursor tracking based on autotrigger setting
1 parent 9bd9d99 commit 271f592

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { LanguageClient } from 'vscode-languageclient'
88
import { getLogger } from 'aws-core-vscode/shared'
99
import { globals } from 'aws-core-vscode/shared'
1010
import { AmazonQInlineCompletionItemProvider } from './completion'
11+
import { CodeSuggestionsState } from 'aws-core-vscode/codewhisperer'
1112

1213
// Configuration section for cursor updates
1314
export const cursorUpdateConfigurationSection = 'aws.q.cursorUpdate'
@@ -32,11 +33,23 @@ export class CursorUpdateManager implements vscode.Disposable, ICursorUpdateReco
3233
private lastSentDocumentUri?: string
3334
private isActive = false
3435
private lastRequestTime = 0
36+
private autotriggerStateDisposable?: vscode.Disposable
3537

3638
constructor(
3739
private readonly languageClient: LanguageClient,
3840
private readonly inlineCompletionProvider?: AmazonQInlineCompletionItemProvider
39-
) {}
41+
) {
42+
// Listen for autotrigger state changes to enable/disable the timer
43+
this.autotriggerStateDisposable = CodeSuggestionsState.instance.onDidChangeState((isEnabled: boolean) => {
44+
if (isEnabled && this.isActive) {
45+
// If autotrigger is enabled and we're active, ensure timer is running
46+
this.setupUpdateTimer()
47+
} else {
48+
// If autotrigger is disabled, clear the timer but keep isActive state
49+
this.clearUpdateTimer()
50+
}
51+
})
52+
}
4053

4154
/**
4255
* Start tracking cursor positions and sending periodic updates
@@ -66,7 +79,9 @@ export class CursorUpdateManager implements vscode.Disposable, ICursorUpdateReco
6679
}
6780

6881
this.isActive = true
69-
this.setupUpdateTimer()
82+
if (CodeSuggestionsState.instance.isSuggestionsEnabled()) {
83+
this.setupUpdateTimer()
84+
}
7085
}
7186

7287
/**
@@ -130,7 +145,7 @@ export class CursorUpdateManager implements vscode.Disposable, ICursorUpdateReco
130145
}
131146

132147
/**
133-
* Send a cursor position update to the language server
148+
* Request LSP generate a completion for the current cursor position.
134149
*/
135150
private async sendCursorUpdate(): Promise<void> {
136151
// Don't send an update if a regular request was made recently
@@ -185,6 +200,12 @@ export class CursorUpdateManager implements vscode.Disposable, ICursorUpdateReco
185200
* Dispose of resources
186201
*/
187202
public dispose(): void {
203+
// Dispose of the autotrigger state change listener
204+
if (this.autotriggerStateDisposable) {
205+
this.autotriggerStateDisposable.dispose()
206+
this.autotriggerStateDisposable = undefined
207+
}
208+
188209
this.stop()
189210
}
190211
}

packages/amazonq/test/unit/app/inline/cursorUpdateManager.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,66 @@ describe('CursorUpdateManager', () => {
236236
// Verify the provider was called again
237237
assert.strictEqual(provideStub.callCount, 1, 'Update should be sent when position has changed')
238238
})
239+
240+
describe('autotrigger state handling', () => {
241+
let codeSuggestionsStateStub: sinon.SinonStubbedInstance<any>
242+
let onDidChangeStateStub: sinon.SinonStub
243+
let mockDisposable: { dispose: sinon.SinonStub }
244+
245+
beforeEach(() => {
246+
// Mock the disposable returned by onDidChangeState
247+
mockDisposable = { dispose: sinon.stub() }
248+
onDidChangeStateStub = sinon.stub().returns(mockDisposable)
249+
250+
codeSuggestionsStateStub = {
251+
isSuggestionsEnabled: sinon.stub().returns(true),
252+
onDidChangeState: onDidChangeStateStub,
253+
}
254+
255+
// Mock the CodeSuggestionsState import
256+
const CodeSuggestionsState = require('aws-core-vscode/codewhisperer')
257+
sinon.stub(CodeSuggestionsState, 'CodeSuggestionsState').value({
258+
instance: codeSuggestionsStateStub,
259+
})
260+
})
261+
262+
it('should not start timer when autotrigger is disabled', async () => {
263+
// Test the new behavior: timer doesn't start when autotrigger is disabled
264+
codeSuggestionsStateStub.isSuggestionsEnabled.returns(false)
265+
sendRequestStub.resolves({})
266+
267+
await cursorUpdateManager.start()
268+
269+
// Manager should be active but timer should not be started
270+
assert.strictEqual((cursorUpdateManager as any).isActive, true)
271+
assert.ok(!setIntervalStub.called, 'Timer should NOT be started when autotrigger is disabled')
272+
})
273+
274+
it('should start/stop timer when autotrigger state changes', async () => {
275+
// Start with autotrigger enabled
276+
codeSuggestionsStateStub.isSuggestionsEnabled.returns(true)
277+
sendRequestStub.resolves({})
278+
await cursorUpdateManager.start()
279+
280+
// Get the state change callback
281+
const stateChangeCallback = onDidChangeStateStub.firstCall.args[0]
282+
283+
// Reset stubs to test state changes
284+
setIntervalStub.resetHistory()
285+
clearIntervalStub.resetHistory()
286+
287+
// Simulate autotrigger being disabled
288+
stateChangeCallback(false)
289+
assert.ok(clearIntervalStub.called, 'Timer should be stopped when autotrigger is disabled')
290+
291+
// Simulate autotrigger being enabled again
292+
stateChangeCallback(true)
293+
assert.ok(setIntervalStub.called, 'Timer should be started when autotrigger is re-enabled')
294+
})
295+
296+
it('should dispose autotrigger state listener on dispose', () => {
297+
cursorUpdateManager.dispose()
298+
assert.ok(mockDisposable.dispose.called, 'Autotrigger state listener should be disposed')
299+
})
300+
})
239301
})

0 commit comments

Comments
 (0)