<commit_before>// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.plugins

import com.intellij.externalDependencies.DependencyOnPlugin
import com.intellij.externalDependencies.ExternalDependenciesManager
import com.intellij.ide.AppLifecycleListener
import com.intellij.ide.IdeBundle
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ProjectManagerListener
import com.intellij.openapi.startup.StartupActivity
import com.intellij.project.stateStore
import com.intellij.util.xmlb.annotations.XCollection
import org.jetbrains.annotations.ApiStatus
import javax.swing.JComponent

@State(
  name = "ProjectPluginTrackerManager",
  storages = [Storage(value = StoragePathMacros.NON_ROAMABLE_FILE, roamingType = RoamingType.DISABLED)],
  reloadable = false,
)
@ApiStatus.Internal
class ProjectPluginTrackerManager : SimplePersistentStateComponent<ProjectPluginTrackerManagerState>(ProjectPluginTrackerManagerState()) {
  companion object {
    @JvmStatic
    val instance
      get() = service<ProjectPluginTrackerManager>()

    @JvmStatic
    fun loadPlugins(pluginIds: Collection<PluginId>): Boolean = DynamicPlugins.loadPlugins(pluginIds.toPluginDescriptors())

    @JvmStatic
    @JvmOverloads
    fun unloadPlugins(
      pluginIds: Collection<PluginId>,
      project: Project? = null,
      parentComponent: JComponent? = null,
    ): Boolean = DynamicPlugins.unloadPlugins(
      pluginIds.toPluginDescriptors(),
      project,
      parentComponent,
    )

    internal class EnableDisablePluginsActivity : StartupActivity {

      init {
        if (ApplicationManager.getApplication().isUnitTestMode) {
          throw ExtensionNotApplicableException.INSTANCE
        }
      }

      override fun runActivity(project: Project) {
        val indicator = ProgressManager.getInstance().progressIndicator
        ApplicationManager.getApplication().invokeLater(
          Runnable {
            val manager = instance
            val tracker = manager.getPluginTracker(project)
            val projects = openProjectsExcludingCurrent(project)

            indicator?.let {
              it.text = IdeBundle.message("plugins.progress.loading.plugins.for.current.project.title", project.name)
            }
            val pluginIdsToLoad = tracker.enabledPluginsIds
              .union(manager.locallyDisabledAndGloballyEnabledPlugins(projects))
            loadPlugins(pluginIdsToLoad)

            indicator?.let {
              it.text = IdeBundle.message("plugins.progress.unloading.plugins.for.current.project.title", project.name)
            }
            manager.unloadPlugins(
              tracker.disabledPluginsIds,
              project,
              projects,
            )
          },
          project.disposed,
        )
      }
    }

    internal fun openProjectsExcludingCurrent(project: Project?) = ProjectManager.getInstance().openProjects.filterNot { it == project }

    private fun Collection<PluginId>.toPluginDescriptors() = mapNotNull { PluginManagerCore.getPlugin(it) }
  }

  private var applicationShuttingDown = false

  init {
    val connection = ApplicationManager.getApplication().messageBus.connect()
    connection.subscribe(
      ProjectManager.TOPIC,
      object : ProjectManagerListener {<commit_msg>[dynamic plugins] invokeAndWait should be used instead of invokeLater #IDEA-261659 fixed<commit_after>// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.plugins

import com.intellij.externalDependencies.DependencyOnPlugin
import com.intellij.externalDependencies.ExternalDependenciesManager
import com.intellij.ide.AppLifecycleListener
import com.intellij.ide.IdeBundle
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ProjectManagerListener
import com.intellij.openapi.startup.StartupActivity
import com.intellij.project.stateStore
import com.intellij.util.xmlb.annotations.XCollection
import org.jetbrains.annotations.ApiStatus
import javax.swing.JComponent

@State(
  name = "ProjectPluginTrackerManager",
  storages = [Storage(value = StoragePathMacros.NON_ROAMABLE_FILE, roamingType = RoamingType.DISABLED)],
  reloadable = false,
)
@ApiStatus.Internal
class ProjectPluginTrackerManager : SimplePersistentStateComponent<ProjectPluginTrackerManagerState>(ProjectPluginTrackerManagerState()) {
  companion object {
    @JvmStatic
    val instance
      get() = service<ProjectPluginTrackerManager>()

    @JvmStatic
    fun loadPlugins(pluginIds: Collection<PluginId>): Boolean = DynamicPlugins.loadPlugins(pluginIds.toPluginDescriptors())

    @JvmStatic
    @JvmOverloads
    fun unloadPlugins(
      pluginIds: Collection<PluginId>,
      project: Project? = null,
      parentComponent: JComponent? = null,
    ): Boolean = DynamicPlugins.unloadPlugins(
      pluginIds.toPluginDescriptors(),
      project,
      parentComponent,
    )

    internal class EnableDisablePluginsActivity : StartupActivity {

      init {
        if (ApplicationManager.getApplication().isUnitTestMode) {
          throw ExtensionNotApplicableException.INSTANCE
        }
      }

      override fun runActivity(project: Project) {
        val manager = instance
        val tracker = manager.getPluginTracker(project)
        val projects = openProjectsExcludingCurrent(project)

        val pluginIdsToLoad = tracker.enabledPluginsIds
          .union(manager.locallyDisabledAndGloballyEnabledPlugins(projects))

        val pluginIdsToUnload = tracker.disabledPluginsIds

        if (pluginIdsToLoad.isNotEmpty() ||
            pluginIdsToUnload.isNotEmpty()) {
          val indicator = ProgressManager.getInstance().progressIndicator
          ApplicationManager.getApplication().invokeAndWait {
            indicator?.let {
              it.text = IdeBundle.message("plugins.progress.loading.plugins.for.current.project.title", project.name)
            }
            loadPlugins(pluginIdsToLoad)

            indicator?.let {
              it.text = IdeBundle.message("plugins.progress.unloading.plugins.for.current.project.title", project.name)
            }
            manager.unloadPlugins(
              pluginIdsToUnload,
              project,
              projects,
            )
          }
        }
      }
    }

    internal fun openProjectsExcludingCurrent(project: Project?) = ProjectManager.getInstance().openProjects.filterNot { it == project }

    private fun Collection<PluginId>.toPluginDescriptors() = mapNotNull { PluginManagerCore.getPlugin(it) }
  }

  private var applicationShuttingDown = false

  init {
    val connection = ApplicationManager.getApplication().messageBus.connect()
    connection.subscribe(
      ProjectManager.TOPIC,
      object : ProjectManagerListener {
{'fraction_non_alphanumeric': 0.0801899235030335, 'fraction_numerical': 0.0034291743603270903, 'mean_word_length': 3.6294261294261294, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '833677', 'n_tokens_mistral': 2044, 'n_tokens_neox': 1985, 'n_words': 362}