diff --git a/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt b/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt index 0d01a73b80a..7915a6ee1c2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource import kotlin.script.experimental.api.ScriptDiagnostic +import kotlin.script.experimental.api.ScriptEvaluationConfiguration import kotlin.script.experimental.intellij.ScriptDefinitionsProvider import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration @@ -25,19 +26,28 @@ class BridgeScriptDefinitionsContributor(private val project: Project) : ScriptD return extensions.asSequence().flatMap { provider -> val explicitClasses = provider.getDefinitionClasses().toList() val classPath = provider.getDefinitionsClassPath().toList() - val hostConfiguration = defaultJvmScriptingHostConfiguration + val baseHostConfiguration = defaultJvmScriptingHostConfiguration + // TODO: rewrite load and discovery to return kotlin.script.experimental.host.ScriptDefinition to avoid unnecessary conversions val explicitDefinitions = if (explicitClasses.isEmpty()) emptySequence() - else loadDefinitionsFromTemplates(explicitClasses, classPath, hostConfiguration).asSequence() + else loadDefinitionsFromTemplates(explicitClasses, classPath, baseHostConfiguration).asSequence() val discoveredDefinitions = if (provider.useDiscovery()) ScriptDefinitionsFromClasspathDiscoverySource( classPath, - hostConfiguration, + baseHostConfiguration, ::loggingReporter ).definitions else emptySequence() - explicitDefinitions + discoveredDefinitions + val loadedDefinitions = (explicitDefinitions + discoveredDefinitions).map { + kotlin.script.experimental.host.ScriptDefinition( + it.compilationConfiguration, + it.evaluationConfiguration ?: ScriptEvaluationConfiguration.Default + ) + }.toList() + provider.provideDefinitions(baseHostConfiguration, loadedDefinitions).map { + ScriptDefinition.FromNewDefinition(baseHostConfiguration, it) + }.asSequence() } } } diff --git a/libraries/scripting/intellij/src/kotlin/script/experimental/intellij/scriptDefinitionProvider.kt b/libraries/scripting/intellij/src/kotlin/script/experimental/intellij/scriptDefinitionProvider.kt index bc56fa70507..dc7276fa583 100644 --- a/libraries/scripting/intellij/src/kotlin/script/experimental/intellij/scriptDefinitionProvider.kt +++ b/libraries/scripting/intellij/src/kotlin/script/experimental/intellij/scriptDefinitionProvider.kt @@ -6,22 +6,55 @@ package kotlin.script.experimental.intellij import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.extensions.Extensions -import com.intellij.openapi.project.Project import java.io.File +import kotlin.script.experimental.host.ScriptDefinition +import kotlin.script.experimental.host.ScriptingHostConfiguration +/** + * IntelliJ extension point for providing script definitions + * + * The scripting infrastructure will load this extension point on project instantiation, and then collect all definitions + * provided by the extension point, combining 3 ways, depending on the data returned from the interface members: + * - for all FQNs of classes returned from the [getDefinitionClasses] function, it will load the class with the classpath from + * the [getDefinitionsClassPath] and create it's definition from the KotlinScript annotation + * - if [useDiscovery] method returns true, the classpath returned by [getDefinitionsClassPath] will be scanned for the discovery + * markers, and found script definitions will be loaded and created the same way as ones returned from [getDefinitionClasses] + * After collecting all definitions will be passed to the [provideDefinitions] for possible modifications. The implementation + * may also remove or add new definitions at this point. + * Processed definitions are provided to the scripting support infrastructure. + */ interface ScriptDefinitionsProvider { + /** + * A display name used to identify particular providers + */ val id: String + /** + * Should return a list of the FQNs of the script definition template classes to load explicitly, if any + */ fun getDefinitionClasses(): Iterable + /** + * Should return a classpath required for loading script definition template classes + */ fun getDefinitionsClassPath(): Iterable + /** + * if returns true, the IntelliJ will scan the classpath from [getDefinitionClasses] to discover script definition templates + * using definition markers in the "META-INF/kotlin/script/templates/" folder + */ fun useDiscovery(): Boolean + /** + * The callback to update/add/remove script definitions after loading, if needed + */ + fun provideDefinitions( + baseHostConfiguration: ScriptingHostConfiguration, + loadedScriptDefinitions: List + ): Iterable = loadedScriptDefinitions + companion object { val EP_NAME: ExtensionPointName = - ExtensionPointName.create("org.jetbrains.kotlin.scriptDefinitionsProvider") + ExtensionPointName.create("org.jetbrains.kotlin.scriptDefinitionsProvider") } - } diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt index 86942920986..2dd7b4b43ef 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt @@ -178,14 +178,10 @@ abstract class ScriptDefinition : UserDataHolderBase() { override val evaluationConfiguration: ScriptEvaluationConfiguration? ) : FromConfigurationsBase() - open class FromTemplate( + open class FromNewDefinition( private val baseHostConfiguration: ScriptingHostConfiguration, - template: KClass<*>, - contextClass: KClass<*> = ScriptCompilationConfiguration::class + private val definition: kotlin.script.experimental.host.ScriptDefinition ) : FromConfigurationsBase() { - - private val definition = createScriptDefinitionFromTemplate(KotlinType(template), baseHostConfiguration, contextClass) - override val hostConfiguration: ScriptingHostConfiguration get() = definition.compilationConfiguration[ScriptCompilationConfiguration.hostConfiguration] ?: baseHostConfiguration @@ -193,6 +189,15 @@ abstract class ScriptDefinition : UserDataHolderBase() { override val evaluationConfiguration: ScriptEvaluationConfiguration get() = definition.evaluationConfiguration } + open class FromTemplate( + baseHostConfiguration: ScriptingHostConfiguration, + template: KClass<*>, + contextClass: KClass<*> = ScriptCompilationConfiguration::class + ) : FromNewDefinition( + baseHostConfiguration, + createScriptDefinitionFromTemplate(KotlinType(template), baseHostConfiguration, contextClass) + ) + companion object { fun getDefault(hostConfiguration: ScriptingHostConfiguration) = object : FromLegacy(hostConfiguration, StandardScriptDefinition) {