CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlin--kotlin-daemon-client

Client library for communicating with the Kotlin compilation daemon, enabling remote compilation services and incremental compilation workflows.

Pending
Overview
Eval results
Files

repl-client.mddocs/

REPL Client

Interactive Kotlin compilation and evaluation through the daemon with state management and history tracking. Provides a complete REPL (Read-Eval-Print Loop) implementation for interactive Kotlin development.

Capabilities

KotlinRemoteReplCompilerClient

Main REPL client class that provides interactive compilation capabilities through the daemon.

/**
 * Remote REPL compiler client for interactive Kotlin compilation
 * @param compileService The daemon service to use
 * @param clientAliveFlagFile File indicating client is alive (optional)
 * @param targetPlatform Target platform for compilation
 * @param args Compiler arguments and configuration
 * @param messageCollector Handles compiler messages
 * @param templateClasspath Classpath for REPL template
 * @param templateClassName Name of the REPL template class
 * @param port Port for service communication
 */
class KotlinRemoteReplCompilerClient(
    protected val compileService: CompileService,
    clientAliveFlagFile: File?,
    targetPlatform: CompileService.TargetPlatform,
    args: Array<out String>,
    messageCollector: MessageCollector,
    templateClasspath: List<File>,
    templateClassName: String,
    port: Int = SOCKET_ANY_FREE_PORT
) : ReplCompiler {
    val services: BasicCompilerServicesWithResultsFacadeServer
    val sessionId: Int
}

Usage Example:

import org.jetbrains.kotlin.daemon.client.KotlinRemoteReplCompilerClient
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import java.io.File

val compileService = KotlinCompilerClient.connectToCompileService(...)
val messageCollector = PrintingMessageCollector(System.out, null, false)
val templateClasspath = listOf(File("/path/to/kotlin-stdlib.jar"))

val replClient = KotlinRemoteReplCompilerClient(
    compileService = compileService,
    clientAliveFlagFile = File("/tmp/repl-client.flag"),
    targetPlatform = CompileService.TargetPlatform.JVM,
    args = arrayOf("-classpath", "/path/to/libs/*"),
    messageCollector = messageCollector,
    templateClasspath = templateClasspath,
    templateClassName = "kotlin.script.templates.standard.ScriptTemplateWithArgs"
)

try {
    // Create REPL state
    val lock = ReentrantReadWriteLock()
    val state = replClient.createState(lock)
    
    // Evaluate REPL lines
    val codeLine1 = ReplCodeLine(0, 0, "val x = 42")
    val checkResult1 = replClient.check(state, codeLine1)
    
    if (checkResult1 is ReplCheckResult.Ok) {
        val compileResult1 = replClient.compile(state, codeLine1)
        println("Result: $compileResult1")
    }
    
    val codeLine2 = ReplCodeLine(1, 1, "println(\"x = \$x\")")
    val checkResult2 = replClient.check(state, codeLine2)
    
    if (checkResult2 is ReplCheckResult.Ok) {
        val compileResult2 = replClient.compile(state, codeLine2)
        println("Result: $compileResult2")
    }
    
} finally {
    replClient.dispose()
}

REPL State Management

Creates and manages REPL execution state with thread-safe access.

/**
 * Create a new REPL state for managing compilation context
 * @param lock Read-write lock for thread-safe state access
 * @return REPL state instance
 */
fun createState(lock: ReentrantReadWriteLock): IReplStageState<*>

Code Checking

Checks REPL code lines for syntax and semantic errors without compilation.

/**
 * Check a REPL code line for errors without compiling
 * @param state The REPL state to check against
 * @param codeLine The code line to check
 * @return Check result indicating success or failure with diagnostics
 */
fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult

Code Compilation

Compiles and executes REPL code lines within the managed state.

/**
 * Compile and execute a REPL code line
 * @param state The REPL state for compilation context
 * @param codeLine The code line to compile
 * @return Compilation result with execution outcome
 */
fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult

Resource Cleanup

Properly disposes of REPL resources and releases daemon session.

/**
 * Dispose REPL client and free resources
 * Should be called at the end of REPL lifetime
 */
fun dispose()

REPL State Classes

RemoteReplCompilerState

Manages REPL compilation state with history and generation tracking.

/**
 * Remote REPL compiler state implementation
 * @param replStateFacade Interface to the remote REPL state
 * @param lock Thread synchronization lock
 */
class RemoteReplCompilerState(
    internal val replStateFacade: ReplStateFacade,
    override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) : IReplStageState<Unit> {
    override val currentGeneration: Int
    override val history: IReplStageHistory<Unit>
}

RemoteReplCompilerStateHistory

Manages REPL execution history with navigation and reset capabilities.

/**
 * REPL state history management
 * @param state The REPL state this history belongs to
 */
class RemoteReplCompilerStateHistory(
    private val state: RemoteReplCompilerState
) : IReplStageHistory<Unit>, AbstractList<ReplHistoryRecord<Unit>>() {
    override val size: Int
    val currentGeneration: AtomicInteger
    override val lock: ReentrantReadWriteLock
}

History Operations

/**
 * Get history record at index
 * @param index The history index
 * @return History record at the specified index
 */
fun get(index: Int): ReplHistoryRecord<Unit>

/**
 * Push new item to history (not supported for remote history)
 * @param id Line identifier
 * @param item History item
 */
fun push(id: ILineId, item: Unit)

/**
 * Pop last item from history (not supported for remote history)  
 * @return Last history record or null
 */
fun pop(): ReplHistoryRecord<Unit>?

/**
 * Reset history to initial state
 * @return Iterable of removed line IDs
 */
fun reset(): Iterable<ILineId>

/**
 * Reset history to specific line ID
 * @param id Target line ID to reset to
 * @return Iterable of removed line IDs
 */
fun resetTo(id: ILineId): Iterable<ILineId>

Usage Patterns

Basic REPL Session

val replClient = KotlinRemoteReplCompilerClient(...)
val lock = ReentrantReadWriteLock()
val state = replClient.createState(lock)

try {
    var lineNumber = 0
    
    // Read-eval-print loop
    while (true) {
        print("kotlin> ")
        val input = readLine() ?: break
        
        if (input.trim() == ":quit") break
        
        val codeLine = ReplCodeLine(lineNumber++, lineNumber, input)
        
        // Check syntax first
        when (val checkResult = replClient.check(state, codeLine)) {
            is ReplCheckResult.Ok -> {
                // Compile and execute
                when (val compileResult = replClient.compile(state, codeLine)) {
                    is ReplCompileResult.Ok -> {
                        // Print result if available
                        compileResult.data.let { data ->
                            if (data.result != null) {
                                println("res${lineNumber}: ${data.result}")
                            }
                        }
                    }
                    is ReplCompileResult.Error -> {
                        println("Compilation error: ${compileResult.message}")
                    }
                }
            }
            is ReplCheckResult.Error -> {
                println("Syntax error: ${checkResult.message}")
            }
        }
    }
} finally {
    replClient.dispose()
}

REPL with History Management

val replClient = KotlinRemoteReplCompilerClient(...)
val state = replClient.createState(ReentrantReadWriteLock())

try {
    // Execute some code
    val lines = listOf(
        "val x = 10",
        "val y = 20", 
        "val sum = x + y",
        "println(sum)"
    )
    
    lines.forEachIndexed { index, code ->
        val codeLine = ReplCodeLine(index, index, code)
        replClient.check(state, codeLine)
        replClient.compile(state, codeLine)
    }
    
    // Check history
    val history = state.history
    println("History size: ${history.size}")
    
    // Reset to a previous state
    if (history.size >= 2) {
        val secondLineId = history[1].id
        val removedIds = history.resetTo(secondLineId)
        println("Removed lines: $removedIds")
    }
    
} finally {
    replClient.dispose()
}

REPL with Error Handling

class ReplErrorHandler(private val replClient: KotlinRemoteReplCompilerClient) {
    fun evaluateLine(state: IReplStageState<*>, code: String, lineId: Int): String {
        val codeLine = ReplCodeLine(lineId, lineId, code)
        
        return try {
            when (val checkResult = replClient.check(state, codeLine)) {
                is ReplCheckResult.Ok -> {
                    when (val compileResult = replClient.compile(state, codeLine)) {
                        is ReplCompileResult.Ok -> {
                            compileResult.data.result?.toString() ?: "OK"
                        }
                        is ReplCompileResult.Error -> {
                            "Compilation Error: ${compileResult.message}"
                        }
                        else -> "Unknown compilation result: $compileResult"
                    }
                }
                is ReplCheckResult.Error -> {
                    "Check Error: ${checkResult.message}"
                }
                else -> "Unknown check result: $checkResult"
            }
        } catch (e: Exception) {
            "Exception: ${e.message}"
        }
    }
}

val errorHandler = ReplErrorHandler(replClient)
val result = errorHandler.evaluateLine(state, "val invalid syntax", 0)
println(result)

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-daemon-client

docs

compilation-services.md

daemon-connection.md

index.md

repl-client.md

service-facades.md

stream-servers.md

tile.json