Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9d71b4c
syncModuleDependencies call barebones
samgst-amazon Feb 26, 2025
1f1c2ac
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Feb 26, 2025
f92ab4d
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Feb 26, 2025
58e3ea2
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Feb 26, 2025
060f64a
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Mar 3, 2025
63eb25c
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Mar 3, 2025
f5f4c87
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Mar 4, 2025
10ddb2d
implement syncModuleDependencies logic
samgst-amazon Feb 27, 2025
44c794e
detekt
samgst-amazon Mar 4, 2025
90d5365
Merge branch 'refs/heads/feature/q-lsp' into samgst/q-lsp-module-depe…
samgst-amazon Mar 5, 2025
9edbfac
return completableFuture
samgst-amazon Mar 5, 2025
b9ba38f
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Mar 5, 2025
a461559
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Mar 5, 2025
5ff55ca
ExtensionPoint impl
samgst-amazon Mar 5, 2025
b2d5cc3
detekt
samgst-amazon Mar 5, 2025
a1c08a5
fix EachExtensionSafe
samgst-amazon Mar 5, 2025
f254b7a
update ExtensionPoint namespace
samgst-amazon Mar 6, 2025
c9d7ab3
private functions not needed
samgst-amazon Mar 6, 2025
7b77a6f
detekt
samgst-amazon Mar 6, 2025
3263ac9
class visibility
samgst-amazon Mar 6, 2025
7e74c9e
cs.launch for the ModuleDependencyServiceHandler
samgst-amazon Mar 6, 2025
e35e956
Tests
samgst-amazon Mar 7, 2025
d14bfe4
Merge branch 'feature/q-lsp' into samgst/q-lsp-module-dependencies
samgst-amazon Mar 7, 2025
2edaba4
update xml
samgst-amazon Mar 7, 2025
6d9eb85
move xml impl to src root
samgst-amazon Mar 7, 2025
db03df1
feedback
samgst-amazon Mar 7, 2025
2fd9ee6
change message to notification instead of Request
samgst-amazon Mar 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ import org.eclipse.lsp4j.jsonrpc.services.JsonNotification
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
import org.eclipse.lsp4j.services.LanguageServer
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.UpdateCredentialsPayload
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
import java.util.concurrent.CompletableFuture

/**
* Remote interface exposed by the Amazon Q language server
*/
@Suppress("unused")
interface AmazonQLanguageServer : LanguageServer {
@JsonRequest("aws/syncModuleDependencies")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you see if @JsonNotification works

fun syncModuleDependencies(params: SyncModuleDependenciesParams): CompletableFuture<Unit>

@JsonRequest("aws/credentials/token/update")
fun updateTokenCredentials(payload: UpdateCredentialsPayload): CompletableFuture<ResponseMessage>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import software.aws.toolkits.core.utils.info
import software.aws.toolkits.core.utils.warn
import software.aws.toolkits.jetbrains.isDeveloperMode
import software.aws.toolkits.jetbrains.services.amazonq.lsp.auth.DefaultAuthCredentialsService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.DefaultModuleDependenciesService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.createExtendedClientMetadata
import software.aws.toolkits.jetbrains.services.amazonq.lsp.textdocument.TextDocumentServiceHandler
Expand Down Expand Up @@ -301,6 +302,7 @@ private class AmazonQServerInstance(private val project: Project, private val cs
}

DefaultAuthCredentialsService(project, encryptionManager, this)
DefaultModuleDependenciesService(project, this)
TextDocumentServiceHandler(project, this)
WorkspaceServiceHandler(project, this)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies

import com.intellij.openapi.Disposable
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdkType
import com.intellij.openapi.roots.ModuleRootEvent
import com.intellij.openapi.roots.ModuleRootListener
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.vfs.VfsUtil
import com.jetbrains.python.packaging.management.PythonPackageManager
import com.jetbrains.python.sdk.PythonSdkUtil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this service we should define a generic interface that is registered with the extension point system and register them dynamically through optional depends. otherwise this will all fail if user is missing the java/python plugin

import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
import java.util.concurrent.CompletableFuture

class DefaultModuleDependenciesService(
private val project: Project,
serverInstance: Disposable,
) : ModuleDependenciesService,
ModuleRootListener {

init {
project.messageBus.connect(serverInstance).subscribe(
ModuleRootListener.TOPIC,
this
)
// project initiation with initial list of dependencies
syncAllModules()
}

override fun rootsChanged(event: ModuleRootEvent) {
if (event.isCausedByFileTypesChange) return
// call on change with updated dependencies
syncAllModules()
}

override fun syncModuleDependencies(params: SyncModuleDependenciesParams): CompletableFuture<Unit> =
CompletableFuture<Unit>().also { completableFuture ->
AmazonQLspService.executeIfRunning(project) { languageServer ->
languageServer.syncModuleDependencies(params)
completableFuture.complete(null)
} ?: completableFuture.completeExceptionally(IllegalStateException("LSP Server not running"))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplifies to

Suggested change
CompletableFuture<Unit>().also { completableFuture ->
AmazonQLspService.executeIfRunning(project) { languageServer ->
languageServer.syncModuleDependencies(params)
completableFuture.complete(null)
} ?: completableFuture.completeExceptionally(IllegalStateException("LSP Server not running"))
}
AmazonQLspService.executeIfRunning(project) { languageServer ->
languageServer.syncModuleDependencies(params)
}?.toCompletableFuture() ?: CompletableFuture.failedFuture(IllegalStateException("LSP Server not running"))


private fun syncAllModules() {
ModuleManager.getInstance(project).modules.forEach { module ->
val language = getModuleLanguage(module)
val params = when (language) {
"Java" -> createJavaParams(module)
"Python" -> createPythonParams(module)
else -> return
}
syncModuleDependencies(params)
}
}

private fun getModuleLanguage(module: Module): String {
return when {
ModuleRootManager.getInstance(module).sdk?.sdkType is JavaSdkType -> "Java"
PythonSdkUtil.findPythonSdk(module) != null -> "Python"
else -> "Unknown"
}
}

private fun getSourceRoots(module: Module): List<String> {
val sourceRoots = mutableListOf<String>()

// Get all source roots from content entries
ModuleRootManager.getInstance(module).contentEntries
.flatMap { contentEntry ->
contentEntry.sourceFolders
.filter { !it.isTestSource }
.mapNotNull { it.file?.path }
}
.forEach { path -> sourceRoots.add(path) }

return sourceRoots
}

private fun createJavaParams(module: Module): SyncModuleDependenciesParams {
val sourceRoots = getSourceRoots(module)
val dependencies = mutableListOf<String>()

// Get library dependencies
ModuleRootManager.getInstance(module).orderEntries().forEachLibrary { library ->
library.getUrls(OrderRootType.CLASSES).forEach { url ->
dependencies.add(VfsUtil.urlToPath(url))
}
true
}

return SyncModuleDependenciesParams(
moduleName = module.name,
programmingLanguage = "Java",
files = sourceRoots,
dirs = dependencies,
includePatterns = emptyList(),
excludePatterns = emptyList()
)
}

private fun createPythonParams(module: Module): SyncModuleDependenciesParams {
val sourceRoots = getSourceRoots(module)
val dependencies = mutableListOf<String>()

// Get Python packages
PythonSdkUtil.findPythonSdk(module)?.let { sdk ->
val packageManager = PythonPackageManager.forSdk(module.project, sdk)

Check warning on line 114 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/dependencies/DefaultModuleDependenciesService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.jetbrains.python.packaging.management.PythonPackageManager.Companion' is declared in unstable 'com.jetbrains.python.packaging.management.PythonPackageManager' marked with @ApiStatus.Experimental

Check warning on line 114 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/dependencies/DefaultModuleDependenciesService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'forSdk(com.intellij.openapi.project.Project, com.intellij.openapi.projectRoots.Sdk)' is declared in unstable 'com.jetbrains.python.packaging.management.PythonPackageManager' marked with @ApiStatus.Experimental
packageManager.installedPackages.forEach { pkg ->

Check warning on line 115 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/dependencies/DefaultModuleDependenciesService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'getInstalledPackages()' is declared in unstable 'com.jetbrains.python.packaging.management.PythonPackageManager' marked with @ApiStatus.Experimental
dependencies.add(pkg.name)
}
}

return SyncModuleDependenciesParams(
moduleName = module.name,
programmingLanguage = "Python",
files = sourceRoots,
dirs = dependencies,
includePatterns = emptyList(),
excludePatterns = emptyList()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies

import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
import java.util.concurrent.CompletableFuture

interface ModuleDependenciesService {
fun syncModuleDependencies(params: SyncModuleDependenciesParams): CompletableFuture<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies

public class SyncModuleDependenciesParams(

Check warning on line 6 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/dependencies/SyncModuleDependenciesParams.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant visibility modifier

Redundant visibility modifier
val moduleName: String,

Check warning on line 7 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/dependencies/SyncModuleDependenciesParams.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Property "moduleName" is never used

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Property "moduleName" is never used
val programmingLanguage: String,
val files: List<String>,
val dirs: List<String>,

Check warning on line 10 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/dependencies/SyncModuleDependenciesParams.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Property "dirs" is never used

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Property "dirs" is never used
val includePatterns: List<String>,

Check warning on line 11 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/dependencies/SyncModuleDependenciesParams.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Property "includePatterns" is never used

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Property "includePatterns" is never used
val excludePatterns: List<String>,

Check warning on line 12 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/dependencies/SyncModuleDependenciesParams.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Property "excludePatterns" is never used

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Property "excludePatterns" is never used
)
Loading