diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index 350cc95bd46..d4793b922af 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -18,10 +18,13 @@ package org.jetbrains.kotlin.idea.core.script import com.intellij.ide.projectView.impl.ProjectRootsUtil.isInTestSource import com.intellij.ide.scratch.ScratchFileService +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.fileTypes.FileTypeManager import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.ProjectJdkTable @@ -29,21 +32,18 @@ import com.intellij.openapi.projectRoots.ex.PathUtilEx import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.caches.project.SdkInfo import org.jetbrains.kotlin.idea.caches.project.getScriptRelatedModuleInfo -import org.jetbrains.kotlin.script.* -import org.jetbrains.kotlin.scripting.compiler.plugin.KotlinScriptDefinitionAdapterFromNewAPI import org.jetbrains.kotlin.idea.util.ProjectRootsUtil.isInContent import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.script.KotlinScriptDefinition -import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate -import org.jetbrains.kotlin.script.ScriptDefinitionProvider -import org.jetbrains.kotlin.script.ScriptTemplatesProvider +import org.jetbrains.kotlin.script.* +import org.jetbrains.kotlin.scripting.compiler.plugin.KotlinScriptDefinitionAdapterFromNewAPI +import org.jetbrains.kotlin.scripting.compiler.plugin.KotlinScriptDefinitionAdapterFromNewAPIBase import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.flattenTo import java.io.File -import java.lang.reflect.InvocationTargetException import java.net.URLClassLoader import kotlin.concurrent.write import kotlin.script.dependencies.Environment @@ -133,6 +133,25 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit private fun updateDefinitions() { assert(lock.isWriteLocked) { "updateDefinitions should only be called under the write lock" } definitions = definitionsByContributor.values.flattenTo(mutableListOf()).asSequence() + + // Register new file extensions + val fileTypeManager = FileTypeManager.getInstance() + val extensions = definitions?.mapNotNull { definition -> + (definition as? KotlinScriptDefinitionAdapterFromNewAPIBase) + ?.scriptFileExtensionWithDot?.removePrefix(".") + ?.takeIf { fileTypeManager.getFileTypeByExtension(it) != KotlinFileType.INSTANCE } + }?.toList() + + if (extensions?.isNotEmpty() == true) { + ApplicationManager.getApplication().invokeLater { + runWriteAction { + extensions.forEach { + fileTypeManager.associateExtension(KotlinFileType.INSTANCE, it) + } + } + } + } + clearCache() // TODO: clear by script type/definition ServiceManager.getService(project, ScriptDependenciesCache::class.java).clear() diff --git a/idea/testData/script/definition/highlighting/customExtension/mainModule/script.mykts b/idea/testData/script/definition/highlighting/customExtension/mainModule/script.mykts new file mode 100644 index 00000000000..b8a3500273d --- /dev/null +++ b/idea/testData/script/definition/highlighting/customExtension/mainModule/script.mykts @@ -0,0 +1 @@ +1 + "a" diff --git a/idea/testData/script/definition/highlighting/customExtension/mainModule/template/template.kt b/idea/testData/script/definition/highlighting/customExtension/mainModule/template/template.kt new file mode 100644 index 00000000000..5e054e8c6a1 --- /dev/null +++ b/idea/testData/script/definition/highlighting/customExtension/mainModule/template/template.kt @@ -0,0 +1,14 @@ +package custom.scriptDefinition + +import java.io.File +import kotlin.script.dependencies.* +import kotlin.script.experimental.dependencies.* +import kotlin.script.experimental.location.* +import kotlin.script.templates.ScriptTemplateDefinition +import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.annotations.KotlinScriptEvaluator +import kotlin.script.experimental.annotations.KotlinScriptFileExtension + +@KotlinScript("Kotlin Script with custom extension") +@KotlinScriptFileExtension("mykts") +open class Template \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt index 46fdfd2b4e7..61392573d68 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfoTest.kt @@ -27,6 +27,7 @@ import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.psi.PsiManager import com.intellij.testFramework.ModuleTestCase import com.intellij.testFramework.PlatformTestCase import com.intellij.testFramework.PsiTestUtil @@ -429,7 +430,9 @@ class IdeaModuleInfoTest : ModuleTestCase() { ) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported) private val VirtualFile.moduleInfo: IdeaModuleInfo - get() = getModuleInfoByVirtualFile(project, this)!! + get() { + return PsiManager.getInstance(project).findFile(this)!!.getModuleInfo() + } private val Module.production: ModuleProductionSourceInfo get() = productionSourceInfo()!! diff --git a/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationTest.kt b/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationTest.kt index e40da562431..ee4cd59d612 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/script/AbstractScriptConfigurationTest.kt @@ -31,6 +31,7 @@ import com.intellij.testFramework.PlatformTestCase import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.exceptionCases.AbstractExceptionCase +import com.intellij.util.ui.UIUtil import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.idea.completion.test.KotlinCompletionTestCase import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor @@ -46,6 +47,9 @@ import org.jetbrains.kotlin.test.util.addDependency import org.jetbrains.kotlin.test.util.projectLibrary import org.jetbrains.kotlin.test.util.renderAsGotoImplementation import org.jetbrains.kotlin.utils.PathUtil +import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR +import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMMON_JAR +import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR import org.junit.Assert import org.junit.ComparisonFailure import java.io.File @@ -63,7 +67,8 @@ abstract class AbstractScriptConfigurationHighlightingTest : AbstractScriptConfi checkHighlighting( editor, InTextDirectivesUtils.isDirectiveDefined(file.text, "// CHECK_WARNINGS"), - InTextDirectivesUtils.isDirectiveDefined(file.text, "// CHECK_INFOS")) + InTextDirectivesUtils.isDirectiveDefined(file.text, "// CHECK_INFOS") + ) } fun doComplexTest(path: String) { @@ -131,8 +136,13 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() { // do not create default module } - private fun findMainScript(testDir: String) = File(testDir).walkTopDown().find { it.name == SCRIPT_NAME } + private fun findMainScript(testDir: String): File { + val scriptFile = File(testDir).walkTopDown().find { it.name == SCRIPT_NAME } + if (scriptFile != null) return scriptFile + + return File(testDir).walkTopDown().singleOrNull { it.name.contains("script") } ?: error("Couldn't find $SCRIPT_NAME file in $testDir") + } protected fun configureScriptFile(path: String) { val mainScriptFile = findMainScript(path) @@ -217,9 +227,9 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() { private fun defaultEnvironment(path: String): Map { val templateOutDir = File("${path}template").takeIf { it.isDirectory }?.let { - compileLibToDir(it, PathUtil.kotlinPathsForDistDirectory.scriptRuntimePath.path) + compileLibToDir(it, *scriptClasspath()) } ?: File("idea/testData/script/definition/defaultTemplate").takeIf { it.isDirectory }?.let { - compileLibToDir(it, PathUtil.kotlinPathsForDistDirectory.scriptRuntimePath.path) + compileLibToDir(it, *scriptClasspath()) } val libSrcDir = File("${path}lib").takeIf { it.isDirectory } @@ -235,14 +245,24 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() { ) } + private fun scriptClasspath(): Array { + return with(PathUtil.kotlinPathsForDistDirectory) { + arrayOf( + File(libPath, KOTLIN_JAVA_SCRIPT_RUNTIME_JAR).path, + File(libPath, KOTLIN_SCRIPTING_COMMON_JAR).path, + File(libPath, KOTLIN_SCRIPTING_JVM_JAR).path + ) + } + } + private fun createFileAndSyncDependencies(scriptFile: File) { var script: VirtualFile? = null if (module != null) { - script = module.moduleFile?.parent?.findChild(SCRIPT_NAME) + script = module.moduleFile?.parent?.findChild(scriptFile.name) } if (script == null) { - val target = File(project.basePath, SCRIPT_NAME) + val target = File(project.basePath, scriptFile.name) scriptFile.copyTo(target) script = LocalFileSystem.getInstance().findFileByPath(target.path) } @@ -287,6 +307,9 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() { provider, testRootDisposable ) + ScriptDefinitionsManager.getInstance(project).reloadScriptDefinitions() + + UIUtil.dispatchAllInvocationEvents() } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java index 9a917878a01..a79c5558422 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/script/ScriptConfigurationHighlightingTestGenerated.java @@ -56,6 +56,11 @@ public class ScriptConfigurationHighlightingTestGenerated extends AbstractScript runTest("idea/testData/script/definition/highlighting/customBaseClass/"); } + @TestMetadata("customExtension") + public void testCustomExtension() throws Exception { + runTest("idea/testData/script/definition/highlighting/customExtension/"); + } + @TestMetadata("customLibrary") public void testCustomLibrary() throws Exception { runTest("idea/testData/script/definition/highlighting/customLibrary/"); diff --git a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt index 8f6326e00e9..4d03b2b94fe 100644 --- a/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt +++ b/plugins/scripting/scripting-cli/src/org/jetbrains/kotlin/scripting/compiler/plugin/KotlinScriptDefinitionAdapterFromNewAPI.kt @@ -24,7 +24,7 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit protected abstract val scriptDefinition: ScriptDefinition - protected abstract val scriptFileExtensionWithDot: String + abstract val scriptFileExtensionWithDot: String open val baseClass: KClass<*> by lazy(LazyThreadSafetyMode.PUBLICATION) { getScriptingClass(scriptDefinition.compilationConfigurator.defaultConfiguration[ScriptingEnvironmentProperties.baseClass])