@@ -19,22 +19,35 @@ import com.intellij.openapi.util.Disposer
1919import com.intellij.openapi.util.Key
2020import com.intellij.util.io.await
2121import kotlinx.coroutines.CoroutineScope
22+ import kotlinx.coroutines.TimeoutCancellationException
2223import kotlinx.coroutines.launch
24+ import kotlinx.coroutines.time.withTimeout
25+ import org.eclipse.lsp4j.ClientCapabilities
26+ import org.eclipse.lsp4j.ClientInfo
27+ import org.eclipse.lsp4j.FileOperationsWorkspaceCapabilities
2328import org.eclipse.lsp4j.InitializeParams
2429import org.eclipse.lsp4j.InitializedParams
30+ import org.eclipse.lsp4j.SynchronizationCapabilities
31+ import org.eclipse.lsp4j.TextDocumentClientCapabilities
32+ import org.eclipse.lsp4j.WorkspaceClientCapabilities
33+ import org.eclipse.lsp4j.WorkspaceFolder
2534import org.eclipse.lsp4j.jsonrpc.Launcher
2635import org.eclipse.lsp4j.launch.LSPLauncher
2736import org.slf4j.event.Level
2837import software.aws.toolkits.core.utils.getLogger
2938import software.aws.toolkits.core.utils.warn
3039import software.aws.toolkits.jetbrains.isDeveloperMode
40+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.createExtendedClientMetadata
41+ import software.aws.toolkits.jetbrains.services.telemetry.ClientMetadata
3142import java.io.IOException
3243import java.io.OutputStreamWriter
3344import java.io.PipedInputStream
3445import java.io.PipedOutputStream
3546import java.io.PrintWriter
3647import java.io.StringWriter
48+ import java.net.URI
3749import java.nio.charset.StandardCharsets
50+ import java.time.Duration
3851import java.util.concurrent.Future
3952
4053// https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/server/LSPProcessListener.java
@@ -107,6 +120,57 @@ private class AmazonQServerInstance(private val project: Project, private val cs
107120 private val launcherFuture: Future <Void >
108121 private val launcherHandler: KillableProcessHandler
109122
123+ private fun createClientCapabilities (): ClientCapabilities =
124+ ClientCapabilities ().apply {
125+ textDocument = TextDocumentClientCapabilities ().apply {
126+ // For didSaveTextDocument, other textDocument/ messages always mandatory
127+ synchronization = SynchronizationCapabilities ().apply {
128+ didSave = true
129+ }
130+ }
131+
132+ workspace = WorkspaceClientCapabilities ().apply {
133+ applyEdit = false
134+
135+ // For workspace folder changes
136+ workspaceFolders = true
137+
138+ // For file operations (create, delete)
139+ fileOperations = FileOperationsWorkspaceCapabilities ().apply {
140+ didCreate = true
141+ didDelete = true
142+ }
143+ }
144+ }
145+
146+ // needs case handling when project's base path is null: default projects/unit tests
147+ private fun createWorkspaceFolders (): List <WorkspaceFolder > =
148+ project.basePath?.let { basePath ->
149+ listOf (
150+ WorkspaceFolder (
151+ URI (" file://$basePath " ).toString(),
152+ project.name
153+ )
154+ )
155+ }.orEmpty() // no folders to report or workspace not folder based
156+
157+ private fun createClientInfo (): ClientInfo {
158+ val metadata = ClientMetadata .getDefault()
159+ return ClientInfo ().apply {
160+ name = metadata.awsProduct.toString()
161+ version = metadata.awsVersion
162+ }
163+ }
164+
165+ private fun createInitializeParams (): InitializeParams =
166+ InitializeParams ().apply {
167+ processId = ProcessHandle .current().pid().toInt()
168+ capabilities = createClientCapabilities()
169+ clientInfo = createClientInfo()
170+ workspaceFolders = createWorkspaceFolders()
171+ initializationOptions = createExtendedClientMetadata()
172+ }
173+
110174 init {
111175 val cmd = GeneralCommandLine (" amazon-q-lsp" )
112176
@@ -143,18 +207,14 @@ private class AmazonQServerInstance(private val project: Project, private val cs
143207 launcherFuture = launcher.startListening()
144208
145209 cs.launch {
146- val initializeResult = languageServer.initialize(
147- InitializeParams ().apply {
148- // does this work on windows
149- processId = ProcessHandle .current().pid().toInt()
150- // capabilities
151- // client info
152- // trace?
153- // workspace folders?
154- // anything else we need?
210+ val initializeResult = try {
211+ withTimeout(Duration .ofSeconds(10 )) {
212+ languageServer.initialize(createInitializeParams()).await()
155213 }
156- // probably need a timeout
157- ).await()
214+ } catch (_: TimeoutCancellationException ) {
215+ LOG .warn { " LSP initialization timed out" }
216+ null
217+ }
158218
159219 // then if this succeeds then we can allow the client to send requests
160220 if (initializeResult == null ) {
0 commit comments