~
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