~
diff --git a/compiler/cli/build.gradle.kts b/compiler/cli/build.gradle.kts
index 7eead92..db5f700 100644
--- a/compiler/cli/build.gradle.kts
+++ b/compiler/cli/build.gradle.kts
@@ -23,6 +23,8 @@
     compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
     compileOnly(intellijDep()) { includeIntellijCoreJarDependencies(project) }
 
+    runtime(projectDist(":kotlin-reflect"))
+
     // Used in REPL code insight
     compileOnly(project(":idea:idea-core"))
 
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt
index c351a6e..cfbe9e8 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt
@@ -39,7 +39,7 @@
 import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
 import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
 import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
-import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
+import org.jetbrains.kotlin.cli.jvm.repl.KotlinRepl
 import org.jetbrains.kotlin.codegen.CompilationException
 import org.jetbrains.kotlin.config.*
 import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
@@ -103,7 +103,7 @@
                     messageCollector.report(ERROR, "Specify script source path to evaluate")
                     return COMPILATION_ERROR
                 }
-                ReplFromTerminal.run(rootDisposable, configuration)
+                KotlinRepl.run(rootDisposable, configuration)
                 return ExitCode.OK
             }
         }
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinRepl.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinRepl.kt
new file mode 100644
index 0000000..ba8e703
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/KotlinRepl.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl
+
+import com.intellij.openapi.Disposable
+import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
+import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
+import org.jetbrains.kotlin.cli.jvm.repl.configuration.ConsoleReplConfiguration
+import org.jetbrains.kotlin.cli.jvm.repl.configuration.ReplConfiguration
+import org.jetbrains.kotlin.cli.jvm.repl.configuration.IdeReplConfiguration
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplProcessor
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.config.KotlinCompilerVersion
+import java.util.concurrent.Callable
+import java.util.concurrent.Executors
+import java.util.concurrent.Future
+
+class KotlinRepl(
+        disposable: Disposable,
+        compilerConfiguration: CompilerConfiguration,
+        private val replConfiguration: ReplConfiguration
+) {
+    private val replInitializer: Future<ReplInterpreter> = Executors.newSingleThreadExecutor().submit(Callable {
+        ReplInterpreter(disposable, compilerConfiguration, replConfiguration)
+    })
+
+    private val replInterpreter: ReplInterpreter
+        get() = replInitializer.get()
+
+    val writer get() = replConfiguration.writer
+
+    private val messageCollector = compilerConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
+
+    private fun doRun() {
+        try {
+            with(writer) {
+                printlnWelcomeMessage(
+                    "Welcome to Kotlin version ${KotlinCompilerVersion.VERSION} " +
+                            "(JRE ${System.getProperty("java.runtime.version")})"
+                )
+                printlnWelcomeMessage("Type :help for help, :quit for quit")
+            }
+
+            // Display compiler messages related to configuration and CLI arguments, quit if there are errors
+            val hasErrors = messageCollector.hasErrors()
+            (messageCollector as? GroupingMessageCollector)?.flush()
+            if (hasErrors) return
+
+            val processor = ReplProcessor(replInterpreter, replConfiguration)
+            replConfiguration.reader.runLoop(processor)
+        } catch (e: Exception) {
+            replConfiguration.exceptionReporter.report(e)
+            throw e
+        } finally {
+            try {
+                replConfiguration.reader.flushHistory()
+            } catch (e: Exception) {
+                replConfiguration.exceptionReporter.report(e)
+                throw e
+            }
+        }
+    }
+
+    enum class WhatNextAfterOneLine {
+        READ_LINE,
+        INCOMPLETE,
+        QUIT
+    }
+
+    companion object {
+        fun run(disposable: Disposable, configuration: CompilerConfiguration) {
+            val replIdeMode = System.getProperty("kotlin.repl.ideMode") == "true"
+            val replConfiguration = if (replIdeMode) IdeReplConfiguration() else ConsoleReplConfiguration()
+
+            return try {
+                KotlinRepl(disposable, configuration, replConfiguration).doRun()
+            } catch (e: Exception) {
+                replConfiguration.exceptionReporter.report(e)
+                throw e
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt
deleted file mode 100644
index ed6ab5f..0000000
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplFromTerminal.kt
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2010-2016 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.jetbrains.kotlin.cli.jvm.repl
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.util.io.FileUtil
-import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
-import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
-import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
-import org.jetbrains.kotlin.cli.jvm.repl.configuration.ConsoleReplConfiguration
-import org.jetbrains.kotlin.cli.jvm.repl.configuration.ReplConfiguration
-import org.jetbrains.kotlin.cli.jvm.repl.configuration.IdeReplConfiguration
-import org.jetbrains.kotlin.cli.jvm.repl.messages.unescapeLineBreaks
-import org.jetbrains.kotlin.config.CompilerConfiguration
-import org.jetbrains.kotlin.config.KotlinCompilerVersion
-import java.io.File
-import java.io.IOException
-import java.io.PrintWriter
-import java.util.*
-import java.util.concurrent.Callable
-import java.util.concurrent.Executors
-import java.util.concurrent.Future
-
-class ReplFromTerminal(
-        disposable: Disposable,
-        compilerConfiguration: CompilerConfiguration,
-        private val replConfiguration: ReplConfiguration
-) {
-    private val replInitializer: Future<ReplInterpreter> = Executors.newSingleThreadExecutor().submit(Callable {
-        ReplInterpreter(disposable, compilerConfiguration, replConfiguration)
-    })
-
-    private val replInterpreter: ReplInterpreter
-        get() = replInitializer.get()
-
-    private val writer get() = replConfiguration.writer
-
-    private val messageCollector = compilerConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
-
-    private fun doRun() {
-        try {
-            with (writer) {
-                printlnWelcomeMessage("Welcome to Kotlin version ${KotlinCompilerVersion.VERSION} " +
-                                             "(JRE ${System.getProperty("java.runtime.version")})")
-                printlnWelcomeMessage("Type :help for help, :quit for quit")
-            }
-
-            // Display compiler messages related to configuration and CLI arguments, quit if there are errors
-            val hasErrors = messageCollector.hasErrors()
-            (messageCollector as? GroupingMessageCollector)?.flush()
-            if (hasErrors) return
-
-            var next = WhatNextAfterOneLine.READ_LINE
-            while (true) {
-                next = one(next)
-                if (next == WhatNextAfterOneLine.QUIT) {
-                    break
-                }
-            }
-        }
-        catch (e: Exception) {
-            replConfiguration.exceptionReporter.report(e)
-            throw e
-        }
-        finally {
-            try {
-                replConfiguration.commandReader.flushHistory()
-            }
-            catch (e: Exception) {
-                replConfiguration.exceptionReporter.report(e)
-                throw e
-            }
-
-        }
-    }
-
-    enum class WhatNextAfterOneLine {
-        READ_LINE,
-        INCOMPLETE,
-        QUIT
-    }
-
-    private fun one(next: WhatNextAfterOneLine): WhatNextAfterOneLine {
-        var line = replConfiguration.commandReader.readLine(next) ?: return WhatNextAfterOneLine.QUIT
-
-        line = unescapeLineBreaks(line)
-
-        if (line.startsWith(":") && (line.length == 1 || line.get(1) != ':')) {
-            val notQuit = oneCommand(line.substring(1))
-            return if (notQuit) WhatNextAfterOneLine.READ_LINE else WhatNextAfterOneLine.QUIT
-        }
-
-        val lineResult = eval(line)
-        return if (lineResult is ReplEvalResult.Incomplete) {
-            WhatNextAfterOneLine.INCOMPLETE
-        }
-        else {
-            WhatNextAfterOneLine.READ_LINE
-        }
-    }
-
-    private fun eval(line: String): ReplEvalResult {
-        val evalResult = replInterpreter.eval(line)
-        when (evalResult) {
-            is ReplEvalResult.ValueResult, is ReplEvalResult.UnitResult -> {
-                writer.notifyCommandSuccess()
-                if (evalResult is ReplEvalResult.ValueResult) {
-                    writer.outputCommandResult(evalResult.value.toString())
-                }
-            }
-            is ReplEvalResult.Error.Runtime -> writer.outputRuntimeError(evalResult.message)
-            is ReplEvalResult.Error.CompileTime -> writer.outputRuntimeError(evalResult.message)
-            is ReplEvalResult.Incomplete -> writer.notifyIncomplete()
-        }
-        return evalResult
-    }
-
-    @Throws(Exception::class)
-    private fun oneCommand(command: String): Boolean {
-        val split = splitCommand(command)
-        if (split.isNotEmpty() && command == "help") {
-            val commands = mapOf("help" to "show this help",
-                                 "doc <qualified name>" to "show documentation for declaration",
-                                 "load <file>" to "load script from specified file",
-                                 "classes" to "dump classes to terminal",
-                                 "quit" to "quit the interpreter")
-
-            val maxCommandLength = commands.keys.fold(0) { max, s -> maxOf(max, s.length) } + 4
-            val renderedCommands = commands.entries.joinToString("\n") {
-                ":" + it.key + " ".repeat(maxCommandLength - it.key.length) + it.value
-            }
-
-            writer.printlnHelpMessage("Available commands:\n" + renderedCommands)
-            return true
-        }
-        else if (split.size == 2 && split[0] == "doc") {
-            val docComment = replInterpreter.doc(split[1])
-
-            if (docComment != null) {
-                writer.printlnHelpMessage(docComment)
-            } else {
-                writer.printlnHelpMessage("No documentation found.")
-            }
-
-            return true
-        }
-        else if (split.size == 1 && split.single() == "classes") {
-            replInterpreter.dumpClasses(PrintWriter(System.out))
-            return true
-        }
-        else if (split.size == 1 && split.single() == "quit") {
-            return false
-        }
-        else if (split.size == 2 && split[0] == "load") {
-            val fileName = split[1]
-            try {
-                val scriptText = FileUtil.loadFile(File(fileName))
-                eval(scriptText)
-            } catch (e: IOException) {
-                writer.outputCompileError("Can not load script: ${e.message}")
-            }
-            return true
-        }
-        else {
-            writer.printlnHelpMessage("Unknown command\n" + "Type :help for help")
-            return true
-        }
-    }
-
-    companion object {
-        private fun splitCommand(command: String): List<String> {
-            return Arrays.asList(*command.split(" ".toRegex()).dropLastWhile(String::isEmpty).toTypedArray())
-        }
-
-        fun run(disposable: Disposable, configuration: CompilerConfiguration) {
-            val replIdeMode = System.getProperty("kotlin.repl.ideMode") == "true"
-            val replConfiguration = if (replIdeMode) IdeReplConfiguration() else ConsoleReplConfiguration()
-            return try {
-                ReplFromTerminal(disposable, configuration, replConfiguration).doRun()
-            }
-            catch (e: Exception) {
-                replConfiguration.exceptionReporter.report(e)
-                throw e
-            }
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt
index b247728..86d8723 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/ReplInterpreter.kt
@@ -27,6 +27,7 @@
 import org.jetbrains.kotlin.cli.common.repl.*
 import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
 import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
+import org.jetbrains.kotlin.cli.jvm.repl.codeinsight.ReplCodeInsightFacadeImpl
 import org.jetbrains.kotlin.cli.jvm.repl.configuration.ReplConfiguration
 import org.jetbrains.kotlin.config.CompilerConfiguration
 import org.jetbrains.kotlin.config.JVMConfigurationKeys
@@ -134,8 +135,24 @@
         }
     }
 
+    fun complete(line: String): Collection<DeclarationDescriptor> {
+        val compilerState = evalState.asState<GenericReplCompilerState>()
+
+        val codeFragment = KtPsiFactory(compilerState.analyzerEngine.project).createExpressionCodeFragment(line, null)
+        compilerState.analyzerEngine.setDelegateFactory(codeFragment.containingKtFile)
+
+        val targetIdentifier =
+            codeFragment.findElementAt(codeFragment.textLength - 1)
+                ?.getNonStrictParentOfType(KtSimpleNameExpression::class.java)
+                    ?: return emptyList()
+
+        val codeInsightFacade = ReplCodeInsightFacadeImpl.create(compilerState.analyzerEngine)
+        return codeInsightFacade.complete(targetIdentifier, "o")
+    }
+
     fun doc(rawFqName: String): String? {
         val compilerState = evalState.asState<GenericReplCompilerState>()
+
         val bindingContext = compilerState.analyzerEngine.trace.bindingContext
         val moduleDescriptor = compilerState.analyzerEngine.module
         val qualifiedExpressionResolver = compilerState.analyzerEngine.qualifiedExpressionResolver
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/codeinsight/ReplCodeInsightFacade.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/codeinsight/ReplCodeInsightFacade.kt
index dc32495..ae3b2d2 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/codeinsight/ReplCodeInsightFacade.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/codeinsight/ReplCodeInsightFacade.kt
@@ -33,8 +33,6 @@
 import java.lang.reflect.InvocationHandler
 import java.lang.reflect.Modifier
 import java.lang.reflect.Proxy.getProxyClass
-import java.net.URLDecoder
-import java.nio.charset.Charset
 
 interface ReplCodeInsightFacade {
     fun complete(expression: KtSimpleNameExpression, identifierPart: String): Collection<DeclarationDescriptor>
@@ -46,16 +44,7 @@
                 DescriptorKindFilter.CALLABLES_MASK or DescriptorKindFilter.CLASSIFIERS_MASK)
 
         fun create(replCodeAnalyzer: ReplCodeAnalyzer): ReplCodeInsightFacade {
-//            val kotlinCompilerJarFile = findJarByClass(ReplCodeAnalyzer::class.java)
-//                                        ?: return error("Can't find kotlin-compiler.jar")
-
-            val kotlinCompilerJarFile = File("/Users/yan/jb/kotlin/dist/kotlinc/lib/kotlin-compiler.jar")
-
-            val kotlinCodeInsightFile = File(kotlinCompilerJarFile.parentFile, "kotlin-code-insight-base.jar")
-            if (!kotlinCodeInsightFile.exists()) {
-                error("Can't find kotlin-code-insight-base.jar")
-            }
-
+            val kotlinCodeInsightFile = getKotlinCodeInsightJar()
             val classLoaderWithCodeInsight = ReplClassLoader(listOf(kotlinCodeInsightFile), replCodeAnalyzer.javaClass.classLoader)
 
             fun addClass(className: String) {
@@ -69,10 +58,10 @@
             addClass("org.jetbrains.kotlin.cli.jvm.repl.codeinsight.ResolutionFacadeForRepl")
 
             val actualImplementation = Class.forName(ReplCodeInsightFacadeImpl::class.java.name, true, classLoaderWithCodeInsight)
-                    .constructors.single().newInstance(replCodeAnalyzer)
+                    .declaredConstructors.single().newInstance(replCodeAnalyzer)
 
             val proxyClass = getProxyClass(ReplCodeInsightFacadeImpl::class.java.classLoader, ReplCodeInsightFacade::class.java)
-            val proxy = proxyClass.constructors.single().newInstance(InvocationHandler { proxy, method, args ->
+            val proxy = proxyClass.constructors.single().newInstance(InvocationHandler { _, method, args ->
                 val isStatic = Modifier.isStatic(method.modifiers)
 
                 fun parameterTypesMatches(first: Array<Class<*>>, second: Array<Class<*>>): Boolean {
@@ -88,14 +77,35 @@
             return proxy as ReplCodeInsightFacade
         }
 
-        private fun findJarByClass(klass: Class<*>): File? {
-            val classFileName = klass.name.substringAfterLast(".") + ".class"
-            val resource = klass.getResource(classFileName) ?: return null
-            val uri = resource.toString()
-            if (!uri.startsWith("jar:file:")) return null
+        private fun getKotlinCodeInsightJar(): File {
+            System.getProperty("kotlin.code.insight.jar")?.let { return File(it) }
 
-            val fileName = URLDecoder.decode(uri.removePrefix("jar:file:").substringBefore("!"), Charset.defaultCharset().name())
-            return File(fileName)
+            val kotlinCompilerJarFile = getClasspathEntry(ReplCodeAnalyzer::class.java) ?: error("Can't find Kotlin compiler")
+
+            val kotlinCodeInsightFile = File(kotlinCompilerJarFile.parentFile, "kotlin-code-insight.jar")
+            if (!kotlinCodeInsightFile.exists()) {
+                error("Can't find kotlin-code-insight.jar")
+            }
+
+            return kotlinCodeInsightFile
+        }
+
+        private fun getClasspathEntry(clazz: Class<*>): File? {
+            val classFileName = clazz.name.replace('.', '/') + ".class"
+            val resource = clazz.classLoader.getResource(classFileName) ?: return null
+
+            return File(
+                when (resource.protocol?.toLowerCase()) {
+                    "file" -> resource.path
+                        ?.takeIf { it.endsWith(classFileName) }
+                        ?.removeSuffix(classFileName)
+                    "jar" -> resource.path
+                        .takeIf { it.startsWith("file:", ignoreCase = true) }
+                        ?.drop("file:".length)
+                        ?.substringBefore("!/")
+                    else -> null
+                }
+            )
         }
     }
 
@@ -105,18 +115,18 @@
             replCodeAnalyzer.module)
 
     override fun complete(expression: KtSimpleNameExpression, identifierPart: String): Collection<DeclarationDescriptor> {
-        val nameFilter: (Name) -> Boolean = { name -> applicableNameFor(identifierPart, name) }
-
         // TODO do not filter out
-        return referenceVariantsHelper.getReferenceVariants(expression, CALLABLES_AND_CLASSIFIERS, nameFilter)
+        return referenceVariantsHelper.getReferenceVariants(expression, CALLABLES_AND_CLASSIFIERS, NameFilter(identifierPart))
     }
 
-    private fun applicableNameFor(prefix: String, name: Name): Boolean {
-        return !name.isSpecial && applicableNameFor(prefix, name.identifier)
-    }
+    class NameFilter(val prefix: String) : (Name) -> Boolean {
+        override fun invoke(name: Name): Boolean {
+            return !name.isSpecial && applicableNameFor(prefix, name.identifier)
+        }
 
-    private fun applicableNameFor(prefix: String, completion: String): Boolean {
-        return completion.startsWith(prefix) || completion.toLowerCase().startsWith(prefix)
+        private fun applicableNameFor(prefix: String, completion: String): Boolean {
+            return completion.startsWith(prefix) || completion.toLowerCase().startsWith(prefix)
+        }
     }
 }
 
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/ClassesReplCommand.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/ClassesReplCommand.kt
new file mode 100644
index 0000000..878d634
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/ClassesReplCommand.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.command
+
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand.*
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandContext
+import java.io.PrintWriter
+
+object ClassesReplCommand : ReplCommand {
+    override val name = "classes"
+    override val args = emptyList<String>()
+    override val help = "dump loaded classes"
+
+    override val constraints = ArgumentConstraints.Empty
+
+    override fun run(context: ReplCommandContext, rawArgs: String): Boolean {
+        context.interpreter.dumpClasses(PrintWriter(System.out))
+        return true
+    }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/DocReplCommand.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/DocReplCommand.kt
new file mode 100644
index 0000000..592cc28
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/DocReplCommand.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.command
+
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand.*
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandContext
+
+object DocReplCommand : ReplCommand {
+    override val name = "doc"
+    override val args = listOf("symbol")
+    override val help = "display documentation for the given symbol"
+
+    override val constraints = ArgumentConstraints.Raw
+
+    override fun run(context: ReplCommandContext, rawArgs: String): Boolean {
+        val docComment = context.interpreter.doc(rawArgs)
+        context.configuration.writer.printlnHelpMessage(docComment ?: "No documentation found.")
+        return true
+    }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/HelpReplCommand.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/HelpReplCommand.kt
new file mode 100644
index 0000000..b96423a
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/HelpReplCommand.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.command
+
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand.*
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandContext
+
+object HelpReplCommand : ReplCommand {
+    override val name = "help"
+    override val args = emptyList<String>()
+    override val help = "display help message"
+
+    override val constraints = ArgumentConstraints.Empty
+
+    override fun run(context: ReplCommandContext, rawArgs: String): Boolean {
+        val commands = ReplCommand.COMMANDS.map { (_, command) ->
+            buildString {
+                append(command.name)
+                if (command.args.isNotEmpty()) {
+                    append(' ')
+                    command.args.joinTo(this) { "<$it>" }
+                }
+            } to command.help
+        }
+
+        val maxCommandLength = (commands.map { it.first.length }.max() ?: 0) + 4
+        val renderedCommands = commands
+            .joinToString("\n") { ":" + it.first + " ".repeat(maxCommandLength - it.first.length) + it.second }
+
+        context.configuration.writer.printlnHelpMessage("Available commands:\n" + renderedCommands)
+        return true
+    }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/LoadReplCommand.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/LoadReplCommand.kt
new file mode 100644
index 0000000..36c81dc
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/LoadReplCommand.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.command
+
+import com.intellij.openapi.util.io.FileUtil
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand.*
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandContext
+import java.io.File
+import java.io.IOException
+
+object LoadReplCommand : ReplCommand {
+    override val name = "load"
+    override val args = listOf("file")
+    override val help = "evaluate a script file"
+
+    override val constraints = ArgumentConstraints.Raw
+
+    override fun run(context: ReplCommandContext, rawArgs: String): Boolean {
+        fun printError(text: String) = context.configuration.writer.outputCompileError(text)
+
+        val file = File(rawArgs).takeIf { it.isFile } ?: run {
+            printError("File not exists: ${File(rawArgs).absolutePath}")
+            return true
+        }
+
+        try {
+            val scriptText = FileUtil.loadFile(file)
+            context.interpreter.eval(scriptText)
+        } catch (e: IOException) {
+            printError("Can not load script: ${e.message}")
+        }
+
+        return true
+    }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/QuitReplCommand.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/QuitReplCommand.kt
new file mode 100644
index 0000000..b626dd6
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/command/QuitReplCommand.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.command
+
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommand.*
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandContext
+
+object QuitReplCommand : ReplCommand {
+    override val name = "quit"
+    override val args = emptyList<String>()
+    override val help = "quit REPL"
+
+    override val constraints = ArgumentConstraints.Empty
+
+    override fun run(context: ReplCommandContext, rawArgs: String): Boolean {
+        if (rawArgs.isNotEmpty()) {
+            context.configuration.writer.outputCompileError("Expected zero arguments, got $rawArgs")
+            return true
+        }
+
+        return false
+    }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ConsoleReplConfiguration.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ConsoleReplConfiguration.kt
index 2043950..1066a75 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ConsoleReplConfiguration.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ConsoleReplConfiguration.kt
@@ -18,7 +18,7 @@
 
 import org.jetbrains.kotlin.cli.jvm.repl.ReplExceptionReporter
 import org.jetbrains.kotlin.cli.jvm.repl.messages.ConsoleDiagnosticMessageHolder
-import org.jetbrains.kotlin.cli.jvm.repl.reader.ConsoleReplCommandReader
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ConsoleReplReader
 import org.jetbrains.kotlin.cli.jvm.repl.writer.ConsoleReplWriter
 
 class ConsoleReplConfiguration : ReplConfiguration {
@@ -27,7 +27,7 @@
     override val exceptionReporter
         get() = ReplExceptionReporter
 
-    override val commandReader = ConsoleReplCommandReader()
+    override val reader = ConsoleReplReader()
 
     override val allowIncompleteLines: Boolean
         get() = true
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/IdeReplConfiguration.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/IdeReplConfiguration.kt
index 667d542..a355356 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/IdeReplConfiguration.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/IdeReplConfiguration.kt
@@ -19,9 +19,7 @@
 import org.jetbrains.kotlin.cli.jvm.repl.IdeReplExceptionReporter
 import org.jetbrains.kotlin.cli.jvm.repl.ReplExceptionReporter
 import org.jetbrains.kotlin.cli.jvm.repl.messages.IdeDiagnosticMessageHolder
-import org.jetbrains.kotlin.cli.jvm.repl.reader.IdeReplCommandReader
-import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandReader
-import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplSystemInWrapper
+import org.jetbrains.kotlin.cli.jvm.repl.reader.*
 import org.jetbrains.kotlin.cli.jvm.repl.writer.IdeSystemOutWrapperReplWriter
 import org.jetbrains.kotlin.cli.jvm.repl.writer.ReplWriter
 
@@ -44,7 +42,7 @@
 
     override val writer: ReplWriter
     override val exceptionReporter: ReplExceptionReporter
-    override val commandReader: ReplCommandReader
+    override val reader: ReplReader
 
     val sinWrapper: ReplSystemInWrapper
 
@@ -62,6 +60,6 @@
 
         writer = soutWrapper
         exceptionReporter = IdeReplExceptionReporter(writer)
-        commandReader = IdeReplCommandReader()
+        reader = IdeReplReader()
     }
 }
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ReplConfiguration.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ReplConfiguration.kt
index 02b303f..0937f8f 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ReplConfiguration.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/configuration/ReplConfiguration.kt
@@ -18,13 +18,14 @@
 
 import org.jetbrains.kotlin.cli.jvm.repl.ReplExceptionReporter
 import org.jetbrains.kotlin.cli.jvm.repl.messages.*
-import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplCommandReader
+import org.jetbrains.kotlin.cli.jvm.repl.reader.ReplReader
 import org.jetbrains.kotlin.cli.jvm.repl.writer.ReplWriter
 
 interface ReplConfiguration {
+    val reader: ReplReader
     val writer: ReplWriter
     val exceptionReporter: ReplExceptionReporter
-    val commandReader: ReplCommandReader
+
     val allowIncompleteLines: Boolean
 
     val executionInterceptor: SnippetExecutionInterceptor
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ConsoleReplCommandReader.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ConsoleReplCommandReader.kt
deleted file mode 100644
index 06c15c0..0000000
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ConsoleReplCommandReader.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2010-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.jetbrains.kotlin.cli.jvm.repl.reader
-
-import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
-import org.jline.reader.EndOfFileException
-import org.jline.reader.LineReader
-import org.jline.reader.LineReaderBuilder
-import org.jline.reader.UserInterruptException
-import org.jline.terminal.TerminalBuilder
-import java.io.File
-import java.util.logging.Level
-import java.util.logging.Logger
-
-class ConsoleReplCommandReader : ReplCommandReader {
-    private val lineReader = LineReaderBuilder.builder()
-            .appName("kotlin")
-            .terminal(TerminalBuilder.terminal())
-            .variable(LineReader.HISTORY_FILE, File(File(System.getProperty("user.home")), ".kotlinc_history").absolutePath)
-            .build()
-            .apply {
-                setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION)
-            }
-
-    override fun readLine(next: ReplFromTerminal.WhatNextAfterOneLine): String? {
-        val prompt = if (next == ReplFromTerminal.WhatNextAfterOneLine.INCOMPLETE) "... " else ">>> "
-        try {
-            return lineReader.readLine(prompt)
-        }
-        catch (e: UserInterruptException) {
-            println("<interrupted>")
-            System.out.flush()
-            return ""
-        }
-        catch (e: EndOfFileException) {
-            return null
-        }
-    }
-
-    override fun flushHistory() = lineReader.history.save()
-
-    private companion object {
-        init {
-            Logger.getLogger("org.jline").level = Level.OFF;
-        }
-    }
-}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ConsoleReplReader.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ConsoleReplReader.kt
new file mode 100644
index 0000000..beec18f
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ConsoleReplReader.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.reader
+
+import org.jetbrains.kotlin.cli.jvm.repl.KotlinRepl
+import org.jline.reader.*
+import org.jline.terminal.TerminalBuilder
+import java.io.File
+import java.util.logging.Level
+import java.util.logging.Logger
+
+class ConsoleReplReader : ReplReader {
+    private var processor: ReplProcessor? = null
+
+    private val lineReader = LineReaderBuilder.builder()
+        .appName("kotlin")
+        .terminal(TerminalBuilder.terminal())
+        .variable(LineReader.HISTORY_FILE, File(File(System.getProperty("user.home")), ".kotlinc_history").absolutePath)
+        .completer(::completer)
+        .build()
+        .apply {
+            Logger.getLogger("org.jline").level = Level.OFF
+            setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION)
+        }
+
+    override fun runLoop(processor: ReplProcessor) {
+        try {
+            this.processor = processor
+            super.runLoop(processor)
+        } finally {
+            this.processor = null
+        }
+    }
+
+    private fun completer(lineReader: LineReader, parsedLine: ParsedLine, candidates: MutableList<Candidate>) {
+        val processor = this.processor ?: error("ReplProcessor is not initialized")
+        candidates.addAll(processor.complete(parsedLine.line(), parsedLine.cursor()).map { Candidate(it) })
+    }
+
+    override fun readLine(next: KotlinRepl.WhatNextAfterOneLine): String? {
+        val prompt = if (next == KotlinRepl.WhatNextAfterOneLine.INCOMPLETE) "... " else ">>> "
+
+        return try {
+            lineReader.readLine(prompt)
+        } catch (e: UserInterruptException) {
+            println("<interrupted>")
+            System.out.flush()
+            ""
+        } catch (e: EndOfFileException) {
+            null
+        }
+    }
+
+    override fun flushHistory() = lineReader.history.save()
+}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/IdeReplCommandReader.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/IdeReplReader.kt
similarity index 78%
rename from compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/IdeReplCommandReader.kt
rename to compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/IdeReplReader.kt
index 95d54a8..f086ecc 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/IdeReplCommandReader.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/IdeReplReader.kt
@@ -16,9 +16,9 @@
 
 package org.jetbrains.kotlin.cli.jvm.repl.reader
 
-import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
+import org.jetbrains.kotlin.cli.jvm.repl.KotlinRepl
 
-class IdeReplCommandReader : ReplCommandReader {
-    override fun readLine(next: ReplFromTerminal.WhatNextAfterOneLine) = readLine()
+class IdeReplReader : ReplReader {
+    override fun readLine(next: KotlinRepl.WhatNextAfterOneLine) = readLine()
     override fun flushHistory() = Unit
 }
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplCommandReader.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplCommandReader.kt
deleted file mode 100644
index 3fb48b0..0000000
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplCommandReader.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2010-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.jetbrains.kotlin.cli.jvm.repl.reader
-
-import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
-
-interface ReplCommandReader {
-    fun readLine(next: ReplFromTerminal.WhatNextAfterOneLine): String?
-    fun flushHistory()
-}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplProcessor.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplProcessor.kt
new file mode 100644
index 0000000..76a5fa2
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplProcessor.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.reader
+
+import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
+import org.jetbrains.kotlin.cli.jvm.repl.ReplInterpreter
+import org.jetbrains.kotlin.cli.jvm.repl.command.*
+import org.jetbrains.kotlin.cli.jvm.repl.configuration.ReplConfiguration
+
+class ReplProcessor(
+    interpreter: ReplInterpreter,
+    configuration: ReplConfiguration
+) {
+    private val context = ReplCommandContext(interpreter, configuration)
+
+    fun processCommand(commandName: String, rawArgs: String): Boolean {
+        val command = ReplCommand.COMMANDS[commandName] ?: run {
+            context.configuration.writer.printlnHelpMessage("Unknown command\n" + "Type :help for help")
+            return true
+        }
+
+        return command.run(context, rawArgs)
+    }
+
+    fun evaluate(text: String): ReplEvalResult {
+        val evalResult = context.interpreter.eval(text)
+        val writer = context.configuration.writer
+
+        when (evalResult) {
+            is ReplEvalResult.ValueResult, is ReplEvalResult.UnitResult -> {
+                writer.notifyCommandSuccess()
+                if (evalResult is ReplEvalResult.ValueResult) {
+                    writer.outputCommandResult(evalResult.value.toString())
+                }
+            }
+            is ReplEvalResult.Error.Runtime -> writer.outputRuntimeError(evalResult.message)
+            is ReplEvalResult.Error.CompileTime -> writer.outputRuntimeError(evalResult.message)
+            is ReplEvalResult.Incomplete -> writer.notifyIncomplete()
+        }
+        return evalResult
+    }
+
+    fun complete(line: String, position: Int): List<String> {
+        return context.interpreter.complete(line.substring(0, position)).map { it.name.asString() }
+    }
+}
+
+interface ReplCommand {
+    val name: String
+    val args: List<String>
+    val help: String
+
+    val constraints: ArgumentConstraints
+
+    /** Returns `true` if REPL should continue processing the next line. */
+    fun run(context: ReplCommandContext, rawArgs: String): Boolean
+
+    sealed class ArgumentConstraints {
+        object Empty : ArgumentConstraints()
+        object Raw : ArgumentConstraints()
+    }
+
+    companion object {
+        val COMMANDS: Map<String, ReplCommand> = listOf(
+            ClassesReplCommand,
+            DocReplCommand,
+            LoadReplCommand,
+            HelpReplCommand,
+            QuitReplCommand
+        ).map { it.name to it }.toMap()
+    }
+}
+
+class ReplCommandContext(val interpreter: ReplInterpreter, val configuration: ReplConfiguration)
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplReader.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplReader.kt
new file mode 100644
index 0000000..c628cc4
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/reader/ReplReader.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.repl.reader
+
+import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
+import org.jetbrains.kotlin.cli.jvm.repl.KotlinRepl
+import org.jetbrains.kotlin.cli.jvm.repl.messages.unescapeLineBreaks
+
+interface ReplReader {
+    fun readLine(next: KotlinRepl.WhatNextAfterOneLine): String?
+    fun flushHistory()
+
+    tailrec fun runLoop(processor: ReplProcessor) {
+        val nextLine = KotlinRepl.WhatNextAfterOneLine.READ_LINE
+        if (processLine(processor, nextLine) != KotlinRepl.WhatNextAfterOneLine.QUIT) {
+            runLoop(processor)
+        }
+    }
+
+    private fun processLine(
+        processor: ReplProcessor,
+        next: KotlinRepl.WhatNextAfterOneLine
+    ): KotlinRepl.WhatNextAfterOneLine {
+        val rawLine = readLine(next) ?: return KotlinRepl.WhatNextAfterOneLine.QUIT
+        val line = unescapeLineBreaks(rawLine)
+
+        if (isCommand(line)) {
+            val commandName = line.substringBefore(' ')
+            val rawArgs = line.substringAfter(' ', missingDelimiterValue = "").trim()
+
+            return if (processor.processCommand(commandName.drop(1), rawArgs)) {
+                KotlinRepl.WhatNextAfterOneLine.READ_LINE
+            } else {
+                KotlinRepl.WhatNextAfterOneLine.QUIT
+            }
+        }
+
+        val lineResult = processor.evaluate(line)
+        return if (lineResult is ReplEvalResult.Incomplete) {
+            KotlinRepl.WhatNextAfterOneLine.INCOMPLETE
+        } else {
+            KotlinRepl.WhatNextAfterOneLine.READ_LINE
+        }
+    }
+
+    private fun isCommand(line: String) = line.startsWith(":") && (line.length == 1 || line[1] != ':')
+}
\ No newline at end of file
diff --git a/idea/ide-common/build.gradle.kts b/idea/ide-common/build.gradle.kts
index 39bd3f3d..2a027f1 100644
--- a/idea/ide-common/build.gradle.kts
+++ b/idea/ide-common/build.gradle.kts
@@ -16,4 +16,4 @@
     "test" {}
 }
 
-dist(targetName = "kotlin-code-insight-base.jar")
\ No newline at end of file
+dist(targetName = "kotlin-code-insight.jar")
\ No newline at end of file