diff --git a/build.gradle.kts b/build.gradle.kts index 07478d372..36639377a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { testFixturesImplementation(libs.kotest) intellijPlatform { - intellijIdeaCommunity(Platform.version) + intellijIdeaUltimate(Platform.version) plugins(Platform.plugins) bundledPlugins(Platform.bundledPlugins) zipSigner() diff --git a/buildSrc/src/main/kotlin/versions.kt b/buildSrc/src/main/kotlin/versions.kt index e93147952..6dc4074a7 100644 --- a/buildSrc/src/main/kotlin/versions.kt +++ b/buildSrc/src/main/kotlin/versions.kt @@ -17,7 +17,7 @@ object Platform { // Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html // Example: platformPlugins =" com.intellij.java, com.jetbrains.php:203.4449.22" val plugins = - listOf("PythonCore:241.15989.150", "org.jetbrains.android:241.15989.150") + listOf("PythonCore:241.15989.150", "org.jetbrains.android:241.15989.150", "org.jetbrains.plugins.go:241.15989.21") val bundledPlugins = listOf("com.intellij.java", "org.jetbrains.kotlin") } diff --git a/protocol/src/main/kotlin/org/jetbrains/bsp/GoBuildTarget.kt b/protocol/src/main/kotlin/org/jetbrains/bsp/GoBuildTarget.kt new file mode 100644 index 000000000..caac41510 --- /dev/null +++ b/protocol/src/main/kotlin/org/jetbrains/bsp/GoBuildTarget.kt @@ -0,0 +1,8 @@ +package org.jetbrains.bsp + +import java.net.URI + +public data class GoBuildTarget( + val sdkHomePath: URI?, + val importPath: String, +) diff --git a/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/WorkspaceLibraries.kt b/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/WorkspaceLibraries.kt index 5096bdacd..ccc45e0b8 100644 --- a/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/WorkspaceLibraries.kt +++ b/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/WorkspaceLibraries.kt @@ -1,6 +1,7 @@ package org.jetbrains.bsp.protocol import ch.epfl.scala.bsp4j.BuildTargetIdentifier +import java.net.URI public data class LibraryItem( val id: BuildTargetIdentifier, @@ -8,7 +9,9 @@ public data class LibraryItem( val ijars: List, val jars: List, val sourceJars: List, -) + val goImportPath: String? = "", + val goRoot: URI? = URI(""), + ) public data class WorkspaceLibrariesResult( val libraries: List, diff --git a/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/utils/Extractors.kt b/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/utils/Extractors.kt index e83cabd8e..f15540d7e 100644 --- a/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/utils/Extractors.kt +++ b/protocol/src/main/kotlin/org/jetbrains/bsp/protocol/utils/Extractors.kt @@ -7,6 +7,7 @@ import ch.epfl.scala.bsp4j.PythonBuildTarget import ch.epfl.scala.bsp4j.ScalaBuildTarget import com.google.gson.Gson import com.google.gson.JsonObject +import org.jetbrains.bsp.GoBuildTarget import org.jetbrains.bsp.protocol.AndroidBuildTarget import org.jetbrains.bsp.protocol.KotlinBuildTarget @@ -32,6 +33,9 @@ public fun extractKotlinBuildTarget(target: BuildTarget): KotlinBuildTarget? = extractData(target, "kotlin") ?: extractAndroidBuildTarget(target)?.kotlinBuildTarget +public fun extractGoBuildTarget(target: BuildTarget): GoBuildTarget? = + extractData(target, "go") + public fun extractJvmBuildTarget(target: BuildTarget): JvmBuildTarget? = extractData(target, BuildTargetDataKind.JVM) ?: extractAndroidBuildTarget(target)?.jvmBuildTarget diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/config/BspFeatureFlags.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/config/BspFeatureFlags.kt index bbbe2d8a1..82061c039 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/config/BspFeatureFlags.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/config/BspFeatureFlags.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.util.registry.Registry private const val PYTHON_SUPPORT = "bsp.python.support" private const val SCALA_SUPPORT = "bsp.scala.support" private const val ANDROID_SUPPORT = "bsp.android.support" +private const val GO_SUPPORT = "bsp.go.support" private const val BUILD_PROJECT_ON_SYNC = "bsp.build.project.on.sync" private const val SHORTEN_MODULE_LIBRARY_NAMES = "bsp.shorten.module.library.names" @@ -18,6 +19,9 @@ public object BspFeatureFlags { public val isAndroidSupportEnabled: Boolean get() = Registry.`is`(ANDROID_SUPPORT) + public val isGoSupportEnabled: Boolean + get() = Registry.`is`(GO_SUPPORT) + public val isBuildProjectOnSyncEnabled: Boolean get() = Registry.`is`(BUILD_PROJECT_ON_SYNC) diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/extension/points/GoSdkGetterExtension.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/extension/points/GoSdkGetterExtension.kt new file mode 100644 index 000000000..743e2db87 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/extension/points/GoSdkGetterExtension.kt @@ -0,0 +1,85 @@ +package org.jetbrains.plugins.bsp.extension.points + +import ch.epfl.scala.bsp4j.BuildTarget +import com.goide.project.GoModuleSettings +import com.goide.sdk.GoSdk +import com.goide.sdk.GoSdkService +import com.goide.vgo.project.workspaceModel.VgoWorkspaceModelUpdater +import com.intellij.openapi.application.writeAction +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import org.jetbrains.bsp.protocol.utils.extractGoBuildTarget +import org.jetbrains.plugins.bsp.magicmetamodel.ProjectDetails + +public interface GoSdkGetterExtension { + public suspend fun addGoSdks( + project: Project, + ) + + public fun calculateAllGoSdkInfos( + projectDetails: ProjectDetails, + ) + + public fun enableGoSupportForModule( + module: Module, + ) + + public fun restoreGoModulesRegistry( + project: Project, + ) +} + +private val ep = ExtensionPointName.create( + "org.jetbrains.bsp.goSdkGetterExtension", +) + +public fun goSdkExtension(): GoSdkGetterExtension? = ep.extensionList.firstOrNull() + +public fun goSdkExtensionExists(): Boolean = ep.extensionList.isNotEmpty() + +public class GoSdkGetter: GoSdkGetterExtension { + private var goSdks: Set = emptySet() + + override suspend fun addGoSdks( + project: Project, + ) { + val goSdkService = GoSdkService.getInstance(project) + goSdks.forEach { + writeAction { + goSdkService.setSdk(it) + } + } + } + + override fun calculateAllGoSdkInfos( + projectDetails: ProjectDetails, + ) { + goSdks = projectDetails.targets + .mapNotNull { + createGoSdk(it) + } + .toSet() + } + + override fun enableGoSupportForModule( + module: Module, + ) { + GoModuleSettings.getInstance(module).isGoSupportEnabled = true + } + + override fun restoreGoModulesRegistry( + project: Project, + ) { + VgoWorkspaceModelUpdater(project).restoreModulesRegistry() + } + + private fun createGoSdk(target: BuildTarget): GoSdk? = + extractGoBuildTarget(target)?.let { + if (it.sdkHomePath == null) { + GoSdk.NULL + } else { + GoSdk.fromHomePath(it.sdkHomePath?.path) + } + } +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/DefaultMagicMetaModelState.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/DefaultMagicMetaModelState.kt index 2eb2c7f87..2986429ca 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/DefaultMagicMetaModelState.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/DefaultMagicMetaModelState.kt @@ -7,6 +7,9 @@ import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.BuildTargetI import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ContentRoot import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GenericModuleInfo import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GenericSourceRoot +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoAddendum +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModule +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModuleDependency import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.IntermediateLibraryDependency import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.IntermediateModuleDependency import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.JavaAddendum @@ -199,8 +202,9 @@ public data class ModuleState( var scalaAddendum: ScalaAddendumState? = null, var javaAddendum: JavaAddendumState? = null, var androidAddendum: AndroidAddendumState? = null, + var goAddendum: GoAddendumState? = null, ) : ConvertableFromState { - public fun toJavaModule(): JavaModule = JavaModule( + private fun toJavaModule(): JavaModule = JavaModule( genericModuleInfo = module.fromState(), baseDirContentRoot = baseDirContentRoot?.fromState(), sourceRoots = sourceRoots.map { it.toJavaSourceRoot() }, @@ -213,7 +217,7 @@ public data class ModuleState( androidAddendum = androidAddendum?.fromState(), ) - public fun toPythonModule(): PythonModule = PythonModule( + private fun toPythonModule(): PythonModule = PythonModule( module = module.fromState(), sourceRoots = sourceRoots.map { it.toGenericSourceRoot() }, libraries = libraries?.map { it.toPythonLibrary() }.orEmpty(), @@ -221,9 +225,21 @@ public data class ModuleState( sdkInfo = sdkInfo?.fromState(), ) + private fun toGoModule(): GoModule = + GoModule( + module = module.fromState(), + importPath = goAddendum?.importPath ?: "", + root = Path(goAddendum?.root ?: ""), + sourceRoots = sourceRoots.map { it.toGenericSourceRoot() }, + resourceRoots = resourceRoots.map { it.toResourceRoot() }, + goDependencies = goAddendum?.goDependencies?.map { it.fromState() }.orEmpty() + ) + override fun fromState(): Module = if (module.languageIds.includesPython()) toPythonModule() + else if (module.languageIds.contains("go")) + toGoModule() else toJavaModule() } @@ -290,6 +306,28 @@ public data class AndroidAddendumState( ) } +public data class GoAddendumState( + var importPath: String = "", + var root: String = "", + var goDependencies: List = emptyList(), +) : ConvertableFromState { + override fun fromState(): GoAddendum = GoAddendum( + importPath = importPath, + root = Path(root), + goDependencies = goDependencies.map { it.fromState() }, + ) +} + +public data class GoModuleDependencyState( + var importPath: String = "", + var root: String = "", +) : ConvertableFromState { + override fun fromState(): GoModuleDependency = GoModuleDependency( + importPath = importPath, + root = Path(root), + ) +} + public data class ModuleCapabilitiesState( var canRun: Boolean = false, var canTest: Boolean = false, @@ -323,6 +361,17 @@ public fun AndroidAddendum.toState(): AndroidAddendumState = AndroidAddendumStat assetsDirectories = assetsDirectories.map { it.toString() }, ) +public fun GoAddendum.toState(): GoAddendumState = GoAddendumState( + importPath = importPath, + root = root.toString(), + goDependencies = goDependencies.map { it.toState() }, +) + +public fun GoModuleDependency.toState(): GoModuleDependencyState = GoModuleDependencyState( + importPath = importPath, + root = root.toString(), +) + public fun ModuleCapabilities.toState(): ModuleCapabilitiesState = ModuleCapabilitiesState( canRun = canRun, canTest = canTest, diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/TargetIdToModuleEntitiesMap.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/TargetIdToModuleEntitiesMap.kt index 6b1acb8c2..d01408dc7 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/TargetIdToModuleEntitiesMap.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/TargetIdToModuleEntitiesMap.kt @@ -7,13 +7,12 @@ import kotlinx.coroutines.runBlocking import org.jetbrains.annotations.TestOnly import org.jetbrains.plugins.bsp.magicmetamodel.ProjectDetails import org.jetbrains.plugins.bsp.magicmetamodel.TargetNameReformatProvider -import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.BuildTargetId -import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.BuildTargetInfo -import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.Module +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.* import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers.ModuleDetailsToJavaModuleTransformer +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers.ModuleDetailsToGoModuleTransformer import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers.ModuleDetailsToPythonModuleTransformer import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers.ProjectDetailsToModuleDetailsTransformer -import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.includesPython +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.includesGo import java.nio.file.Path public object TargetIdToModuleEntitiesMap { @@ -40,6 +39,13 @@ public object TargetIdToModuleEntitiesMap { libraryNameProvider, hasDefaultPythonInterpreter, ) + val moduleDetailsToGoModuleTransformer = ModuleDetailsToGoModuleTransformer( + targetsMap, + projectDetails, + moduleNameProvider, + libraryNameProvider, + projectBasePath, + ) return runBlocking(Dispatchers.Default) { projectDetails.targetsId.map { @@ -47,6 +53,8 @@ public object TargetIdToModuleEntitiesMap { val moduleDetails = transformer.moduleDetailsForTargetId(it) val module = if (moduleDetails.target.languageIds.includesPython()) { moduleDetailsToPythonModuleTransformer.transform(moduleDetails) + } else if (moduleDetails.target.languageIds.includesGo()) { + moduleDetailsToGoModuleTransformer.transform(moduleDetails) } else { moduleDetailsToJavaModuleTransformer.transform(moduleDetails) } diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/GoWorkspaceModelEntities.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/GoWorkspaceModelEntities.kt new file mode 100644 index 000000000..a5167faa0 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/GoWorkspaceModelEntities.kt @@ -0,0 +1,36 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel + +import org.jetbrains.bsp.protocol.LibraryItem +import org.jetbrains.plugins.bsp.magicmetamodel.impl.ModuleState +import org.jetbrains.plugins.bsp.magicmetamodel.impl.toState +import java.nio.file.Path + +public data class GoModuleDependency( + val importPath: String, + val root: Path, +) + +public data class GoModule( + val module: GenericModuleInfo, + val sourceRoots: List, + val resourceRoots: List, + val importPath: String, + val root: Path, + val goDependencies: List, + val goLibraries: List = emptyList(), +) : WorkspaceModelEntity(), Module { + override fun toState(): ModuleState = ModuleState( + module = module.toState(), + sourceRoots = sourceRoots.map { it.toState() }, + resourceRoots = resourceRoots.map { it.toState() }, + goAddendum = GoAddendum(importPath, root, goDependencies).toState(), + ) + + override fun getModuleName(): String = module.name +} + +public data class GoAddendum( + var importPath: String, + var root: Path, + val goDependencies: List, +) diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntities.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntities.kt index 09f8ea313..3dd2b2809 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntities.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntities.kt @@ -4,6 +4,7 @@ import ch.epfl.scala.bsp4j.BuildTarget import ch.epfl.scala.bsp4j.BuildTargetCapabilities import org.jetbrains.plugins.bsp.magicmetamodel.impl.ModuleState import org.jetbrains.plugins.bsp.utils.safeCastToURI +import java.net.URI import java.nio.file.Path public data class BuildTargetInfo( @@ -53,7 +54,9 @@ public data class Library( val iJars: List = listOf(), val sourceJars: List = listOf(), val classJars: List = listOf(), -) : WorkspaceModelEntity(), ResourceRootEntity { + val goImportPath: String? = "", + val goRoot: URI? = URI(""), + ) : WorkspaceModelEntity(), ResourceRootEntity { public companion object { public fun formatJarString(jar: String): String = if (jar.endsWith(".jar")) { diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntitiesExtensions.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntitiesExtensions.kt index 11d21cd54..b8ca4d1d1 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntitiesExtensions.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelEntitiesExtensions.kt @@ -11,6 +11,7 @@ public fun LanguageIds.includesKotlin(): Boolean = contains("kotlin") public fun LanguageIds.includesJava(): Boolean = contains("java") public fun LanguageIds.includesScala(): Boolean = contains("scala") public fun LanguageIds.includesAndroid(): Boolean = contains("android") +public fun LanguageIds.includesGo(): Boolean = contains("go") public fun LanguageIds.includesJavaOrScala(): Boolean = includesJava() || includesScala() public fun LanguageIds.isJvmTarget(): Boolean = diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelUpdater.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelUpdater.kt index 3243eece5..a02f0e168 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelUpdater.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/WorkspaceModelUpdater.kt @@ -12,6 +12,7 @@ import com.intellij.platform.workspace.storage.MutableEntityStorage import com.intellij.platform.workspace.storage.url.VirtualFileUrl import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager import org.jetbrains.bsp.protocol.JvmBinaryJarsItem +import org.jetbrains.bsp.protocol.LibraryItem import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.WorkspaceModelUpdaterImpl import java.nio.file.Path @@ -28,6 +29,7 @@ public data class ModuleDetails( val moduleDependencies: List, val defaultJdkName: String?, val jvmBinaryJars: List, + val goLibraries: List? ) internal data class ModuleName( diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/WorkspaceModelUpdaterImpl.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/WorkspaceModelUpdaterImpl.kt index dbf5c2b8d..b3967d25b 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/WorkspaceModelUpdaterImpl.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/WorkspaceModelUpdaterImpl.kt @@ -6,12 +6,14 @@ import com.intellij.platform.workspace.storage.MutableEntityStorage import com.intellij.platform.workspace.storage.impl.url.toVirtualFileUrl import com.intellij.platform.workspace.storage.url.VirtualFileUrl import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModule import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.JavaModule import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.Library import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.Module import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ModuleName import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.PythonModule import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.WorkspaceModelUpdater +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.GoModuleUpdater import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.JavaModuleUpdater import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.LibraryEntityUpdater import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.PythonModuleUpdater @@ -39,6 +41,7 @@ internal class WorkspaceModelUpdaterImpl( private val javaModuleUpdater = JavaModuleUpdater(workspaceModelEntityUpdaterConfig, projectBasePath, isAndroidSupportEnabled) private val pythonModuleUpdater = PythonModuleUpdater(workspaceModelEntityUpdaterConfig, isPythonSupportEnabled) + private val goModuleUpdater = GoModuleUpdater(workspaceModelEntityUpdaterConfig) private val workspaceModuleRemover = WorkspaceModuleRemover(workspaceModelEntityUpdaterConfig) private val javaModuleToDummyJavaModulesTransformerHACK = @@ -52,6 +55,7 @@ internal class WorkspaceModelUpdaterImpl( javaModuleUpdater.addEntity(module) } is PythonModule -> pythonModuleUpdater.addEntity(module) + is GoModule -> goModuleUpdater.addEntity(module) } } diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoEntitiesExtension.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoEntitiesExtension.kt new file mode 100644 index 000000000..ef42e7a36 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoEntitiesExtension.kt @@ -0,0 +1,79 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters + +import com.goide.vgo.project.workspaceModel.entities.VgoDependencyEntity +import com.goide.vgo.project.workspaceModel.entities.VgoStandaloneModuleEntity +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.platform.workspace.jps.entities.ModuleEntity +import com.intellij.platform.workspace.storage.WorkspaceEntity +import com.intellij.platform.workspace.storage.impl.url.toVirtualFileUrl +import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModule +import org.jetbrains.workspacemodel.entities.BspEntitySource +import kotlin.io.path.toPath + +public interface GoEntitiesExtension { + public fun prepareAllEntitiesForGoModule( + entityToAdd: GoModule, + goModule: ModuleEntity, + virtualFileUrlManager: VirtualFileUrlManager, + ): GoModuleEntities +} + +public data class GoModuleEntities( + val goModuleWorkspaceEntity: WorkspaceEntity, + val goDependenciesWorkspaceEntity: List, + val goLibrariesWorkspaceEntity: List, +) + +private val ep = ExtensionPointName.create( + "org.jetbrains.bsp.goEntitiesExtension", +) + +public fun goEntitiesExtension(): GoEntitiesExtension? = ep.extensionList.firstOrNull() + +public fun goEntitiesExtensionExists(): Boolean = ep.extensionList.isNotEmpty() + +public class GoEntitiesExtensionImpl: GoEntitiesExtension { + override fun prepareAllEntitiesForGoModule( + entityToAdd: GoModule, + goModule: ModuleEntity, + virtualFileUrlManager: VirtualFileUrlManager, + ): GoModuleEntities { + val vgoModule = VgoStandaloneModuleEntity( + moduleId = goModule.symbolicId, + entitySource = BspEntitySource, + importPath = entityToAdd.importPath, + root = entityToAdd.root.toVirtualFileUrl(virtualFileUrlManager), + ) + + val vgoModuleDependencies = entityToAdd.goDependencies.map { + VgoDependencyEntity( + importPath = it.importPath, + entitySource = BspEntitySource, + isMainModule = false, + internal = true, + ) { + this.module = vgoModule + this.root = it.root.toVirtualFileUrl(virtualFileUrlManager) + } + } + + val vgoModuleLibraries = entityToAdd.goLibraries.map { + VgoDependencyEntity( + importPath = it.goImportPath ?: "", + entitySource = BspEntitySource, + isMainModule = false, + internal = false, + ) { + this.module = vgoModule + this.root = it.goRoot?.toPath()?.toVirtualFileUrl(virtualFileUrlManager) + } + } + + return GoModuleEntities( + goModuleWorkspaceEntity = vgoModule, + goDependenciesWorkspaceEntity = vgoModuleDependencies, + goLibrariesWorkspaceEntity = vgoModuleLibraries, + ) + } +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoModuleUpdater.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoModuleUpdater.kt new file mode 100644 index 000000000..b92158f92 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoModuleUpdater.kt @@ -0,0 +1,40 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters + +import com.intellij.platform.workspace.storage.WorkspaceEntity +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModule + +internal class GoModuleUpdater( + private val workspaceModelEntityUpdaterConfig: WorkspaceModelEntityUpdaterConfig, +) : WorkspaceModelEntityWithoutParentModuleUpdater { + override fun addEntity(entityToAdd: GoModule): WorkspaceEntity { + val moduleEntityUpdater = ModuleEntityUpdater(workspaceModelEntityUpdaterConfig) + val moduleEntity = moduleEntityUpdater.addEntity(entityToAdd.module) + + val sourceEntityUpdater = SourceEntityUpdater(workspaceModelEntityUpdaterConfig) + sourceEntityUpdater.addEntries(entityToAdd.sourceRoots, moduleEntity) + + val goResourceEntityUpdater = GoResourceEntityUpdater(workspaceModelEntityUpdaterConfig) + goResourceEntityUpdater.addEntries(entityToAdd.resourceRoots, moduleEntity) + + if (!goEntitiesExtensionExists()) { + error("Go entities extension does not exist.") + } + val goEntitiesExtension = goEntitiesExtension()!! + + val goModuleEntities = goEntitiesExtension.prepareAllEntitiesForGoModule( + entityToAdd, + moduleEntity, + workspaceModelEntityUpdaterConfig.virtualFileUrlManager, + ) + + goModuleEntities.goDependenciesWorkspaceEntity.forEach { + workspaceModelEntityUpdaterConfig.workspaceEntityStorageBuilder.addEntity(it) + } + + goModuleEntities.goLibrariesWorkspaceEntity.forEach { + workspaceModelEntityUpdaterConfig.workspaceEntityStorageBuilder.addEntity(it) + } + + return goModuleEntities.goModuleWorkspaceEntity + } +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoResourceEntityUpdater.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoResourceEntityUpdater.kt new file mode 100644 index 000000000..803525170 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoResourceEntityUpdater.kt @@ -0,0 +1,55 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters + +import com.intellij.platform.workspace.jps.entities.ContentRootEntity +import com.intellij.platform.workspace.jps.entities.ModuleEntity +import com.intellij.platform.workspace.jps.entities.SourceRootEntity +import com.intellij.platform.workspace.storage.MutableEntityStorage +import com.intellij.platform.workspace.storage.impl.url.toVirtualFileUrl +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ContentRoot +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ResourceRoot + +internal class GoResourceEntityUpdater( + private val workspaceModelEntityUpdaterConfig: WorkspaceModelEntityUpdaterConfig, +) : WorkspaceModelEntityWithParentModuleUpdater { + private val contentRootEntityUpdater = ContentRootEntityUpdater(workspaceModelEntityUpdaterConfig) + + override fun addEntity(entityToAdd: ResourceRoot, parentModuleEntity: ModuleEntity): SourceRootEntity { + val contentRootEntity = addContentRootEntity(entityToAdd, parentModuleEntity) + + return addSourceRootEntity( + workspaceModelEntityUpdaterConfig.workspaceEntityStorageBuilder, + contentRootEntity, + entityToAdd, + ) + } + + private fun addContentRootEntity( + entityToAdd: ResourceRoot, + parentModuleEntity: ModuleEntity, + ): ContentRootEntity { + val contentRoot = ContentRoot( + path = entityToAdd.resourcePath, + ) + + return contentRootEntityUpdater.addEntity(contentRoot, parentModuleEntity) + } + + private fun addSourceRootEntity( + builder: MutableEntityStorage, + contentRootEntity: ContentRootEntity, + entityToAdd: ResourceRoot, + ): SourceRootEntity = + builder.addEntity( + SourceRootEntity( + url = entityToAdd.resourcePath.toVirtualFileUrl(workspaceModelEntityUpdaterConfig.virtualFileUrlManager), + rootType = ROOT_TYPE, + entitySource = contentRootEntity.entitySource, + ) { + this.contentRoot = contentRootEntity + }, + ) + + private companion object { + private const val ROOT_TYPE = "go-resource" + } +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToGoModuleTransformer.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToGoModuleTransformer.kt new file mode 100644 index 000000000..c6d02f44d --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToGoModuleTransformer.kt @@ -0,0 +1,80 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers + +import ch.epfl.scala.bsp4j.BuildTarget +import org.jetbrains.bsp.protocol.utils.extractGoBuildTarget +import org.jetbrains.plugins.bsp.magicmetamodel.TargetNameReformatProvider +import org.jetbrains.plugins.bsp.magicmetamodel.ProjectDetails +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.BuildTargetId +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.BuildTargetInfo +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GenericModuleInfo +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModule +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GoModuleDependency +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ModuleDetails +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.toBsp4JTargetIdentifier +import java.net.URI +import java.nio.file.Path +import kotlin.io.path.toPath + +internal class ModuleDetailsToGoModuleTransformer( + private val targetsMap: Map, + private val projectDetails: ProjectDetails, + moduleNameProvider: TargetNameReformatProvider, + libraryNameProvider: TargetNameReformatProvider, + projectBasePath: Path, +) : ModuleDetailsToModuleTransformer(targetsMap, moduleNameProvider, libraryNameProvider) { + override val type = "WEB_MODULE" + + private val sourcesItemToGoSourceRootTransformer = SourcesItemToGoSourceRootTransformer(projectBasePath) + private val resourcesItemToGoResourceRootTransformer = + ResourcesItemToGoResourceRootTransformer(projectBasePath) + + override fun transform(inputEntity: ModuleDetails): GoModule { + val goBuildInfo = extractGoBuildTarget(inputEntity.target) + + return GoModule( + module = toGenericModuleInfo(inputEntity), + sourceRoots = sourcesItemToGoSourceRootTransformer.transform(inputEntity.sources.map { + BuildTargetAndSourceItem( + inputEntity.target, + it, + ) + }), + resourceRoots = resourcesItemToGoResourceRootTransformer.transform(inputEntity.resources), + importPath = goBuildInfo?.importPath ?: "", + root = URI.create(inputEntity.target.baseDirectory).toPath(), + goDependencies = toGoDependencies(inputEntity), + goLibraries = inputEntity.goLibraries ?: emptyList(), + ) + } + + override fun toGenericModuleInfo(inputEntity: ModuleDetails): GenericModuleInfo { + val bspModuleDetails = BspModuleDetails( + target = inputEntity.target, + dependencySources = inputEntity.dependenciesSources, + type = type, + javacOptions = null, + pythonOptions = inputEntity.pythonOptions, + libraryDependencies = inputEntity.libraryDependencies, + moduleDependencies = inputEntity.moduleDependencies, + scalacOptions = inputEntity.scalacOptions, + ) + return bspModuleDetailsToModuleTransformer.transform(bspModuleDetails) + } + + private fun toGoDependencies(inputEntity: ModuleDetails): List = + inputEntity.moduleDependencies + .asSequence() + .mapNotNull { targetsMap[it] } + .map { it.id.toBsp4JTargetIdentifier() } + .mapNotNull { buildTargetIdentifier -> projectDetails.targets.find { it.id == buildTargetIdentifier } } + .mapNotNull { buildTargetToGoModuleDependency(it) } + .toList() + + private fun buildTargetToGoModuleDependency(buildTarget: BuildTarget): GoModuleDependency? = + extractGoBuildTarget(buildTarget)?.let { + GoModuleDependency( + importPath = it.importPath, + root = URI.create(buildTarget.baseDirectory).toPath() + ) + } +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformer.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformer.kt index 7b1d080bf..ad96cabf7 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformer.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformer.kt @@ -35,6 +35,7 @@ public class ProjectDetailsToModuleDetailsTransformer( moduleDependencies = allDependencies.targetDependencies.map { it.uri }, defaultJdkName = projectDetails.defaultJdkName, jvmBinaryJars = jvmBinaryJarsIndex[targetId].orEmpty(), + goLibraries = projectDetails.libraries.orEmpty() ) } } diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ResourcesItemToGoResourceRootTransformer.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ResourcesItemToGoResourceRootTransformer.kt new file mode 100644 index 000000000..da97beeb6 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ResourcesItemToGoResourceRootTransformer.kt @@ -0,0 +1,19 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers + +import ch.epfl.scala.bsp4j.ResourcesItem +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ResourceRoot +import java.nio.file.Path + +internal class ResourcesItemToGoResourceRootTransformer(private val projectBasePath: Path) : + WorkspaceModelEntityPartitionTransformer { + override fun transform(inputEntity: ResourcesItem): List = + inputEntity.resources + .map(this::toResourceRoot) + .distinct() + + private fun toResourceRoot(resourcePath: String) = + ResourceRoot( + resourcePath = RawUriToDirectoryPathTransformer.transform(resourcePath), + rootType = "", + ) +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/SourcesItemToGoSourceRootTransformer.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/SourcesItemToGoSourceRootTransformer.kt new file mode 100644 index 000000000..9e765efb8 --- /dev/null +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/SourcesItemToGoSourceRootTransformer.kt @@ -0,0 +1,44 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters.transformers + +import ch.epfl.scala.bsp4j.BuildTarget +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.GenericSourceRoot +import java.nio.file.Path + +internal class SourcesItemToGoSourceRootTransformer(private val projectBasePath: Path) : + WorkspaceModelEntityPartitionTransformer { + private val sourceRootType = "go-source" + private val testSourceRootType = "go-test" + + override fun transform(inputEntities: List): List { + val allSourceRoots = super.transform(inputEntities) + + return allSourceRoots.filter { isNotAChildOfAnySourceDir(it, allSourceRoots) } + } + + private fun isNotAChildOfAnySourceDir( + sourceRoot: GenericSourceRoot, + allSourceRoots: List, + ): Boolean = + allSourceRoots.none { sourceRoot.sourcePath.parent.startsWith(it.sourcePath) } + + override fun transform(inputEntity: BuildTargetAndSourceItem): List { + val rootType = inferRootType(inputEntity.buildTarget) + + return SourceItemToSourceRootTransformer + .transform(inputEntity.sourcesItem.sources) + .map { toGoSourceRoot(it, rootType) } + } + + private fun inferRootType(buildTarget: BuildTarget): String = + if (buildTarget.tags.contains("test")) testSourceRootType else sourceRootType + + private fun toGoSourceRoot( + sourceRoot: SourceRoot, + rootType: String, + ): GenericSourceRoot { + return GenericSourceRoot( + sourcePath = sourceRoot.sourcePath, + rootType = rootType, + ) + } +} diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/server/tasks/CollectProjectDetailsTask.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/server/tasks/CollectProjectDetailsTask.kt index 69a08ccd6..8037868d1 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/server/tasks/CollectProjectDetailsTask.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/server/tasks/CollectProjectDetailsTask.kt @@ -24,10 +24,12 @@ import com.intellij.platform.util.progress.reportSequentialProgress import com.intellij.platform.workspace.jps.JpsFileDependentEntitySource import com.intellij.platform.workspace.jps.JpsFileEntitySource import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource +import com.intellij.platform.workspace.jps.entities.ModuleEntity import com.intellij.platform.workspace.storage.EntitySource import com.intellij.platform.workspace.storage.MutableEntityStorage import com.intellij.platform.workspace.storage.url.VirtualFileUrl import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager +import com.intellij.workspaceModel.ide.impl.legacyBridge.module.findModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -52,6 +54,8 @@ import org.jetbrains.plugins.bsp.config.BspFeatureFlags import org.jetbrains.plugins.bsp.config.BspPluginBundle import org.jetbrains.plugins.bsp.config.rootDir import org.jetbrains.plugins.bsp.extension.points.PythonSdkGetterExtension +import org.jetbrains.plugins.bsp.extension.points.goSdkExtension +import org.jetbrains.plugins.bsp.extension.points.goSdkExtensionExists import org.jetbrains.plugins.bsp.extension.points.pythonSdkGetterExtension import org.jetbrains.plugins.bsp.extension.points.pythonSdkGetterExtensionExists import org.jetbrains.plugins.bsp.flow.open.projectSyncHook @@ -141,6 +145,7 @@ public class CollectProjectDetailsTask(project: Project, private val taskId: Any } } + @Suppress("CognitiveComplexMethod") private suspend fun doExecute(buildProject: Boolean) { reportSequentialProgress { reporter -> val projectDetails = @@ -176,6 +181,12 @@ public class CollectProjectDetailsTask(project: Project, private val taskId: Any } } + if (BspFeatureFlags.isGoSupportEnabled && goSdkExtensionExists()) { + reporter.indeterminateStep(text = BspPluginBundle.message("progress.bar.calculate.go.sdk.infos")) { + calculateAllGoSdkInfosSubtask(projectDetails) + } + } + reporter.sizedStep(workSize = 25, text = BspPluginBundle.message("progress.bar.update.internal.model")) { updateInternalModelSubtask(projectDetails) } @@ -354,6 +365,17 @@ public class CollectProjectDetailsTask(project: Project, private val taskId: Any ) } + private suspend fun calculateAllGoSdkInfosSubtask(projectDetails: ProjectDetails) = withSubtask( + "calculate-all-go-sdk-infos", + BspPluginBundle.message("console.task.model.calculate.go.sdk.infos") + ) { + runInterruptible { + logPerformance(it) { + goSdkExtension()?.calculateAllGoSdkInfos(projectDetails) + } + } + } + private suspend fun updateInternalModelSubtask(projectDetails: ProjectDetails) { withSubtask("calculate-project-structure", BspPluginBundle.message("console.task.model.calculate.structure")) { runInterruptible { @@ -457,6 +479,12 @@ public class CollectProjectDetailsTask(project: Project, private val taskId: Any if (BspFeatureFlags.isAndroidSupportEnabled) { addBspFetchedAndroidSdks() } + + if (BspFeatureFlags.isGoSupportEnabled) { + addBspFetchedGoSdks() + goSdkExtension()?.restoreGoModulesRegistry(project) + enableGoSupportInTargets() + } } private suspend fun addBspFetchedJdks() = withSubtask( @@ -531,6 +559,33 @@ public class CollectProjectDetailsTask(project: Project, private val taskId: Any SdkUtils.addSdkIfNeeded(sdk) } + private suspend fun addBspFetchedGoSdks() = + goSdkExtension()?.let { extension -> + withSubtask("add-bsp-fetched-go-sdks", BspPluginBundle.message("console.task.model.add.go.fetched.sdks")) { + logPerformanceSuspend("add-bsp-fetched-go-sdks") { + extension.addGoSdks(project) + } + } + } + + private suspend fun enableGoSupportInTargets() = + goSdkExtension()?.let { extension -> + withSubtask( + "enable-go-support-in-targets", + BspPluginBundle.message("console.task.model.add.go.support.in.targets")) { + logPerformanceSuspend("enable-go-support-in-targets") { + val workspaceModel = WorkspaceModel.getInstance(project) + workspaceModel.currentSnapshot.entities(ModuleEntity::class.java).forEach { moduleEntity -> + moduleEntity.findModule(workspaceModel.currentSnapshot)?.let { module -> + writeAction { + extension.enableGoSupportForModule(module) + } + } + } + } + } + } + private suspend fun applyChangesOnWorkspaceModel() = withSubtask( "apply-changes-on-workspace-model", BspPluginBundle.message("console.task.model.apply.changes") diff --git a/src/main/kotlin/org/jetbrains/plugins/bsp/ui/gutters/BspJVMRunLineMarkerContributor.kt b/src/main/kotlin/org/jetbrains/plugins/bsp/ui/gutters/BspJVMRunLineMarkerContributor.kt index 70c391275..0dd0cdb8d 100644 --- a/src/main/kotlin/org/jetbrains/plugins/bsp/ui/gutters/BspJVMRunLineMarkerContributor.kt +++ b/src/main/kotlin/org/jetbrains/plugins/bsp/ui/gutters/BspJVMRunLineMarkerContributor.kt @@ -1,5 +1,7 @@ package org.jetbrains.plugins.bsp.ui.gutters +import com.goide.psi.GoFile +import com.goide.psi.impl.GoFunctionDeclarationImpl import com.intellij.execution.lineMarker.RunLineMarkerContributor import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.DefaultActionGroup @@ -28,8 +30,12 @@ public class BspJVMRunLineMarkerContributor : RunLineMarkerContributor() { else null private fun PsiElement.shouldAddMarker(): Boolean = - !isInsideJar() && getStrictParentOfType() - ?.isClassOrMethod() ?: false + (!isInsideJar() && getStrictParentOfType() + ?.isClassOrMethod() ?: false) || isGoTopLevelFunction() + + private fun PsiElement.isGoTopLevelFunction() = + getStrictParentOfType() is GoFunctionDeclarationImpl + && getStrictParentOfType()?.parent is GoFile private fun PsiElement.isInsideJar() = containingFile.virtualFile?.url?.startsWith("jar://") ?: false diff --git a/src/main/resources/META-INF/bsp-withGo.xml b/src/main/resources/META-INF/bsp-withGo.xml new file mode 100644 index 000000000..e3be5c462 --- /dev/null +++ b/src/main/resources/META-INF/bsp-withGo.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 4e69eddba..cbf8834ef 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -6,6 +6,7 @@ com.intellij.modules.platform com.intellij.java org.jetbrains.kotlin + org.jetbrains.plugins.go com.intellij.modules.python org.jetbrains.android @@ -25,6 +26,12 @@ + + @@ -128,6 +135,7 @@ + diff --git a/src/main/resources/messages/BspPluginBundle.properties b/src/main/resources/messages/BspPluginBundle.properties index f581f8cec..33e761806 100644 --- a/src/main/resources/messages/BspPluginBundle.properties +++ b/src/main/resources/messages/BspPluginBundle.properties @@ -35,9 +35,12 @@ console.task.mobile.no.target.device=No target device found. console.task.mobile.waiting.for.target.device=Waiting for the target device to come online... console.task.model.add.android.fetched.sdks=Adding fetched Android SDKs console.task.model.add.fetched.jdks=Adding fetched JDKs done. +console.task.model.add.go.fetched.sdks=Adding fetched Go SDKs +console.task.model.add.go.support.in.targets=Adding Go support in targets console.task.model.add.python.fetched.sdks=Adding fetched Python SDKs console.task.model.add.scala.fetched.sdks=Adding fetched Scala SDKs console.task.model.apply.changes=Applying changes on workspace model +console.task.model.calculate.go.sdk.infos=Calculating all go sdk infos console.task.model.calculate.jdks.infos=Calculating all unique jdk infos console.task.model.calculate.python.sdks.done=Calculating all python sdk infos console.task.model.calculate.scala.sdk.infos=Calculating all scala sdk infos @@ -66,6 +69,7 @@ console.tasks.title={0}: {1} disconnect.action.text=Disconnect From BSP Server plugin.name=BSP (experimental) progress.bar.calculate.android.sdk.infos=Calculating all unique Android SDK infos +progress.bar.calculate.go.sdk.infos=Calculating all unique go sdk infos progress.bar.calculate.jdk.infos=Calculating all unique JDK infos progress.bar.calculate.python.sdk.infos=Calculating all unique Python SDK infos progress.bar.collect.project.details=Collecting project details diff --git a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoResourceEntityUpdaterTest.kt b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoResourceEntityUpdaterTest.kt new file mode 100644 index 000000000..204375d1d --- /dev/null +++ b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/GoResourceEntityUpdaterTest.kt @@ -0,0 +1,141 @@ +package org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.impl.updaters + +import com.intellij.platform.workspace.jps.entities.ContentRootEntity +import com.intellij.platform.workspace.jps.entities.SourceRootEntity +import com.intellij.platform.workspace.storage.impl.url.toVirtualFileUrl +import org.jetbrains.plugins.bsp.magicmetamodel.impl.workspacemodel.ResourceRoot +import org.jetbrains.workspace.model.matchers.entries.ExpectedSourceRootEntity +import org.jetbrains.workspace.model.matchers.entries.shouldBeEqual +import org.jetbrains.workspace.model.matchers.entries.shouldContainExactlyInAnyOrder +import org.jetbrains.workspace.model.test.framework.WorkspaceModelWithParentGoModuleBaseTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.net.URI +import kotlin.io.path.toPath + +@DisplayName("goResourceEntityUpdater.addEntity(entityToAdd, parentModuleEntity) tests") +class GoResourceEntityUpdaterTest : WorkspaceModelWithParentGoModuleBaseTest() { + private lateinit var goResourceEntityUpdater: GoResourceEntityUpdater + + @BeforeEach + override fun beforeEach() { + super.beforeEach() + + val workspaceModelEntityUpdaterConfig = + WorkspaceModelEntityUpdaterConfig(workspaceEntityStorageBuilder, virtualFileUrlManager, projectBasePath, project) + goResourceEntityUpdater = GoResourceEntityUpdater(workspaceModelEntityUpdaterConfig) + } + + @Test + fun `should add one go resource root to the workspace model`() { + // given + val resourcePath = URI.create("file:///root/dir/example/resource/File.txt").toPath() + val goResourceRoot = ResourceRoot(resourcePath, "") + + // when + val returnedResourceRootEntity = runTestWriteAction { + goResourceEntityUpdater.addEntity(goResourceRoot, parentModuleEntity) + } + + // then + val virtualResourceUrl = resourcePath.toVirtualFileUrl(virtualFileUrlManager) + + val expectedResourceRootEntity = ExpectedSourceRootEntity( + contentRootEntity = ContentRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl, + excludedPatterns = emptyList(), + ), + sourceRootEntity = SourceRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl, + rootType = "go-resource", + ) {}, + parentModuleEntity = parentModuleEntity, + ) + + returnedResourceRootEntity shouldBeEqual expectedResourceRootEntity + loadedEntries(SourceRootEntity::class.java) shouldContainExactlyInAnyOrder listOf( + expectedResourceRootEntity, + ) + } + + @Test + fun `should add multiple go resource roots to the workspace model`() { + // given + val resourcePath1 = URI.create("file:///root/dir/example/resource/File1.txt").toPath() + val goResourceRoot1 = ResourceRoot(resourcePath1, "") + + val resourcePath2 = URI.create("file:///root/dir/example/resource/File2.txt").toPath() + val goResourceRoot2 = ResourceRoot(resourcePath2, "") + + val resourcePath3 = URI.create("file:///root/dir/example/resource/File3.txt").toPath() + val goResourceRoot3 = ResourceRoot(resourcePath2, "") + + val goResourceRoots = listOf(goResourceRoot1, goResourceRoot2, goResourceRoot3) + + // when + val returnedResourceRootEntities = runTestWriteAction { + goResourceEntityUpdater.addEntries(goResourceRoots, parentModuleEntity) + } + + // then + val virtualResourceUrl1 = resourcePath1.toVirtualFileUrl(virtualFileUrlManager) + + val expectedResourceRootEntity1 = ExpectedSourceRootEntity( + contentRootEntity = ContentRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl1, + excludedPatterns = emptyList(), + ), + sourceRootEntity = SourceRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl1, + rootType = "go-resource", + ) {}, + parentModuleEntity = parentModuleEntity, + ) + + val virtualResourceUrl2 = resourcePath2.toVirtualFileUrl(virtualFileUrlManager) + + val expectedResourceRootEntity2 = ExpectedSourceRootEntity( + contentRootEntity = ContentRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl2, + excludedPatterns = emptyList(), + ), + sourceRootEntity = SourceRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl2, + rootType = "go-resource", + ) {}, + parentModuleEntity = parentModuleEntity, + ) + + val virtualResourceUrl3 = resourcePath3.toVirtualFileUrl(virtualFileUrlManager) + + val expectedResourceRootEntity3 = ExpectedSourceRootEntity( + contentRootEntity = ContentRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl3, + excludedPatterns = emptyList(), + ), + sourceRootEntity = SourceRootEntity( + entitySource = parentModuleEntity.entitySource, + url = virtualResourceUrl3, + rootType = "go-resource", + ) {}, + parentModuleEntity = parentModuleEntity, + ) + + val expectedResourceRootEntities = listOf( + expectedResourceRootEntity1, + expectedResourceRootEntity2, + expectedResourceRootEntity3, + ) + + returnedResourceRootEntities shouldContainExactlyInAnyOrder expectedResourceRootEntities + loadedEntries(SourceRootEntity::class.java) shouldContainExactlyInAnyOrder expectedResourceRootEntities + } +} diff --git a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToJavaModuleTransformerTest.kt b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToJavaModuleTransformerTest.kt index d298fb9af..f61ff2195 100644 --- a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToJavaModuleTransformerTest.kt +++ b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToJavaModuleTransformerTest.kt @@ -165,6 +165,7 @@ class ModuleDetailsToJavaModuleTransformerTest { ), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val targetsMap = listOf(buildTargetId.uri, "module2", "module3").toDefaultTargetsMap() @@ -312,6 +313,7 @@ class ModuleDetailsToJavaModuleTransformerTest { ), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val targetsMap = listOf(buildTargetId.uri, "module2", "module3").toDefaultTargetsMap() @@ -456,6 +458,7 @@ class ModuleDetailsToJavaModuleTransformerTest { ), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val module2Root = createTempDirectory(projectBasePath, "module2").toAbsolutePath() @@ -522,6 +525,7 @@ class ModuleDetailsToJavaModuleTransformerTest { ), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val modulesDetails = listOf(moduleDetails1, moduleDetails2) diff --git a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToPythonModuleTransformerTest.kt b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToPythonModuleTransformerTest.kt index ca8564798..8511f3936 100644 --- a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToPythonModuleTransformerTest.kt +++ b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ModuleDetailsToPythonModuleTransformerTest.kt @@ -147,6 +147,7 @@ class ModuleDetailsToPythonModuleTransformerTest { ), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val targetsMap = listOf("module1", "module2", "module3").toDefaultTargetsMap() @@ -283,6 +284,7 @@ class ModuleDetailsToPythonModuleTransformerTest { ), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val module2Root = createTempDirectory(projectBasePath, "module2").toAbsolutePath() @@ -340,6 +342,7 @@ class ModuleDetailsToPythonModuleTransformerTest { moduleDependencies = listOf(buildTargetId3.uri), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val modulesDetails = listOf(moduleDetails1, moduleDetails2) @@ -440,6 +443,7 @@ class ModuleDetailsToPythonModuleTransformerTest { moduleDependencies = emptyList(), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) fun emptyExpectedModule(name: String, sdkInfo: PythonSdkInfo): PythonModule { diff --git a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformerTest.kt b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformerTest.kt index 9a3f30fa6..49c5b5f5b 100644 --- a/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformerTest.kt +++ b/src/test/kotlin/org/jetbrains/plugins/bsp/magicmetamodel/impl/workspacemodel/impl/updaters/transformers/ProjectDetailsToModuleDetailsTransformerTest.kt @@ -60,6 +60,7 @@ class ProjectDetailsToModuleDetailsTransformerTest { moduleDependencies = emptyList(), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) actualModuleDetails shouldBe expectedModuleDetails @@ -131,6 +132,7 @@ class ProjectDetailsToModuleDetailsTransformerTest { moduleDependencies = emptyList(), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) actualModuleDetails shouldBe expectedModuleDetails @@ -267,6 +269,7 @@ class ProjectDetailsToModuleDetailsTransformerTest { moduleDependencies = listOf(target2Id.uri), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val expectedModuleDetails2 = ModuleDetails( target = target2, @@ -281,6 +284,7 @@ class ProjectDetailsToModuleDetailsTransformerTest { moduleDependencies = emptyList(), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val expectedModuleDetails3 = ModuleDetails( target = target3, @@ -295,6 +299,7 @@ class ProjectDetailsToModuleDetailsTransformerTest { moduleDependencies = listOf(target2Id.uri), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) val expectedModuleDetails4 = ModuleDetails( target = target4, @@ -309,6 +314,7 @@ class ProjectDetailsToModuleDetailsTransformerTest { moduleDependencies = listOf(target1Id.uri), defaultJdkName = null, jvmBinaryJars = emptyList(), + goLibraries = emptyList() ) actualModuleDetails1 shouldBe expectedModuleDetails1 diff --git a/src/testFixtures/kotlin/org/jetbrains/workspace/model/test/framework/WorkspaceModelBaseTest.kt b/src/testFixtures/kotlin/org/jetbrains/workspace/model/test/framework/WorkspaceModelBaseTest.kt index 1bd0fb7ba..81df4991c 100644 --- a/src/testFixtures/kotlin/org/jetbrains/workspace/model/test/framework/WorkspaceModelBaseTest.kt +++ b/src/testFixtures/kotlin/org/jetbrains/workspace/model/test/framework/WorkspaceModelBaseTest.kt @@ -151,3 +151,6 @@ public abstract class WorkspaceModelWithParentJavaModuleBaseTest : WorkspaceMode public abstract class WorkspaceModelWithParentPythonModuleBaseTest : WorkspaceModelWithParentModuleBaseTest() { override val parentModuleType: String = "PYTHON_MODULE" } +public abstract class WorkspaceModelWithParentGoModuleBaseTest : WorkspaceModelWithParentModuleBaseTest() { + override val parentModuleType: String = "WEB_MODULE" +}