Skip to content

Commit 6988762

Browse files
committed
wip
1 parent 947c471 commit 6988762

File tree

8 files changed

+390
-173
lines changed

8 files changed

+390
-173
lines changed

packages/amazonq/src/lsp/chat/activation.ts

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ import {
1717
updateConfigurationRequestType,
1818
} from '@aws/language-server-runtimes/protocol'
1919

20-
export async function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) {
20+
export async function activate(
21+
languageClient: LanguageClient,
22+
encryptionKey: Buffer,
23+
mynahUIPath: string,
24+
injectedProvider?: AmazonQChatViewProvider
25+
) {
2126
const disposables = globals.context.subscriptions
2227

2328
// Make sure we've sent an auth profile to the language server before even initializing the UI
@@ -26,21 +31,30 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu
2631
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
2732
})
2833

29-
const provider = new AmazonQChatViewProvider(mynahUIPath)
34+
const provider = injectedProvider ?? new AmazonQChatViewProvider(mynahUIPath)
3035

31-
disposables.push(
32-
window.registerWebviewViewProvider(AmazonQChatViewProvider.viewType, provider, {
33-
webviewOptions: {
34-
retainContextWhenHidden: true,
35-
},
36-
})
37-
)
36+
try {
37+
disposables.push(
38+
window.registerWebviewViewProvider(AmazonQChatViewProvider.viewType, provider, {
39+
webviewOptions: {
40+
retainContextWhenHidden: true,
41+
},
42+
})
43+
)
44+
} catch (err) {
45+
getLogger().debug('Webview provider already registered: %O', err)
46+
}
3847

3948
/**
4049
* Commands are registered independent of the webview being open because when they're executed
4150
* they focus the webview
4251
**/
43-
registerCommands(provider)
52+
try {
53+
registerCommands(provider)
54+
} catch (err) {
55+
getLogger().debug('Webview provider already registered: %O', err)
56+
}
57+
4458
registerLanguageServerEventListener(languageClient, provider)
4559

4660
provider.onDidResolveWebview(() => {
@@ -70,23 +84,34 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu
7084
})
7185

7286
// register event listeners from the legacy agent flow
73-
await registerLegacyChatListeners(globals.context)
87+
try {
88+
// register event listeners from the legacy agent flow
89+
await registerLegacyChatListeners(globals.context)
90+
} catch (err) {
91+
getLogger().info('Legacy chat listeners already registered: %O', err)
92+
}
7493

75-
disposables.push(
76-
AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => {
77-
void pushConfigUpdate(languageClient, {
78-
type: 'profile',
79-
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
80-
})
81-
await provider.refreshWebview()
82-
}),
83-
Commands.register('aws.amazonq.updateCustomizations', () => {
84-
void pushConfigUpdate(languageClient, {
85-
type: 'customization',
86-
customization: undefinedIfEmpty(getSelectedCustomization().arn),
94+
try {
95+
disposables.push(
96+
AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => {
97+
void pushConfigUpdate(languageClient, {
98+
type: 'profile',
99+
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
100+
})
101+
await provider.refreshWebview()
102+
}),
103+
Commands.register('aws.amazonq.updateCustomizations', () => {
104+
void pushConfigUpdate(languageClient, {
105+
type: 'customization',
106+
customization: undefinedIfEmpty(getSelectedCustomization().arn),
107+
})
87108
})
88-
})
89-
)
109+
)
110+
} catch (err) {
111+
getLogger().info('Event listeners already registered: %O', err)
112+
}
113+
114+
return provider
90115
}
91116

92117
/**

packages/amazonq/src/lsp/chat/webviewProvider.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
8181
performance.mark(amazonqMark.open)
8282
}
8383

84-
private async getWebviewContent() {
84+
public async getWebviewContent() {
8585
const featureConfigData = await featureConfig.getFeatureConfigs()
8686

8787
const isSM = isSageMaker('SMAI')
@@ -110,7 +110,6 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
110110
script-src ${entrypoint} filesystem: file: vscode-resource: https: ws: wss: 'unsafe-inline';`
111111

112112
return `
113-
<!DOCTYPE html>
114113
<html lang="en">
115114
<head>
116115
<meta charset="UTF-8">

packages/amazonq/src/lsp/client.ts

Lines changed: 112 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,20 @@ import {
3636
} from 'aws-core-vscode/shared'
3737
import { activate } from './chat/activation'
3838
import { AmazonQResourcePaths } from './lspInstaller'
39+
import { LspClient } from 'aws-core-vscode/amazonq'
3940

4041
const localize = nls.loadMessageBundle()
4142
const logger = getLogger('amazonqLsp.lspClient')
4243

4344
export async function startLanguageServer(
4445
extensionContext: vscode.ExtensionContext,
4546
resourcePaths: AmazonQResourcePaths
46-
) {
47+
): Promise<LanguageClient> {
48+
if (LspClient.instance.client) {
49+
logger.info('Language server already running, skipping initialization')
50+
return LspClient.instance.client
51+
}
52+
4753
const toDispose = extensionContext.subscriptions
4854

4955
const serverModule = resourcePaths.lsp
@@ -156,129 +162,131 @@ export async function startLanguageServer(
156162
}),
157163
}
158164

159-
const client = new LanguageClient(
165+
LspClient.instance.client = new LanguageClient(
160166
clientId,
161167
localize('amazonq.server.name', 'Amazon Q Language Server'),
162168
serverOptions,
163169
clientOptions
164170
)
171+
const client = LspClient.instance.client
165172

166173
const disposable = client.start()
167174
toDispose.push(disposable)
168175

169176
const auth = new AmazonQLspAuth(client)
170177

171-
return client.onReady().then(async () => {
172-
await auth.refreshConnection()
178+
await client.onReady()
179+
await auth.refreshConnection()
173180

174-
if (Experiments.instance.get('amazonqLSPInline', false)) {
175-
const inlineManager = new InlineCompletionManager(client)
176-
inlineManager.registerInlineCompletion()
177-
toDispose.push(
178-
inlineManager,
179-
Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => {
180-
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
181-
}),
182-
vscode.workspace.onDidCloseTextDocument(async () => {
183-
await vscode.commands.executeCommand('aws.amazonq.rejectCodeSuggestion')
184-
})
185-
)
186-
}
181+
if (Experiments.instance.get('amazonqLSPInline', false)) {
182+
const inlineManager = new InlineCompletionManager(client)
183+
inlineManager.registerInlineCompletion()
184+
toDispose.push(
185+
inlineManager,
186+
Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => {
187+
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
188+
}),
189+
vscode.workspace.onDidCloseTextDocument(async () => {
190+
await vscode.commands.executeCommand('aws.amazonq.rejectCodeSuggestion')
191+
})
192+
)
193+
}
187194

188-
if (Experiments.instance.get('amazonqChatLSP', true)) {
189-
await activate(client, encryptionKey, resourcePaths.ui)
190-
}
195+
if (Experiments.instance.get('amazonqChatLSP', true)) {
196+
await activate(client, encryptionKey, resourcePaths.ui)
197+
}
191198

192-
const refreshInterval = auth.startTokenRefreshInterval(10 * oneSecond)
199+
const refreshInterval = auth.startTokenRefreshInterval(10 * oneSecond)
193200

194-
const sendProfileToLsp = async () => {
195-
try {
196-
const result = await client.sendRequest(updateConfigurationRequestType.method, {
197-
section: 'aws.q',
198-
settings: {
199-
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
200-
},
201-
})
202-
client.info(
203-
`Client: Updated Amazon Q Profile ${AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn} to Amazon Q LSP`,
204-
result
205-
)
206-
} catch (err) {
207-
client.error('Error when setting Q Developer Profile to Amazon Q LSP', err)
208-
}
201+
const sendProfileToLsp = async () => {
202+
try {
203+
const result = await client.sendRequest(updateConfigurationRequestType.method, {
204+
section: 'aws.q',
205+
settings: {
206+
profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn,
207+
},
208+
})
209+
client.info(
210+
`Client: Updated Amazon Q Profile ${AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn} to Amazon Q LSP`,
211+
result
212+
)
213+
} catch (err) {
214+
client.error('Error when setting Q Developer Profile to Amazon Q LSP', err)
209215
}
216+
}
210217

211-
// send profile to lsp once.
212-
void sendProfileToLsp()
218+
// send profile to lsp once.
219+
void sendProfileToLsp()
213220

214-
toDispose.push(
215-
AuthUtil.instance.auth.onDidChangeActiveConnection(async () => {
216-
await auth.refreshConnection()
217-
}),
218-
AuthUtil.instance.auth.onDidDeleteConnection(async () => {
219-
client.sendNotification(notificationTypes.deleteBearerToken.method)
220-
}),
221-
AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(sendProfileToLsp),
222-
vscode.commands.registerCommand('aws.amazonq.getWorkspaceId', async () => {
223-
const requestType = new RequestType<GetConfigurationFromServerParams, ResponseMessage, Error>(
224-
'aws/getConfigurationFromServer'
225-
)
226-
const workspaceIdResp = await client.sendRequest(requestType.method, {
227-
section: 'aws.q.workspaceContext',
228-
})
229-
return workspaceIdResp
230-
}),
231-
vscode.workspace.onDidCreateFiles((e) => {
232-
client.sendNotification('workspace/didCreateFiles', {
233-
files: e.files.map((it) => {
234-
return { uri: it.fsPath }
235-
}),
236-
} as CreateFilesParams)
237-
}),
238-
vscode.workspace.onDidDeleteFiles((e) => {
239-
client.sendNotification('workspace/didDeleteFiles', {
240-
files: e.files.map((it) => {
241-
return { uri: it.fsPath }
221+
toDispose.push(
222+
AuthUtil.instance.auth.onDidChangeActiveConnection(async () => {
223+
await auth.refreshConnection()
224+
}),
225+
AuthUtil.instance.auth.onDidDeleteConnection(async () => {
226+
client.sendNotification(notificationTypes.deleteBearerToken.method)
227+
}),
228+
AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(sendProfileToLsp),
229+
vscode.commands.registerCommand('aws.amazonq.getWorkspaceId', async () => {
230+
const requestType = new RequestType<GetConfigurationFromServerParams, ResponseMessage, Error>(
231+
'aws/getConfigurationFromServer'
232+
)
233+
const workspaceIdResp = await client.sendRequest(requestType.method, {
234+
section: 'aws.q.workspaceContext',
235+
})
236+
return workspaceIdResp
237+
}),
238+
vscode.workspace.onDidCreateFiles((e) => {
239+
client.sendNotification('workspace/didCreateFiles', {
240+
files: e.files.map((it) => {
241+
return { uri: it.fsPath }
242+
}),
243+
} as CreateFilesParams)
244+
}),
245+
vscode.workspace.onDidDeleteFiles((e) => {
246+
client.sendNotification('workspace/didDeleteFiles', {
247+
files: e.files.map((it) => {
248+
return { uri: it.fsPath }
249+
}),
250+
} as DeleteFilesParams)
251+
}),
252+
vscode.workspace.onDidRenameFiles((e) => {
253+
client.sendNotification('workspace/didRenameFiles', {
254+
files: e.files.map((it) => {
255+
return { oldUri: it.oldUri.fsPath, newUri: it.newUri.fsPath }
256+
}),
257+
} as RenameFilesParams)
258+
}),
259+
vscode.workspace.onDidSaveTextDocument((e) => {
260+
client.sendNotification('workspace/didSaveTextDocument', {
261+
textDocument: {
262+
uri: e.uri.fsPath,
263+
},
264+
} as DidSaveTextDocumentParams)
265+
}),
266+
vscode.workspace.onDidChangeWorkspaceFolders((e) => {
267+
client.sendNotification('workspace/didChangeWorkspaceFolder', {
268+
event: {
269+
added: e.added.map((it) => {
270+
return {
271+
name: it.name,
272+
uri: it.uri.fsPath,
273+
} as WorkspaceFolder
242274
}),
243-
} as DeleteFilesParams)
244-
}),
245-
vscode.workspace.onDidRenameFiles((e) => {
246-
client.sendNotification('workspace/didRenameFiles', {
247-
files: e.files.map((it) => {
248-
return { oldUri: it.oldUri.fsPath, newUri: it.newUri.fsPath }
275+
removed: e.removed.map((it) => {
276+
return {
277+
name: it.name,
278+
uri: it.uri.fsPath,
279+
} as WorkspaceFolder
249280
}),
250-
} as RenameFilesParams)
251-
}),
252-
vscode.workspace.onDidSaveTextDocument((e) => {
253-
client.sendNotification('workspace/didSaveTextDocument', {
254-
textDocument: {
255-
uri: e.uri.fsPath,
256-
},
257-
} as DidSaveTextDocumentParams)
258-
}),
259-
vscode.workspace.onDidChangeWorkspaceFolders((e) => {
260-
client.sendNotification('workspace/didChangeWorkspaceFolder', {
261-
event: {
262-
added: e.added.map((it) => {
263-
return {
264-
name: it.name,
265-
uri: it.uri.fsPath,
266-
} as WorkspaceFolder
267-
}),
268-
removed: e.removed.map((it) => {
269-
return {
270-
name: it.name,
271-
uri: it.uri.fsPath,
272-
} as WorkspaceFolder
273-
}),
274-
},
275-
} as DidChangeWorkspaceFoldersParams)
276-
}),
277-
{ dispose: () => clearInterval(refreshInterval) },
278-
// Set this inside onReady so that it only triggers on subsequent language server starts (not the first)
279-
onServerRestartHandler(client, auth)
280-
)
281-
})
281+
},
282+
} as DidChangeWorkspaceFoldersParams)
283+
}),
284+
{ dispose: () => clearInterval(refreshInterval) },
285+
// Set this inside onReady so that it only triggers on subsequent language server starts (not the first)
286+
onServerRestartHandler(client, auth)
287+
)
288+
289+
return client
282290
}
283291

284292
/**

0 commit comments

Comments
 (0)