I work on a Kotlin project that also uses Kotlin scripts (embedded as resources). The Kotlin script files are evaluated with some context, i.e. with variables bound. As a result, the plain script does not compile / run by itself (Ctrl+Shift+F10 on Windows), and either does auto-completion work.
Is there a way to tell the IDE about the context in which the script is run, i.e. which variables will be bound at runtime, so that the IDE will be able to perform auto-completion when working on the script inside the IDE?
(Sorry for the late answer, seems we overlooked your question here).
I assume that you’re setting the context by using your own script definition, either by having the variables passed in the base class constructor, or passing it in the configuration as provided properties. If it is done differently, please explain how.
To make autocompletion work, you need to supply Intellij with your script definition. The easiest way is to put the jar with the script definition and discovery file to the module’s classpath, and put the script into sources. Or you can write an intellij plugin that supplies the jars to idea - in this case you can have your script in any location. And as a substitution (or workaround) for the latter, you can specify the FQN of your definition class along with the classpath needed to load it in the kotlin compiler settings → “Kotlin scripting” in Intellij.
We are working on the other ways to configure scripting in the IDE too.
I’m setting context (and I mean context in the literal sense, not javax.script.ScriptContext) by two means:
binding variables via engine.put()
adding preface / postface literal text to the main script to execute
As the project in question is Open Source, let me give you some pointers. This is an example for an embedded script that, if open in the IDE, lights up red like a Christmas tree due to undefined variables:
What you would need to do is to generate/create mock classes that provide the symbols you expect. You can then mark this mock project/jar as a “provided” or “compileOnly” dependency of the script so that it can work. It may require you to put the script in a proper module though (not in resource).
It is quite unlikely that we’ll be able to support a variant with script text modifications in the IDE any time soon (although there is some functionality in the pipeline that can substitute it at least partially).
But at the current stage, you can achieve the same thing using the different approach. It might be a bit complicated though:
@KotlinScript(fileExtension = "custom.ext", compilationConfiguration = ScriptConfiguration::class)
abstract class MyScript(val bindings: Map<String, Any?>) {
val ortResult = bindings["ortResult"] as OrtResult
val evalErrors = mutableListOf<OrtIssue>()
}
object ScriptConfiguration : ScriptCompilationConfiguration(
{
defaultImports("com.here.ort.model.*", "java.util.*")
ide {
acceptedLocations(ScriptAcceptedLocation.Everywhere)
}
})
It is a good idea to have a dedicated extension for your scripts (“custom.ext” in the example above), since IDE distinguish scripts by the extension.
Then you’ll need to create your own JSR-223 factory the same way as here - kotlin/KotlinJsr223ScriptEngineFactoryExamples.kt at master · JetBrains/kotlin · GitHub, but use your script definition (MyScript) in place of KotlinStandardJsr223ScriptTemplate. You probably can do it in the same jar. And you need to register it in the services folder, of course.
You’ll still need a postface part in your evaluator though, but it seems not relevant to the IDE.
Then finally you need to supply Intellij with the definition. The simplest ad-hoc way to do it is to specify the FQN of your definition class along with the classpath needed to load it in the kotlin compiler settings → “Kotlin scripting” in Intellij.
I do have a similar problem but I do not have a real “template” to use. My code to invoke a script is:
val result = host.eval(
InputStreamReader(`is`).readText().toScriptSource(),
ScriptCompilationConfiguration {
baseClass(IntegrationConfiguration::class)
jvm {
//
// This is needed as workaround for:
// https://youtrack.jetbrains.com/issue/KT-27497
//
javaHome(File(javaHome))
//
// The Kotlin script compiler does not inherit
// the classpath by default
//
dependenciesFromClassloader(wholeClasspath = true)
}
},
ScriptEvaluationConfiguration {
//
// Arguments used to initialize the script base class
//
constructorArgs(registry, builder)
}
)
So when I edit my kotlin script, there’s no auto completion even if I add IntegrationConfiguration as script template class.
This looks very interesting, but currently i’m not sure how to implement this. In your example you’re using:
ide {
acceptedLocations(ScriptAcceptedLocation.Everywhere)
}
But this seems not to be in official maven repositories but only in kontlin-dev repository. But i wasn’t able to use it (version 1.3.30-dev-576 from bintray) because of missing dependecies for thist version in the repository (despite the warning that the kotlin-gradle-plugin won’t fit the Intellij Idea version). Earlier versions i’ve tried led me to a 401-Not-Authorized.
But maybe i’m trying all this too naive. I do apologize for this.
@lburgazzoli, you need to move your ScriptCompilationConfiguration into an object is in my sample above and reference it in the @KotlinScriptannotation, with which your IntegrationConfiguration is (should be) annotated. Then if IDEA will pick your template, it should offer appropriate highlighting/completion.
But it makes sense to replace your dependenciesFromClassloader in the configuration with specific dependencies, otherwise, you’ll likely get different classpath on the runtime and in the IDE.
(although taking into account the missing acceptedLocations configuration key in the public Kotlin releases, by default it will work only for the scripts in source roots; so maybe it is better to wait until 1.3.20)
I am trying to get camel-k kotlin script autocomplete working in intellij but I don’t know how to configure the Script Template Classes and Script templates classpath.
This thread seems to be the only one that covers this! Any help would be appreciated.
I have org.apache.camel.k.loader.kotlin.dsl.IntegrationConfiguration in Compiler → Kotlin Complier → Kotlin Script → Script template classes
and /Users/dylan/.m2/repository/org/apache/camel/k/camel-k-loader-kotlin/1.0.9/ in Compiler → Kotlin Complier → Kotlin Script → Script template classpath
but autocomplete is still not working.
Is there a way to see error messages from intellij to see what is wrong?
@sschuberth are you still able to get autocompletion working without setting the options in IDEA? I am trying to achieve the same thing (autocompletion for a custom script inside the IDE).
as well as making sure the script definition project (":script") has been compiled.
I am thinking that I must have missed something – or that how IDEA discovers definitions has changed in recent versions of the kotlin plugin, in particular following your latest post from December '21.