mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
IDEA-300739 Do not create instances of LangSupport during LangManager initialization
GitOrigin-RevId: a985502bde6f18d6fae7ba33463f7c6fad0b3a09
This commit is contained in:
committed by
intellij-monorepo-bot
parent
51ce98424c
commit
68b7c53db2
@@ -1,6 +1,6 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="training">
|
||||
<ift.language.extension language="JAVA" implementationClass="com.intellij.java.ift.JavaLangSupport"/>
|
||||
<ift.language.extension language="JAVA" defaultProductName="IDEA" implementationClass="com.intellij.java.ift.JavaLangSupport"/>
|
||||
<ift.learning.course language="JAVA" implementationClass="com.intellij.java.ift.JavaLearningCourse"/>
|
||||
<ifs.suggesterSupport language="JAVA" implementationClass="com.intellij.java.ifs.JavaSuggesterSupport"/>
|
||||
</extensions>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<extensionPoints>
|
||||
<extensionPoint name="ift.language.extension"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint" dynamic="true">
|
||||
beanClass="training.lang.LangSupportBean" dynamic="true">
|
||||
<with attribute="implementationClass" implements="training.lang.LangSupport"/>
|
||||
</extensionPoint>
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
package training.actions
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.LanguageExtensionPoint
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
@@ -14,6 +13,7 @@ import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import training.lang.LangManager
|
||||
import training.lang.LangSupport
|
||||
import training.lang.LangSupportBean
|
||||
import training.learn.LearnBundle
|
||||
import training.ui.LearnToolWindow
|
||||
import training.util.resetPrimaryLanguage
|
||||
@@ -23,8 +23,8 @@ internal class ChooseProgrammingLanguageForLearningAction(private val learnToolW
|
||||
override fun createPopupActionGroup(button: JComponent?): DefaultActionGroup {
|
||||
val allActionsGroup = DefaultActionGroup()
|
||||
val supportedLanguagesExtensions = LangManager.getInstance().supportedLanguagesExtensions.sortedBy { it.language }
|
||||
for (langSupportExt: LanguageExtensionPoint<LangSupport> in supportedLanguagesExtensions) {
|
||||
val languageId = langSupportExt.language
|
||||
for (langSupportExt: LangSupportBean in supportedLanguagesExtensions) {
|
||||
val languageId = langSupportExt.getLang()
|
||||
val displayName = Language.findLanguageByID(languageId)?.displayName ?: continue
|
||||
allActionsGroup.add(SelectLanguageAction(languageId, displayName))
|
||||
}
|
||||
@@ -50,7 +50,7 @@ internal class ChooseProgrammingLanguageForLearningAction(private val learnToolW
|
||||
private inner class SelectLanguageAction(private val languageId: String, @NlsSafe displayName: String) : AnAction(displayName) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val ep = LangManager.getInstance().supportedLanguagesExtensions.singleOrNull { it.language == languageId } ?: return
|
||||
resetPrimaryLanguage(ep.instance)
|
||||
resetPrimaryLanguage(ep.getLang())
|
||||
learnToolWindow.setModulesPanel()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
package training.lang
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.LanguageExtensionPoint
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo
|
||||
import com.intellij.openapi.components.*
|
||||
@@ -16,30 +15,33 @@ import training.util.*
|
||||
Storage(value = trainerPluginConfigName, deprecated = true)
|
||||
])
|
||||
class LangManager : SimplePersistentStateComponent<LangManager.State>(State()) {
|
||||
val supportedLanguagesExtensions: List<LanguageExtensionPoint<LangSupport>>
|
||||
val supportedLanguagesExtensions: List<LangSupportBean>
|
||||
get() {
|
||||
return ExtensionPointName<LanguageExtensionPoint<LangSupport>>(LangSupport.EP_NAME).extensionList
|
||||
.filter { courseCanBeUsed(it.language) }
|
||||
return ExtensionPointName<LangSupportBean>(LangSupport.EP_NAME).extensionList
|
||||
.filter { courseCanBeUsed(it.getLang()) }
|
||||
}
|
||||
|
||||
val languages: List<LanguageExtensionPoint<LangSupport>>
|
||||
val languages: List<LangSupportBean>
|
||||
get() = supportedLanguagesExtensions.filter { Language.findLanguageByID(it.language) != null }
|
||||
|
||||
private var langSupportRef: LangSupport? by WeakReferenceDelegator()
|
||||
private val langSupportDelegator = LazyWeakReferenceDelegator {
|
||||
supportedLanguagesExtensions.find { langBean -> langBean.language == state.languageName }?.instance
|
||||
}
|
||||
private val langSupportRef: LangSupport? by langSupportDelegator
|
||||
|
||||
init {
|
||||
val productName = ApplicationNamesInfo.getInstance().productName
|
||||
val langSupportBeans = languages
|
||||
val onlyLang =
|
||||
languages.singleOrNull()
|
||||
?: languages.singleOrNull { it.instance.defaultProductName == productName }
|
||||
?: languages.firstOrNull()?.also {
|
||||
langSupportBeans.singleOrNull()
|
||||
?: langSupportBeans.singleOrNull { it.defaultProductName == productName }
|
||||
?: langSupportBeans.firstOrNull()?.also {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||
logger<LangManager>().warn("No default language for $productName. Selected ${it.language}.")
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyLang != null) {
|
||||
langSupportRef = onlyLang.instance
|
||||
state.languageName = onlyLang.language
|
||||
}
|
||||
}
|
||||
@@ -62,18 +64,26 @@ class LangManager : SimplePersistentStateComponent<LangManager.State>(State()) {
|
||||
}
|
||||
|
||||
// do not call this if LearnToolWindow with modules or learn views due to reinitViews
|
||||
fun updateLangSupport(langSupport: LangSupport) {
|
||||
this.langSupportRef = langSupport
|
||||
state.languageName = supportedLanguagesExtensions.find { it.instance == langSupport }?.language
|
||||
?: throw Exception("Unable to get language.")
|
||||
fun updateLangSupport(languageId: String) {
|
||||
val oldLanguage = state.languageName
|
||||
state.languageName = supportedLanguagesExtensions.find { it.language == languageId }?.language
|
||||
?: throw Exception("Unable to find LangSupport for language: $languageId")
|
||||
if (state.languageName != oldLanguage) {
|
||||
langSupportDelegator.reset()
|
||||
}
|
||||
getAllLearnToolWindows().forEach { it.reinitViews() }
|
||||
}
|
||||
|
||||
fun getLangSupport(): LangSupport? = langSupportRef
|
||||
|
||||
fun getLanguageId(): String? = state.languageName
|
||||
|
||||
override fun loadState(state: State) {
|
||||
val oldLanguage = this.state.languageName
|
||||
super.loadState(state)
|
||||
langSupportRef = supportedLanguagesExtensions.find { langExt -> langExt.language == state.languageName }?.instance ?: return
|
||||
if (oldLanguage != state.languageName) {
|
||||
langSupportDelegator.reset()
|
||||
}
|
||||
}
|
||||
|
||||
fun getLanguageDisplayName(): String {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package training.lang
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.extensions.CustomLoadingExtensionPointBean
|
||||
import com.intellij.util.xmlb.annotations.Attribute
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
class LangSupportBean : CustomLoadingExtensionPointBean<LangSupport> {
|
||||
/**
|
||||
* [Language.getID]
|
||||
*/
|
||||
@Attribute("language")
|
||||
var language: String? = null
|
||||
|
||||
/**
|
||||
* [com.intellij.openapi.application.ApplicationNamesInfo.getProductName]
|
||||
*/
|
||||
@Attribute("defaultProductName")
|
||||
var defaultProductName: String? = null
|
||||
|
||||
@Attribute("implementationClass")
|
||||
var implementationClass: String? = null
|
||||
|
||||
constructor() : super()
|
||||
|
||||
@TestOnly
|
||||
constructor(language: String, instance: LangSupport) : super(instance) {
|
||||
this.language = language
|
||||
}
|
||||
|
||||
|
||||
fun getLang(): String = language ?: error("Language must be specified for bean: $implementationClass")
|
||||
|
||||
override fun getImplementationClassName() = implementationClass
|
||||
}
|
||||
@@ -25,9 +25,9 @@ private class FeaturesTrainerSettingsPanel : BoundConfigurable(LearnBundle.messa
|
||||
.map { LanguageOption(it) }
|
||||
comboBox(options)
|
||||
.bindItem({
|
||||
val languageName = LangManager.getInstance().state.languageName
|
||||
options.find { it.id == languageName } ?: options[0]
|
||||
}, { language -> resetPrimaryLanguage(languagesExtensions.first { it.language == language?.id }.instance) })
|
||||
val languageId = LangManager.getInstance().getLanguageId()
|
||||
options.find { it.id == languageId } ?: options[0]
|
||||
}, { language -> language?.let { resetPrimaryLanguage(it.id) } })
|
||||
}
|
||||
}
|
||||
row {
|
||||
|
||||
@@ -64,7 +64,8 @@ open class OnboardingLessonPromoter(@NonNls private val lessonId: String,
|
||||
logger<OnboardingLessonPromoter>().error("No lesson with id $lessonId")
|
||||
return
|
||||
}
|
||||
val primaryLanguage = lesson.module.primaryLanguage ?: error("No primary language for promoting lesson ${lesson.name}")
|
||||
val primaryLanguage: String = lesson.module.primaryLanguage?.primaryLanguage
|
||||
?: error("No primary language for promoting lesson ${lesson.name}")
|
||||
resetPrimaryLanguage(primaryLanguage)
|
||||
LangManager.getInstance().getLangSupport()?.startFromWelcomeFrame { selectedSdk: Sdk? ->
|
||||
OpenLessonActivities.openOnboardingFromWelcomeScreen(lesson, selectedSdk)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package training.util
|
||||
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class LazyWeakReferenceDelegator<T>(private val objGetter: () -> T?) : ReadOnlyProperty<Any?, T?> {
|
||||
private var reference: WeakReference<T>? = null
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
|
||||
if (reference == null) {
|
||||
reference = WeakReference(objGetter())
|
||||
}
|
||||
return reference?.get()
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
reference = null
|
||||
}
|
||||
}
|
||||
@@ -104,11 +104,11 @@ internal fun clearTrainingProgress() {
|
||||
LearningUiManager.activeToolWindow = null
|
||||
}
|
||||
|
||||
internal fun resetPrimaryLanguage(activeLangSupport: LangSupport): Boolean {
|
||||
val old = LangManager.getInstance().getLangSupport()
|
||||
if (activeLangSupport != old) {
|
||||
internal fun resetPrimaryLanguage(newLanguageId: String): Boolean {
|
||||
val oldLanguageId = LangManager.getInstance().getLanguageId()
|
||||
if (newLanguageId != oldLanguageId) {
|
||||
LessonManager.instance.stopLesson()
|
||||
LangManager.getInstance().updateLangSupport(activeLangSupport)
|
||||
LangManager.getInstance().updateLangSupport(newLanguageId)
|
||||
LearningUiManager.activeToolWindow?.setModulesPanel()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package training.simple
|
||||
|
||||
import com.intellij.lang.LanguageExtensionPoint
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.DefaultPluginDescriptor
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
@@ -10,6 +9,7 @@ import com.intellij.testFramework.registerExtension
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import training.lang.LangSupport
|
||||
import training.lang.LangSupportBean
|
||||
import training.learn.course.LearningCourse
|
||||
|
||||
abstract class LessonsAndTipsIntegrationTest : BasePlatformTestCase() {
|
||||
@@ -22,9 +22,9 @@ abstract class LessonsAndTipsIntegrationTest : BasePlatformTestCase() {
|
||||
|
||||
val langId = languageId
|
||||
val langSupport = languageSupport
|
||||
val EP_NAME = ExtensionPointName<LanguageExtensionPoint<LangSupport>>(LangSupport.EP_NAME)
|
||||
val EP_NAME = ExtensionPointName<LangSupportBean>(LangSupport.EP_NAME)
|
||||
if (langId != null && langSupport != null && EP_NAME.extensionList.find { it.language == langId } == null) {
|
||||
val langExtension = LanguageExtensionPoint(langId, langSupport)
|
||||
val langExtension = LangSupportBean(langId, langSupport)
|
||||
// specify fake descriptor because it is required to be not null, but will not be used, because extension instance already created
|
||||
langExtension.pluginDescriptor = DefaultPluginDescriptor("")
|
||||
ApplicationManager.getApplication().registerExtension(EP_NAME, langExtension, testRootDisposable)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="training">
|
||||
<ift.language.extension language="Python" implementationClass="com.jetbrains.python.ift.PythonLangSupport"/>
|
||||
<ift.language.extension language="Python" defaultProductName="PyCharm"
|
||||
implementationClass="com.jetbrains.python.ift.PythonLangSupport"/>
|
||||
<ift.learning.course language="Python" implementationClass="com.jetbrains.python.ift.PythonLearningCourse"/>
|
||||
<ifs.suggesterSupport language="Python" implementationClass="com.jetbrains.python.ifs.PythonSuggesterSupport"/>
|
||||
</extensions>
|
||||
|
||||
Reference in New Issue
Block a user