Skip to content

Commit 2a98342

Browse files
committed
Add LSP auth to client and activation
1 parent b98cb99 commit 2a98342

File tree

2 files changed

+84
-12
lines changed

2 files changed

+84
-12
lines changed

packages/amazonq/src/lsp/activation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { startLanguageServer } from './client'
88
import { AmazonQLspInstaller } from './lspInstaller'
99
import { lspSetupStage, ToolkitError } from 'aws-core-vscode/shared'
1010

11-
export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
11+
export async function activate(ctx: vscode.ExtensionContext) {
1212
try {
1313
await lspSetupStage('all', async () => {
1414
const installResult = await new AmazonQLspInstaller().resolve()
15-
await lspSetupStage('launch', async () => await startLanguageServer(ctx, installResult.resourcePaths))
15+
return await lspSetupStage('launch', () => startLanguageServer(ctx, installResult.resourcePaths))
1616
})
1717
} catch (err) {
1818
const e = err as ToolkitError

packages/amazonq/src/lsp/client.ts

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,40 @@
66
import vscode, { env, version } from 'vscode'
77
import * as nls from 'vscode-nls'
88
import * as crypto from 'crypto'
9+
import * as jose from 'jose'
910
import { LanguageClient, LanguageClientOptions } from 'vscode-languageclient'
1011
import { InlineCompletionManager } from '../app/inline/completion'
1112
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
12-
import { ConnectionMetadata } from '@aws/language-server-runtimes/protocol'
13-
import { Settings, oidcClientName, createServerOptions, globals, Experiments, Commands } from 'aws-core-vscode/shared'
13+
import {
14+
ConnectionMetadata,
15+
GetSsoTokenProgress,
16+
GetSsoTokenProgressToken,
17+
GetSsoTokenProgressType,
18+
MessageActionItem,
19+
ShowDocumentParams,
20+
ShowDocumentRequest,
21+
ShowDocumentResult,
22+
ShowMessageRequest,
23+
ShowMessageRequestParams,
24+
} from '@aws/language-server-runtimes/protocol'
25+
import {
26+
Settings,
27+
oidcClientName,
28+
createServerOptions,
29+
globals,
30+
Experiments,
31+
Commands,
32+
openUrl,
33+
getLogger,
34+
} from 'aws-core-vscode/shared'
1435
import { activate } from './chat/activation'
1536
import { AmazonQResourcePaths } from './lspInstaller'
1637
import { auth2 } from 'aws-core-vscode/auth'
1738

1839
const localize = nls.loadMessageBundle()
1940

41+
export const clientId = 'amazonq'
42+
export const clientName = oidcClientName()
2043
export const encryptionKey = crypto.randomBytes(32)
2144

2245
export async function startLanguageServer(
@@ -41,8 +64,6 @@ export async function startLanguageServer(
4164
})
4265

4366
const documentSelector = [{ scheme: 'file', language: '*' }]
44-
45-
const clientId = 'amazonq'
4667
const traceServerEnabled = Settings.instance.isSet(`${clientId}.trace.server`)
4768

4869
// Options to control the language client
@@ -82,12 +103,8 @@ export async function startLanguageServer(
82103
}),
83104
}
84105

85-
const client = new LanguageClient(
86-
clientId,
87-
localize('amazonq.server.name', 'Amazon Q Language Server'),
88-
serverOptions,
89-
clientOptions
90-
)
106+
const lspName = localize('amazonq.server.name', 'Amazon Q Language Server')
107+
const client = new LanguageClient(clientId, lspName, serverOptions, clientOptions)
91108

92109
const disposable = client.start()
93110
toDispose.push(disposable)
@@ -102,6 +119,59 @@ export async function startLanguageServer(
102119
}
103120
})
104121

122+
client.onRequest<ShowDocumentResult, Error>(ShowDocumentRequest.method, async (params: ShowDocumentParams) => {
123+
try {
124+
return { success: await openUrl(vscode.Uri.parse(params.uri), lspName) }
125+
} catch (err: any) {
126+
getLogger().error(`Failed to open document for LSP: ${lspName}, error: %s`, err)
127+
return { success: false }
128+
}
129+
})
130+
131+
client.onRequest<MessageActionItem | null, Error>(
132+
ShowMessageRequest.method,
133+
async (params: ShowMessageRequestParams) => {
134+
const actions = params.actions?.map((a) => a.title) ?? []
135+
const response = await vscode.window.showInformationMessage(params.message, { modal: true }, ...actions)
136+
return params.actions?.find((a) => a.title === response) ?? (undefined as unknown as null)
137+
}
138+
)
139+
140+
let promise: Promise<void> | undefined
141+
let resolver: () => void = () => {}
142+
client.onProgress(
143+
GetSsoTokenProgressType,
144+
GetSsoTokenProgressToken,
145+
async (partialResult: GetSsoTokenProgress) => {
146+
const decryptedKey = await jose.compactDecrypt(partialResult as unknown as string, encryptionKey)
147+
const val: GetSsoTokenProgress = JSON.parse(decryptedKey.plaintext.toString())
148+
149+
if (val.state === 'InProgress') {
150+
if (promise) {
151+
resolver()
152+
}
153+
promise = new Promise<void>((resolve) => {
154+
resolver = resolve
155+
})
156+
} else {
157+
resolver()
158+
promise = undefined
159+
return
160+
}
161+
162+
void vscode.window.withProgress(
163+
{
164+
cancellable: true,
165+
location: vscode.ProgressLocation.Notification,
166+
title: val.message,
167+
},
168+
async (_) => {
169+
await promise
170+
}
171+
)
172+
}
173+
)
174+
105175
if (Experiments.instance.get('amazonqLSPInline', false)) {
106176
const inlineManager = new InlineCompletionManager(client)
107177
inlineManager.registerInlineCompletion()
@@ -118,6 +188,8 @@ export async function startLanguageServer(
118188

119189
if (Experiments.instance.get('amazonqChatLSP', false)) {
120190
activate(client, encryptionKey, resourcePaths.ui)
191+
AuthUtil.create(new auth2.LanguageClientAuth(client, clientId, encryptionKey))
192+
await AuthUtil.instance.restore()
121193
}
122194
})
123195
}

0 commit comments

Comments
 (0)