org.jetbrains.kotlinx.jupyter.repl.ContextUpdater.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-jupyter-kernel Show documentation
Show all versions of kotlin-jupyter-kernel Show documentation
Kotlin Jupyter kernel published as artifact
The newest version!
package org.jetbrains.kotlinx.jupyter.repl
import jupyter.kotlin.KotlinContext
import jupyter.kotlin.KotlinFunctionInfo
import jupyter.kotlin.KotlinVariableInfo
import org.jetbrains.kotlinx.jupyter.api.KernelLoggerFactory
import org.jetbrains.kotlinx.jupyter.api.getLogger
import java.lang.reflect.Field
import kotlin.reflect.jvm.kotlinFunction
import kotlin.reflect.jvm.kotlinProperty
import kotlin.script.experimental.jvm.BasicJvmReplEvaluator
import kotlin.script.experimental.jvm.KJvmEvaluatedSnippet
import kotlin.script.experimental.util.LinkedSnippet
/**
* ContextUpdater updates current user-defined functions and variables
* to use in completion and KotlinContext.
*/
class ContextUpdater(
loggerFactory: KernelLoggerFactory,
val context: KotlinContext,
private val evaluator: BasicJvmReplEvaluator,
) {
private val logger = loggerFactory.getLogger(this::class)
private var lastProcessedSnippet: LinkedSnippet? = null
fun update() {
try {
var lastSnippet = evaluator.lastEvaluatedSnippet
val newSnippets = mutableListOf()
while (lastSnippet != lastProcessedSnippet && lastSnippet != null) {
val line = lastSnippet.get().result.scriptInstance
if (line != null) {
newSnippets.add(line)
}
lastSnippet = lastSnippet.previous
}
newSnippets.reverse()
refreshVariables(newSnippets)
refreshMethods(newSnippets)
lastProcessedSnippet = evaluator.lastEvaluatedSnippet
} catch (e: ReflectiveOperationException) {
logger.error("Exception updating current variables", e)
} catch (e: NullPointerException) {
logger.error("Exception updating current variables", e)
}
}
private fun refreshMethods(lines: List) {
for (line in lines) {
val methods = line.javaClass.methods
for (method in methods) {
if (objectMethods.contains(method) || method.name == "main") {
continue
}
val function = method.kotlinFunction ?: continue
context.addFunction(function.name, KotlinFunctionInfo(function, line))
}
}
}
@Throws(ReflectiveOperationException::class)
private fun refreshVariables(lines: List) {
for (line in lines) {
val fields = line.javaClass.declaredFields
findVariables(fields, line)
}
}
@Throws(IllegalAccessException::class)
private fun findVariables(
fields: Array,
o: Any,
) {
for (field in fields) {
val fieldName = field.name
if (fieldName.contains("$\$implicitReceiver") || fieldName.contains("script$")) {
continue
}
field.isAccessible = true
val value = field.get(o)
context.addVariable(fieldName, KotlinVariableInfo(value, field.kotlinProperty, field, o))
}
}
companion object {
private val objectMethods = HashSet(listOf(*Any::class.java.methods))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy