[dependencies] feature collector for not loaded (on demand) plugins

GitOrigin-RevId: e7dbeead53df0119220fc8177f11b8aec44a72be
This commit is contained in:
Andrew Kozlov
2022-08-11 12:27:15 +02:00
committed by intellij-monorepo-bot
parent b00da45550
commit e14f946b06
5 changed files with 80 additions and 8 deletions

View File

@@ -9,7 +9,9 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.extensions.ExtensionPointName
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
@Service(Service.Level.APP)
@State(name = "PluginFeatureService", storages = [Storage(StoragePathMacros.CACHE_FILE)])
class PluginFeatureService : SerializablePersistentStateComponent<PluginFeatureService.State>(State()) {
@@ -36,7 +38,7 @@ class PluginFeatureService : SerializablePersistentStateComponent<PluginFeatureS
idMapping: (T) -> String,
displayNameMapping: (T) -> String,
) {
val featureMap = LinkedHashMap(featureMap(featureType))
val featureMap = LinkedHashMap<String, FeaturePluginData>()
// fold
ep.processWithPluginDescriptor { ext, descriptor ->
@@ -48,15 +50,27 @@ class PluginFeatureService : SerializablePersistentStateComponent<PluginFeatureS
featureMap.put(idMapping(ext), pluginData)
}
updateFeatureMapping(featureType, featureMap)
}
@ApiStatus.Experimental
fun updateFeatureMapping(
featureType: String,
featureMap: Map<String, FeaturePluginData>,
) {
updateState { oldState ->
State(oldState.features + (featureType to FeaturePluginList(featureMap)))
val oldFeatures = oldState.features
val newFeatureMap = LinkedHashMap(oldFeatures.getFeatureMap(featureType) ?: emptyMap()) +
featureMap
State(oldFeatures + (featureType to FeaturePluginList(newFeatureMap)))
}
}
fun getPluginForFeature(
featureType: String,
implementationName: String,
): FeaturePluginData? = featureMap(featureType).get(implementationName)
): FeaturePluginData? = state.features.getFeatureMap(featureType)?.get(implementationName)
private fun featureMap(featureType: String) = state.features.get(featureType)?.featureMap ?: emptyMap()
private fun Map<String, FeaturePluginList>.getFeatureMap(featureType: String) = get(featureType)?.featureMap
}

View File

@@ -10,8 +10,10 @@ import com.intellij.openapi.startup.ProjectPostStartupActivity
import com.intellij.openapi.util.NlsSafe
import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.util.xmlb.annotations.Attribute
import org.jetbrains.annotations.ApiStatus
internal class DependencyCollectorBean : BaseKeyedLazyInstance<DependencyCollector>() {
@Attribute("kind")
@JvmField
@RequiredElement
@@ -46,7 +48,8 @@ interface DependencyCollector {
* Marks a plugin as supporting a given dependency. The `coordinate` attribute specifies the name or coordinate of the supported
* library/dependency, in the same format as returned from [DependencyCollector.collectDependencies] for the respective dependency kind.
*/
internal class DependencySupportBean : PluginAware {
internal class DependencySupportBean() : PluginAware {
private var pluginDescriptor: PluginDescriptor? = null
@Attribute("kind")
@@ -71,6 +74,13 @@ internal class DependencySupportBean : PluginAware {
val EP_NAME = ExtensionPointName.create<DependencySupportBean>("com.intellij.dependencySupport")
}
@ApiStatus.Experimental
internal constructor(attributes: Map<String, String>) : this() {
kind = attributes["kind"]!!
coordinate = attributes["coordinate"]!!
displayName = attributes.getOrDefault("displayName", "")
}
override fun setPluginDescriptor(pluginDescriptor: PluginDescriptor) {
this.pluginDescriptor = pluginDescriptor
}
@@ -78,13 +88,20 @@ internal class DependencySupportBean : PluginAware {
internal const val DEPENDENCY_SUPPORT_FEATURE = "dependencySupport"
internal val DependencySupportBean.id: @NlsSafe String
get() = "$kind:$coordinate"
internal val DependencySupportBean.displayNameOrId: @NlsSafe String
get() = displayName.ifEmpty { id }
internal class DependencyFeatureCollector : ProjectPostStartupActivity {
override suspend fun execute(project: Project) {
PluginFeatureService.instance.collectFeatureMapping(
DEPENDENCY_SUPPORT_FEATURE,
DependencySupportBean.EP_NAME,
{ bean -> bean.kind + ":" + bean.coordinate },
{ bean -> bean.displayName.ifEmpty { bean.kind + ":" + bean.coordinate } }
{ it.id },
{ it.displayNameOrId },
)
}
}

View File

@@ -0,0 +1,39 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ide.plugins.advertiser
import com.intellij.ide.plugins.*
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectPostStartupActivity
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Experimental
private class OnDemandDependencyFeatureCollector : ProjectPostStartupActivity {
init {
if (!IdeaPluginDescriptorImpl.isOnDemandEnabled) {
throw ExtensionNotApplicableException.create()
}
}
override suspend fun execute(project: Project) {
val featureMap = LinkedHashMap<String, FeaturePluginData>()
PluginManagerCore.getPluginSet()
.allPlugins // todo modules
.filter { it.pluginClassLoader == null }
.filter { it.isOnDemand }
.associateWith { it.epNameToExtensions?.get(DependencySupportBean.EP_NAME.name) ?: emptyList() }
.forEach { (pluginDescriptor, extensionDescriptors) ->
val pluginData = PluginData(pluginDescriptor)
featureMap += extensionDescriptors.mapNotNull { it.element }
.map { DependencySupportBean(it.attributes) }
.associate { bean ->
bean.id to FeaturePluginData(bean.displayNameOrId, pluginData)
}
}
PluginFeatureService.instance.updateFeatureMapping(DEPENDENCY_SUPPORT_FEATURE, featureMap)
}
}

View File

@@ -1348,6 +1348,7 @@
<advancedSetting id="documentation.components.enable.highlighting.of.links" default="false" groupKey="group.advanced.settings.documentation.components"/>
<backgroundPostStartupActivity implementation="com.intellij.ide.plugins.DependencyFeatureCollector"/>
<backgroundPostStartupActivity implementation="com.intellij.ide.plugins.advertiser.OnDemandDependencyFeatureCollector"/>
<projectService serviceInterface="com.intellij.presentation.FilePresentationService"
serviceImplementation="com.intellij.presentation.impl.FilePresentationServiceImpl"/>

View File

@@ -1,5 +1,6 @@
<!--suppress PluginXmlValidity -->
<idea-plugin package="org.jetbrains.idea.devkit.dummy">
<idea-plugin package="org.jetbrains.idea.devkit.dummy"
on-demand="true">
<id>DevKit</id>
<name>Plugin DevKit</name>
<category>Plugin Development</category>