Skip to content

Commit 45b0236

Browse files
committed
reduce duplication across stage implementations
1 parent 3304e99 commit 45b0236

File tree

5 files changed

+110
-114
lines changed

5 files changed

+110
-114
lines changed

packages/core/src/amazonq/lsp/lspClient.ts

Lines changed: 83 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import {
3333
import { Writable } from 'stream'
3434
import { CodeWhispererSettings } from '../../codewhisperer/util/codewhispererSettings'
3535
import { ResourcePaths, fs, getLogger, globals } from '../../shared'
36-
import { telemetry } from '../../shared/telemetry'
3736

3837
const localize = nls.loadMessageBundle()
3938

@@ -174,108 +173,103 @@ export class LspClient {
174173
* This function assumes the LSP server has already been downloaded.
175174
*/
176175
export async function activate(extensionContext: ExtensionContext, resourcePaths: ResourcePaths) {
177-
return await telemetry.languageServer_setup.run(async (span) => {
178-
span.record({ languageServerSetupStage: 'launch' })
179-
const startTime = performance.now()
180-
LspClient.instance
181-
const toDispose = extensionContext.subscriptions
176+
LspClient.instance
177+
const toDispose = extensionContext.subscriptions
182178

183-
let rangeFormatting: Disposable | undefined
184-
// The debug options for the server
185-
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
186-
const debugOptions = { execArgv: ['--nolazy', '--preserve-symlinks', '--stdio'] }
179+
let rangeFormatting: Disposable | undefined
180+
// The debug options for the server
181+
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
182+
const debugOptions = { execArgv: ['--nolazy', '--preserve-symlinks', '--stdio'] }
187183

188-
const workerThreads = CodeWhispererSettings.instance.getIndexWorkerThreads()
189-
const gpu = CodeWhispererSettings.instance.isLocalIndexGPUEnabled()
184+
const workerThreads = CodeWhispererSettings.instance.getIndexWorkerThreads()
185+
const gpu = CodeWhispererSettings.instance.isLocalIndexGPUEnabled()
190186

191-
if (gpu) {
192-
process.env.Q_ENABLE_GPU = 'true'
193-
} else {
194-
delete process.env.Q_ENABLE_GPU
195-
}
196-
if (workerThreads > 0 && workerThreads < 100) {
197-
process.env.Q_WORKER_THREADS = workerThreads.toString()
198-
} else {
199-
delete process.env.Q_WORKER_THREADS
200-
}
187+
if (gpu) {
188+
process.env.Q_ENABLE_GPU = 'true'
189+
} else {
190+
delete process.env.Q_ENABLE_GPU
191+
}
192+
if (workerThreads > 0 && workerThreads < 100) {
193+
process.env.Q_WORKER_THREADS = workerThreads.toString()
194+
} else {
195+
delete process.env.Q_WORKER_THREADS
196+
}
201197

202-
const serverModule = resourcePaths.lsp
198+
const serverModule = resourcePaths.lsp
203199

204-
const child = spawn(resourcePaths.node, [serverModule, ...debugOptions.execArgv])
205-
// share an encryption key using stdin
206-
// follow same practice of DEXP LSP server
207-
writeEncryptionInit(child.stdin)
200+
const child = spawn(resourcePaths.node, [serverModule, ...debugOptions.execArgv])
201+
// share an encryption key using stdin
202+
// follow same practice of DEXP LSP server
203+
writeEncryptionInit(child.stdin)
208204

209-
// If the extension is launch in debug mode the debug server options are use
210-
// Otherwise the run options are used
211-
let serverOptions: ServerOptions = {
212-
run: { module: serverModule, transport: TransportKind.ipc },
213-
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions },
214-
}
205+
// If the extension is launch in debug mode the debug server options are use
206+
// Otherwise the run options are used
207+
let serverOptions: ServerOptions = {
208+
run: { module: serverModule, transport: TransportKind.ipc },
209+
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions },
210+
}
215211

216-
serverOptions = () => Promise.resolve(child!)
212+
serverOptions = () => Promise.resolve(child!)
217213

218-
const documentSelector = [{ scheme: 'file', language: '*' }]
214+
const documentSelector = [{ scheme: 'file', language: '*' }]
219215

220-
// Options to control the language client
221-
const clientOptions: LanguageClientOptions = {
222-
// Register the server for json documents
223-
documentSelector,
224-
initializationOptions: {
225-
handledSchemaProtocols: ['file', 'untitled'], // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client.
226-
provideFormatter: false, // tell the server to not provide formatting capability and ignore the `aws.stepfunctions.asl.format.enable` setting.
227-
// this is used by LSP to determine index cache path, move to this folder so that when extension updates index is not deleted.
228-
extensionPath: path.join(fs.getUserHomeDir(), '.aws', 'amazonq', 'cache'),
229-
},
230-
// Log to the Amazon Q Logs so everything is in a single channel
231-
// TODO: Add prefix to the language server logs so it is easier to search
232-
outputChannel: globals.logOutputChannel,
233-
}
216+
// Options to control the language client
217+
const clientOptions: LanguageClientOptions = {
218+
// Register the server for json documents
219+
documentSelector,
220+
initializationOptions: {
221+
handledSchemaProtocols: ['file', 'untitled'], // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client.
222+
provideFormatter: false, // tell the server to not provide formatting capability and ignore the `aws.stepfunctions.asl.format.enable` setting.
223+
// this is used by LSP to determine index cache path, move to this folder so that when extension updates index is not deleted.
224+
extensionPath: path.join(fs.getUserHomeDir(), '.aws', 'amazonq', 'cache'),
225+
},
226+
// Log to the Amazon Q Logs so everything is in a single channel
227+
// TODO: Add prefix to the language server logs so it is easier to search
228+
outputChannel: globals.logOutputChannel,
229+
}
234230

235-
// Create the language client and start the client.
236-
LspClient.instance.client = new LanguageClient(
237-
'amazonq',
238-
localize('amazonq.server.name', 'Amazon Q Language Server'),
239-
serverOptions,
240-
clientOptions
241-
)
242-
LspClient.instance.client.registerProposedFeatures()
231+
// Create the language client and start the client.
232+
LspClient.instance.client = new LanguageClient(
233+
'amazonq',
234+
localize('amazonq.server.name', 'Amazon Q Language Server'),
235+
serverOptions,
236+
clientOptions
237+
)
238+
LspClient.instance.client.registerProposedFeatures()
243239

244-
const disposable = LspClient.instance.client.start()
245-
toDispose.push(disposable)
240+
const disposable = LspClient.instance.client.start()
241+
toDispose.push(disposable)
246242

247-
let savedDocument: vscode.Uri | undefined = undefined
243+
let savedDocument: vscode.Uri | undefined = undefined
248244

249-
toDispose.push(
250-
vscode.workspace.onDidSaveTextDocument((document) => {
251-
if (document.uri.scheme !== 'file') {
252-
return
253-
}
254-
savedDocument = document.uri
255-
}),
256-
vscode.window.onDidChangeActiveTextEditor((editor) => {
257-
if (savedDocument && editor && editor.document.uri.fsPath !== savedDocument.fsPath) {
258-
void LspClient.instance.updateIndex([savedDocument.fsPath], 'update')
259-
}
260-
}),
261-
vscode.workspace.onDidCreateFiles((e) => {
262-
void LspClient.instance.updateIndex(
263-
e.files.map((f) => f.fsPath),
264-
'add'
265-
)
266-
}),
267-
vscode.workspace.onDidDeleteFiles((e) => {
268-
void LspClient.instance.updateIndex(
269-
e.files.map((f) => f.fsPath),
270-
'remove'
271-
)
272-
})
273-
)
274-
void LspClient.instance.client.onReady().then(() => {
275-
const disposableFunc = { dispose: () => rangeFormatting?.dispose() as void }
276-
toDispose.push(disposableFunc)
245+
toDispose.push(
246+
vscode.workspace.onDidSaveTextDocument((document) => {
247+
if (document.uri.scheme !== 'file') {
248+
return
249+
}
250+
savedDocument = document.uri
251+
}),
252+
vscode.window.onDidChangeActiveTextEditor((editor) => {
253+
if (savedDocument && editor && editor.document.uri.fsPath !== savedDocument.fsPath) {
254+
void LspClient.instance.updateIndex([savedDocument.fsPath], 'update')
255+
}
256+
}),
257+
vscode.workspace.onDidCreateFiles((e) => {
258+
void LspClient.instance.updateIndex(
259+
e.files.map((f) => f.fsPath),
260+
'add'
261+
)
262+
}),
263+
vscode.workspace.onDidDeleteFiles((e) => {
264+
void LspClient.instance.updateIndex(
265+
e.files.map((f) => f.fsPath),
266+
'remove'
267+
)
277268
})
278-
span.record({ duration: performance.now() - startTime })
269+
)
270+
void LspClient.instance.client.onReady().then(() => {
271+
const disposableFunc = { dispose: () => rangeFormatting?.dispose() as void }
272+
toDispose.push(disposableFunc)
279273
})
280274
}
281275

packages/core/src/amazonq/lsp/lspController.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { isCloud9 } from '../../shared/extensionUtilities'
1515
import globals, { isWeb } from '../../shared/extensionGlobals'
1616
import { isAmazonInternalOs } from '../../shared/vscode/env'
1717
import { WorkspaceLSPResolver } from './workspaceInstaller'
18+
import { lspSetupStage } from './util'
1819

1920
export interface Chunk {
2021
readonly filePath: string
@@ -160,13 +161,10 @@ export class LspController {
160161
}
161162
setImmediate(async () => {
162163
try {
163-
await telemetry.languageServer_setup.run(async (span) => {
164-
const startTime = performance.now()
165-
span.record({ languageServerSetupStage: 'final' })
164+
await lspSetupStage('final', async () => {
166165
const installResult = await new WorkspaceLSPResolver().resolve()
167-
await activateLsp(context, installResult.resourcePaths)
166+
await lspSetupStage('launch', async () => activateLsp(context, installResult.resourcePaths))
168167
getLogger().info('LspController: LSP activated')
169-
span.record({ duration: performance.now() - startTime })
170168
})
171169
void LspController.instance.buildIndex(buildIndexConfig)
172170
// log the LSP server CPU and Memory usage per 30 minutes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { LanguageServerSetupStage, telemetry } from '../../shared/telemetry'
7+
8+
export async function lspSetupStage<T>(stageName: LanguageServerSetupStage, stage: () => Promise<T>) {
9+
return await telemetry.languageServer_setup.run(async (span) => {
10+
const startTime = performance.now()
11+
const result = await stage()
12+
span.record({ languageServerSetupStage: stageName })
13+
span.record({ duration: performance.now() - startTime })
14+
return result
15+
})
16+
}

packages/core/src/amazonq/lsp/workspaceInstaller.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Range } from 'semver'
1111
import { getNodeExecutableName } from '../../shared/lsp/utils/platform'
1212
import { fs } from '../../shared/fs/fs'
1313
import { telemetry } from '../../shared/telemetry'
14+
import { lspSetupStage } from './util'
1415

1516
const manifestUrl = 'https://aws-toolkit-language-servers.amazonaws.com/q-context/manifest.json'
1617
// this LSP client in Q extension is only going to work with these LSP server versions
@@ -19,32 +20,25 @@ const supportedLspServerVersions = '0.1.32'
1920
export class WorkspaceLSPResolver implements LspResolver {
2021
async resolve(): Promise<LspResolution> {
2122
const name = 'AmazonQ-Workspace'
22-
const manifest = await telemetry.languageServer_setup.run(async (span) => {
23-
const startTime = performance.now()
24-
span.record({ languageServerSetupStage: 'getManifest' })
23+
const manifest = await lspSetupStage('getManifest', async () => {
2524
const result = await new ManifestResolver(manifestUrl, name).resolve()
26-
span.record({
27-
languageServerResourceLocation: result.location ?? 'unknown',
25+
telemetry.record({
2826
manifestVersion: result.manifestSchemaVersion,
29-
duration: performance.now() - startTime,
27+
languageServerResourceLocation: result.location ?? 'unknown',
3028
})
3129
return result
3230
})
3331
telemetry.record({
3432
manifestVersion: manifest.manifestSchemaVersion,
3533
})
36-
37-
const installationResult = await telemetry.languageServer_setup.run(async (span) => {
38-
const startTime = performance.now()
39-
span.record({ languageServerSetupStage: 'getServer' })
34+
const installationResult = await lspSetupStage('getServer', async () => {
4035
const result = await new LanguageServerResolver(
4136
manifest,
4237
name,
4338
new Range(supportedLspServerVersions)
4439
).resolve()
45-
span.record({
40+
telemetry.record({
4641
languageServerResourceLocation: result.location ?? 'unknown',
47-
duration: performance.now() - startTime,
4842
})
4943
return result
5044
})

packages/core/src/shared/lsp/lspResolver.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { TargetContent, logger, LspResult, LspVersion, Manifest } from './types'
1313
import { getApplicationSupportFolder } from '../vscode/env'
1414
import { createHash } from '../crypto'
1515
import request from '../request'
16-
import { telemetry } from '../telemetry'
16+
import { lspSetupStage } from '../../amazonq/lsp/util'
1717

1818
export class LanguageServerResolver {
1919
constructor(
@@ -187,13 +187,7 @@ export class LanguageServerResolver {
187187
}
188188
return []
189189
})
190-
const filesToDownload = await telemetry.languageServer_setup.run(async (span) => {
191-
span.record({ languageServerSetupStage: 'validate' })
192-
const startTime = performance.now()
193-
const result = (await Promise.all(verifyTasks)).flat()
194-
span.record({ duration: performance.now() - startTime })
195-
return result
196-
})
190+
const filesToDownload = await lspSetupStage('validate', async () => (await Promise.all(verifyTasks)).flat())
197191

198192
if (filesToDownload.length !== contents.length) {
199193
return false

0 commit comments

Comments
 (0)