Skip to content

Commit 25ba908

Browse files
committed
chore(amazonq): refactor codeWhispereServer.ts
1 parent 1f6b7f7 commit 25ba908

File tree

7 files changed

+1051
-676
lines changed

7 files changed

+1051
-676
lines changed

server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts

Lines changed: 48 additions & 654 deletions
Large diffs are not rendered by default.

server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts renamed to server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,35 @@ import {
99
ResponseError,
1010
TextDocument,
1111
} from '@aws/language-server-runtimes/protocol'
12-
import { RecentEditTracker } from './tracker/codeEditTracker'
12+
import { RecentEditTracker } from '../tracker/codeEditTracker'
1313
import { CredentialsProvider, Logging, Telemetry, Workspace } from '@aws/language-server-runtimes/server-interface'
1414
import {
1515
CodeWhispererServiceToken,
1616
GenerateSuggestionsRequest,
1717
GenerateSuggestionsResponse,
1818
getFileContext,
1919
SuggestionType,
20-
} from '../../shared/codeWhispererService'
21-
import { CodeWhispererSession, SessionManager } from './session/sessionManager'
22-
import { CursorTracker } from './tracker/cursorTracker'
23-
import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection'
24-
import { WorkspaceFolderManager } from '../workspaceContext/workspaceFolderManager'
25-
import { shouldTriggerEdits } from './trigger'
20+
} from '../../../shared/codeWhispererService'
21+
import { CodeWhispererSession, SessionManager } from '../session/sessionManager'
22+
import { CursorTracker } from '../tracker/cursorTracker'
23+
import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection'
24+
import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager'
25+
import { shouldTriggerEdits } from '../trigger'
2626
import {
2727
emitEmptyUserTriggerDecisionTelemetry,
2828
emitServiceInvocationFailure,
2929
emitServiceInvocationTelemetry,
3030
emitUserTriggerDecisionTelemetry,
31-
} from './telemetry/telemetry'
32-
import { TelemetryService } from '../../shared/telemetry/telemetryService'
31+
} from '../telemetry/telemetry'
32+
import { TelemetryService } from '../../../shared/telemetry/telemetryService'
3333
import { textUtils } from '@aws/lsp-core'
34-
import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager'
35-
import { RejectedEditTracker } from './tracker/rejectedEditTracker'
36-
import { getErrorMessage, hasConnectionExpired } from '../../shared/utils'
37-
import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../shared/amazonQServiceManager/errors'
38-
import { DocumentChangedListener } from './documentChangedListener'
39-
import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './contants/constants'
40-
import { StreakTracker } from './tracker/streakTracker'
34+
import { AmazonQBaseServiceManager } from '../../../shared/amazonQServiceManager/BaseAmazonQServiceManager'
35+
import { RejectedEditTracker } from '../tracker/rejectedEditTracker'
36+
import { getErrorMessage, hasConnectionExpired } from '../../../shared/utils'
37+
import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../../shared/amazonQServiceManager/errors'
38+
import { DocumentChangedListener } from '../documentChangedListener'
39+
import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from '../contants/constants'
40+
import { StreakTracker } from '../tracker/streakTracker'
4141

4242
export class EditCompletionHandler {
4343
private readonly editsEnabled: boolean
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import * as assert from 'assert'
2+
import * as sinon from 'sinon'
3+
import { TextDocument } from 'vscode-languageserver-textdocument'
4+
import { InlineCompletionHandler } from './inlineCompletionHandler'
5+
import { SessionManager } from '../session/sessionManager'
6+
import { CodePercentageTracker } from '../tracker/codePercentageTracker'
7+
import { RecentEditTracker } from '../tracker/codeEditTracker'
8+
import { CursorTracker } from '../tracker/cursorTracker'
9+
import { StreakTracker } from '../tracker/streakTracker'
10+
import { TelemetryService } from '../../../shared/telemetry/telemetryService'
11+
import { UserWrittenCodeTracker } from '../../../shared/userWrittenCodeTracker'
12+
import { InlineCompletionTriggerKind, CancellationToken } from '@aws/language-server-runtimes/server-interface'
13+
import { EMPTY_RESULT } from '../contants/constants'
14+
import * as IdleWorkspaceManagerModule from '../../workspaceContext/IdleWorkspaceManager'
15+
import * as telemetryModule from '../telemetry/telemetry'
16+
17+
describe('InlineCompletionHandler', () => {
18+
const testDocument = TextDocument.create('file:///test.cs', 'csharp', 1, 'test content')
19+
20+
const completionParams = {
21+
textDocument: { uri: testDocument.uri },
22+
position: { line: 0, character: 0 },
23+
context: { triggerKind: InlineCompletionTriggerKind.Invoked },
24+
}
25+
26+
let handler: InlineCompletionHandler
27+
let completionSessionManager: SessionManager
28+
let amazonQServiceManager: any
29+
let codePercentageTracker: sinon.SinonStubbedInstance<CodePercentageTracker>
30+
let userWrittenCodeTracker: sinon.SinonStubbedInstance<UserWrittenCodeTracker>
31+
let recentEditTracker: sinon.SinonStubbedInstance<RecentEditTracker>
32+
let cursorTracker: sinon.SinonStubbedInstance<CursorTracker>
33+
let streakTracker: sinon.SinonStubbedInstance<StreakTracker>
34+
let telemetryService: sinon.SinonStubbedInstance<TelemetryService>
35+
let lsp: any
36+
let telemetry: any
37+
let credentialsProvider: any
38+
let workspace: any
39+
let logging: any
40+
let getTextDocument: sinon.SinonStub
41+
42+
beforeEach(() => {
43+
SessionManager.reset()
44+
completionSessionManager = SessionManager.getInstance('COMPLETIONS')
45+
46+
amazonQServiceManager = {
47+
getCodewhispererService: sinon.stub(),
48+
getConfiguration: sinon.stub().returns({ inlineSuggestions: {} }),
49+
}
50+
codePercentageTracker = sinon.createStubInstance(CodePercentageTracker)
51+
userWrittenCodeTracker = sinon.createStubInstance(UserWrittenCodeTracker)
52+
recentEditTracker = sinon.createStubInstance(RecentEditTracker)
53+
cursorTracker = sinon.createStubInstance(CursorTracker)
54+
streakTracker = sinon.createStubInstance(StreakTracker)
55+
telemetryService = sinon.createStubInstance(TelemetryService)
56+
57+
workspace = { getWorkspaceFolder: sinon.stub() }
58+
logging = { log: sinon.stub(), debug: sinon.stub() }
59+
getTextDocument = sinon.stub().resolves(testDocument)
60+
lsp = { getClientInitializeParams: sinon.stub() }
61+
telemetry = { emitMetric: sinon.stub() } as any
62+
credentialsProvider = { getConnectionMetadata: sinon.stub() } as any
63+
64+
// Stub IdleWorkspaceManager and telemetry functions
65+
sinon.stub(IdleWorkspaceManagerModule.IdleWorkspaceManager, 'recordActivityTimestamp')
66+
sinon.stub(telemetryModule, 'emitServiceInvocationTelemetry')
67+
sinon.stub(telemetryModule, 'emitServiceInvocationFailure')
68+
sinon.stub(telemetryModule, 'emitUserTriggerDecisionTelemetry')
69+
70+
handler = new InlineCompletionHandler(
71+
logging,
72+
workspace,
73+
amazonQServiceManager,
74+
completionSessionManager,
75+
codePercentageTracker,
76+
userWrittenCodeTracker,
77+
recentEditTracker,
78+
cursorTracker,
79+
streakTracker,
80+
telemetry,
81+
telemetryService,
82+
credentialsProvider,
83+
false,
84+
1000,
85+
lsp,
86+
getTextDocument
87+
)
88+
})
89+
90+
afterEach(() => {
91+
sinon.restore()
92+
})
93+
94+
it('should return empty result when concurrent request is in progress', async () => {
95+
// Make handler busy
96+
handler['isOnInlineCompletionHandlerInProgress'] = true
97+
98+
const result = await handler.onInlineCompletion(completionParams, CancellationToken.None)
99+
100+
assert.deepEqual(result, EMPTY_RESULT)
101+
sinon.assert.calledWith(logging.log, 'Skip concurrent inline completion')
102+
})
103+
104+
it('should return empty result when service manager not initialized', async () => {
105+
handler = new InlineCompletionHandler(
106+
logging,
107+
workspace,
108+
null as any,
109+
completionSessionManager,
110+
codePercentageTracker,
111+
userWrittenCodeTracker,
112+
recentEditTracker,
113+
cursorTracker,
114+
streakTracker,
115+
{ emitMetric: sinon.stub() } as any,
116+
telemetryService,
117+
{ getConnectionMetadata: sinon.stub() } as any,
118+
false,
119+
1000,
120+
{ getClientInitializeParams: sinon.stub() },
121+
getTextDocument
122+
)
123+
124+
const result = await handler.onInlineCompletion(completionParams, CancellationToken.None)
125+
126+
assert.deepEqual(result, EMPTY_RESULT)
127+
sinon.assert.calledWith(logging.log, 'Amazon Q Service Manager not initialized yet')
128+
})
129+
130+
it('should return empty result when text document not found', async () => {
131+
getTextDocument.resolves(null)
132+
133+
const result = await handler.onInlineCompletion(completionParams, CancellationToken.None)
134+
135+
assert.deepEqual(result, EMPTY_RESULT)
136+
sinon.assert.calledWith(logging.log, `textDocument [${testDocument.uri}] not found`)
137+
})
138+
139+
it('should track cursor position when cursor tracker available', async () => {
140+
getTextDocument.resolves(null) // Will return early
141+
142+
await handler.onInlineCompletion(completionParams, CancellationToken.None)
143+
144+
sinon.assert.calledWith(cursorTracker.trackPosition, testDocument.uri, completionParams.position)
145+
})
146+
})

0 commit comments

Comments
 (0)