diff --git a/plugins/ide-features-trainer/src/training/learn/CourseManager.kt b/plugins/ide-features-trainer/src/training/learn/CourseManager.kt index b19b940fcd38..74c83dbf1cb9 100644 --- a/plugins/ide-features-trainer/src/training/learn/CourseManager.kt +++ b/plugins/ide-features-trainer/src/training/learn/CourseManager.kt @@ -16,10 +16,7 @@ import com.intellij.util.KeyedLazyInstanceEP import com.intellij.util.containers.MultiMap import training.lang.LangManager import training.lang.LangSupport -import training.learn.course.IftModule -import training.learn.course.LearningCourse -import training.learn.course.LearningCourseBase -import training.learn.course.Lesson +import training.learn.course.* import training.learn.lesson.LessonManager import training.statistic.LessonStartingWay import training.util.* @@ -79,10 +76,10 @@ class CourseManager internal constructor() : Disposable { } } - val currentCourse: LearningCourse? + val currentCourses: List get() = LangManager.getInstance().getLanguageId()?.let { lang -> - COURSE_MODULES_EP.extensionList.find { lang.equals(it.language, ignoreCase = true) }?.instance - } + getLanguageEPs(getLanguageToEPs(), lang).map { it.instance } + } ?: emptyList() override fun dispose() { } @@ -138,15 +135,28 @@ class CourseManager internal constructor() : Disposable { } private fun reloadLangModules() { - val extensions = COURSE_MODULES_EP.extensions.filter { courseCanBeUsed(it.language) } - for (e in extensions) { - val langSupport = LangManager.getInstance().getLangSupportById(e.language) - if (langSupport != null) { + val languageToEPs = getLanguageToEPs() + for (languageId in languageToEPs.keys) { + val langSupport = LangManager.getInstance().getLangSupportById(languageId) ?: continue + for (e in getLanguageEPs(languageToEPs, languageId)) { languageCourses.putValues(langSupport, createModules(e.instance, e.pluginDescriptor)) } } } + private fun getLanguageToEPs(): Map>> { + return COURSE_MODULES_EP.extensions.groupBy { it.language }.filterKeys { courseCanBeUsed(it) } + } + + private fun getLanguageEPs(map: Map>>, languageId: String): List> { + return map[languageId]?.let { + val replacingCourse = it.firstOrNull { extensionPoint -> + extensionPoint.instance.otherCoursesMergeStrategy() == LearningCoursesMergeStrategy.REPLACE_MODULES + } + if (replacingCourse != null) listOf(replacingCourse) else it + } ?: emptyList() + } + private fun reloadCommonModules() { val commonCoursesExtensions = COMMON_COURSE_MODULES_EP.extensions for (e in commonCoursesExtensions) { diff --git a/plugins/ide-features-trainer/src/training/learn/course/LearningCourse.kt b/plugins/ide-features-trainer/src/training/learn/course/LearningCourse.kt index 38095d9026fe..4aeda1957046 100644 --- a/plugins/ide-features-trainer/src/training/learn/course/LearningCourse.kt +++ b/plugins/ide-features-trainer/src/training/learn/course/LearningCourse.kt @@ -1,11 +1,22 @@ // 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 training.learn.course +import org.jetbrains.annotations.ApiStatus + interface LearningCourse { fun modules(): Collection + @ApiStatus.Internal + fun otherCoursesMergeStrategy(): LearningCoursesMergeStrategy = LearningCoursesMergeStrategy.ADD_MODULES + /** * @return map of lesson id to the list of suitable [com.intellij.ide.util.TipAndTrickBean.getId] */ fun getLessonIdToTipsMap(): Map> = emptyMap() +} + +@ApiStatus.Internal +enum class LearningCoursesMergeStrategy { + ADD_MODULES, + REPLACE_MODULES } \ No newline at end of file diff --git a/plugins/ide-features-trainer/src/training/ui/IftTipAndTrickPromoter.kt b/plugins/ide-features-trainer/src/training/ui/IftTipAndTrickPromoter.kt index 2cb202ea4c44..a96dd7acbd79 100644 --- a/plugins/ide-features-trainer/src/training/ui/IftTipAndTrickPromoter.kt +++ b/plugins/ide-features-trainer/src/training/ui/IftTipAndTrickPromoter.kt @@ -19,7 +19,6 @@ import com.intellij.util.ui.JBUI import com.intellij.util.ui.UIUtil import training.learn.CourseManager import training.learn.LearnBundle -import training.learn.course.LearningCourse import training.statistic.LessonStartingWay import training.statistic.StatisticBase import training.util.enableLessonsAndPromoters @@ -36,9 +35,8 @@ private class IftTipAndTrickPromoter : TipAndTrickPromotionFactory { } private fun findLessonIdForTip(tip: TipAndTrickBean): String? { - val course: LearningCourse = CourseManager.instance.currentCourse ?: return null - val lessonIdToTipsMap = course.getLessonIdToTipsMap() - val lessonIds = lessonIdToTipsMap.filterValues { it.contains(tip.id) }.keys + val lessonIdToTipsMaps = CourseManager.instance.currentCourses.map { it.getLessonIdToTipsMap() } + val lessonIds = lessonIdToTipsMaps.map { it.filterValues { tipIds -> tipIds.contains(tip.id) }.keys }.flatten() if (lessonIds.isNotEmpty()) { if (lessonIds.size > 1) { thisLogger().warn("$tip declared as suitable in more than one lesson: $lessonIds")