Skip to content

Commit 5ff55ca

Browse files
committed
ExtensionPoint impl
1 parent a461559 commit 5ff55ca

File tree

8 files changed

+172
-14
lines changed

8 files changed

+172
-14
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!-- Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
2+
<!-- SPDX-License-Identifier: Apache-2.0 -->
3+
4+
<idea-plugin>
5+
<extensions defaultExtensionNs="com.intellij">
6+
<moduleDependencyProvider
7+
implementation="software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.providers.JavaModuleDependencyProvider"/>
8+
</extensions>
9+
</idea-plugin>

plugins/amazonq/shared/jetbrains-community/resources/META-INF/module-amazonq.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,17 @@
66
<xi:include href="/META-INF/plugin-codetransform.xml" />
77
<xi:include href="/META-INF/plugin-codewhisperer.xml" />
88

9+
<extensionPoints>
10+
<extensionPoint name="moduleDependencyProvider"
11+
interface="software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.ModuleDependencyProvider"
12+
dynamic="true"/>
13+
</extensionPoints>
14+
915
<extensions defaultExtensionNs="com.intellij">
1016
<applicationService serviceImplementation="migration.software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager"/>
1117
</extensions>
18+
19+
<depends optional="true" config-file="java-support.xml">com.intellij.modules.java</depends>
20+
<depends optional="true" config-file="python-support.xml">com.intellij.modules.python</depends>
21+
1222
</idea-plugin>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!-- Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
2+
<!-- SPDX-License-Identifier: Apache-2.0 -->
3+
4+
<idea-plugin>
5+
<extensions defaultExtensionNs="com.intellij">
6+
<moduleDependencyProvider
7+
implementation="software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.providers.PythonModuleDependencyProvider"/>
8+
</extensions>
9+
</idea-plugin>

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/dependencies/DefaultModuleDependenciesService.kt

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.jetbrains.python.packaging.management.PythonPackageManager
1717
import com.jetbrains.python.sdk.PythonSdkUtil
1818
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
1919
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
20+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.ModuleDependencyProvider.Companion.EP_NAME
2021
import java.util.concurrent.CompletableFuture
2122

2223
class DefaultModuleDependenciesService(
@@ -50,21 +51,12 @@ class DefaultModuleDependenciesService(
5051

5152
private fun syncAllModules() {
5253
ModuleManager.getInstance(project).modules.forEach { module ->
53-
val language = getModuleLanguage(module)
54-
val params = when (language) {
55-
"Java" -> createJavaParams(module)
56-
"Python" -> createPythonParams(module)
57-
else -> return
54+
EP_NAME.forEachExtensionSafe {
55+
if (it.isApplicable(module)) {
56+
syncModuleDependencies(it.createParams(module))
57+
return@forEachExtensionSafe
58+
}
5859
}
59-
syncModuleDependencies(params)
60-
}
61-
}
62-
63-
private fun getModuleLanguage(module: Module): String {
64-
return when {
65-
ModuleRootManager.getInstance(module).sdk?.sdkType is JavaSdkType -> "Java"
66-
PythonSdkUtil.findPythonSdk(module) != null -> "Python"
67-
else -> "Unknown"
6860
}
6961
}
7062

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies
5+
6+
import com.intellij.openapi.extensions.ExtensionPointName
7+
import com.intellij.openapi.module.Module
8+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
9+
10+
interface ModuleDependencyProvider {
11+
companion object {
12+
val EP_NAME = ExtensionPointName<ModuleDependencyProvider>("com.intellij.moduleDependencyProvider")
13+
}
14+
15+
fun isApplicable(module: Module): Boolean
16+
fun createParams(module: Module): SyncModuleDependenciesParams
17+
}
18+
19+
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.providers
5+
6+
import com.intellij.openapi.module.Module
7+
import com.intellij.openapi.roots.ModuleRootManager
8+
import com.intellij.openapi.roots.OrderRootType
9+
import com.intellij.openapi.projectRoots.JavaSdkType
10+
import com.intellij.openapi.vfs.VfsUtil
11+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.ModuleDependencyProvider
12+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
13+
14+
class JavaModuleDependencyProvider : ModuleDependencyProvider {
15+
override fun isApplicable(module: Module): Boolean =
16+
ModuleRootManager.getInstance(module).sdk?.sdkType is JavaSdkType
17+
18+
override fun createParams(module: Module): SyncModuleDependenciesParams {
19+
val sourceRoots = getSourceRoots(module)
20+
val dependencies = mutableListOf<String>()
21+
22+
ModuleRootManager.getInstance(module).orderEntries().forEachLibrary { library ->
23+
library.getUrls(OrderRootType.CLASSES).forEach { url ->
24+
dependencies.add(VfsUtil.urlToPath(url))
25+
}
26+
true
27+
}
28+
29+
return SyncModuleDependenciesParams(
30+
moduleName = module.name,
31+
programmingLanguage = "Java",
32+
files = sourceRoots,
33+
dirs = dependencies,
34+
includePatterns = emptyList(),
35+
excludePatterns = emptyList()
36+
)
37+
}
38+
39+
private fun getSourceRoots(module: Module): List<String> {
40+
return ModuleRootManager.getInstance(module).contentEntries
41+
.flatMap { contentEntry ->
42+
contentEntry.sourceFolders
43+
.filter { !it.isTestSource }
44+
.mapNotNull { it.file?.path }
45+
}
46+
}
47+
}
48+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
5+
package software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.providers
6+
7+
import com.intellij.openapi.module.Module
8+
import com.intellij.openapi.roots.ModuleRootManager
9+
import com.jetbrains.python.packaging.management.PythonPackageManager
10+
import com.jetbrains.python.sdk.PythonSdkUtil
11+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.ModuleDependencyProvider
12+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.SyncModuleDependenciesParams
13+
14+
class PythonModuleDependencyProvider : ModuleDependencyProvider {
15+
override fun isApplicable(module: Module): Boolean =
16+
PythonSdkUtil.findPythonSdk(module) != null
17+
18+
override fun createParams(module: Module): SyncModuleDependenciesParams {
19+
val sourceRoots = getSourceRoots(module)
20+
val dependencies = mutableListOf<String>()
21+
22+
PythonSdkUtil.findPythonSdk(module)?.let { sdk ->
23+
val packageManager = PythonPackageManager.forSdk(module.project, sdk)
24+
packageManager.installedPackages.forEach { pkg ->
25+
dependencies.add(pkg.name)
26+
}
27+
}
28+
29+
return SyncModuleDependenciesParams(
30+
moduleName = module.name,
31+
programmingLanguage = "Python",
32+
files = sourceRoots,
33+
dirs = dependencies,
34+
includePatterns = emptyList(),
35+
excludePatterns = emptyList()
36+
)
37+
}
38+
39+
private fun getSourceRoots(module: Module): List<String> {
40+
return ModuleRootManager.getInstance(module).contentEntries
41+
.flatMap { contentEntry ->
42+
contentEntry.sourceFolders
43+
.filter { !it.isTestSource }
44+
.mapNotNull { it.file?.path }
45+
}
46+
}
47+
}
48+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq.lsp.util
5+
6+
import com.intellij.diagnostic.PluginException
7+
import com.intellij.openapi.diagnostic.Logger
8+
import com.intellij.openapi.extensions.ExtensionPointName
9+
10+
val LOG = Logger.getInstance("software.aws.toolkits.jetbrains.services.amazonq.lsp.util.ExtensionPointUtils")
11+
12+
inline fun <T : Any> ExtensionPointName<T>.forEachExtensionSafe(action: (T) -> Unit) {
13+
for (extension in extensionList) {
14+
try {
15+
action(extension)
16+
} catch (e: PluginException) {
17+
LOG.warn("Failed to process extension ${extension::class.java.name}", e)
18+
} catch (e: Exception) {
19+
LOG.warn("Error processing extension ${extension::class.java.name}", e)
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)