@@ -3,6 +3,8 @@ package org.hyperskill.academy.learning.yaml
33import com.intellij.openapi.application.ApplicationManager
44import com.intellij.openapi.project.Project
55import com.intellij.openapi.util.Key
6+ import com.intellij.openapi.vfs.VfsUtil
7+ import com.intellij.openapi.vfs.VirtualFile
68import org.hyperskill.academy.learning.StudyTaskManager
79import org.hyperskill.academy.learning.guessCourseDir
810import org.hyperskill.academy.learning.isUnitTestMode
@@ -12,8 +14,11 @@ object YamlFormatSettings {
1214 private val YAML_IS_EDU_PROJECT : Key <Boolean > = Key .create(" EDU.yaml_is_edu_project" )
1315
1416 /* *
15- * Determines whether current project looks like an Edu YAML project by checking
16- * if course config file exists in the project (course) root.
17+ * Determines whether current project is a Hyperskill course project by checking
18+ * if course config file exists and has type "hyperskill".
19+ *
20+ * Non-Hyperskill course types (like "coursera", "pycharm", etc.) are handled by
21+ * other plugins (e.g., JetBrains Academy plugin) and should be ignored here.
1722 *
1823 * IMPORTANT: Avoids VFS access on EDT. On UI thread, returns cached value if present
1924 * or schedules background computation and returns false as a conservative default.
@@ -26,7 +31,7 @@ object YamlFormatSettings {
2631 return if (app.isDispatchThread) {
2732 // Don't touch VFS on EDT. Compute in background and cache for subsequent calls.
2833 app.executeOnPooledThread {
29- val result = guessCourseDir()?.findChild( COURSE_CONFIG ) != null
34+ val result = isHyperskillCourseProject()
3035 putUserData(YAML_IS_EDU_PROJECT , result)
3136 if (result) {
3237 // Trigger StudyTaskManager initialization to load course once detection is ready
@@ -37,12 +42,37 @@ object YamlFormatSettings {
3742 false
3843 }
3944 else {
40- val result = guessCourseDir()?.findChild( COURSE_CONFIG ) != null
45+ val result = isHyperskillCourseProject()
4146 putUserData(YAML_IS_EDU_PROJECT , result)
4247 result
4348 }
4449 }
4550
51+ /* *
52+ * Checks if the project contains a Hyperskill course by examining the course config file.
53+ * Returns true only for courses with type "hyperskill".
54+ */
55+ private fun Project.isHyperskillCourseProject (): Boolean {
56+ val courseConfig = guessCourseDir()?.findChild(COURSE_CONFIG ) ? : return false
57+ return isHyperskillCourseConfig(courseConfig)
58+ }
59+
60+ /* *
61+ * Parses the course config file to check if it's a Hyperskill course (type: hyperskill).
62+ * Uses simple text parsing to avoid full YAML deserialization overhead.
63+ */
64+ private fun isHyperskillCourseConfig (configFile : VirtualFile ): Boolean {
65+ return try {
66+ val content = VfsUtil .loadText(configFile)
67+ // Look for "type: hyperskill" or "type:hyperskill" at the beginning of a line
68+ val typeRegex = """ (?m)^type:\s*hyperskill\s*$""" .toRegex()
69+ typeRegex.containsMatchIn(content)
70+ }
71+ catch (e: Exception ) {
72+ false
73+ }
74+ }
75+
4676 // it is here because it's used in test and main code
4777 val YAML_TEST_PROJECT_READY = Key <Boolean >(" EDU.yaml_test_project_ready" )
4878 val YAML_TEST_THROW_EXCEPTION = Key <Boolean >(" EDU.yaml_test_throw_exception" )
0 commit comments