Repl: keep track of command entries which were already processed
Fixes race condition
This commit is contained in:
@@ -25,6 +25,8 @@ class CommandHistory {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val entries = arrayListOf<Entry>()
|
private val entries = arrayListOf<Entry>()
|
||||||
|
private var processedEntriesCount: Int = 0
|
||||||
|
|
||||||
val listeners = arrayListOf<HistoryUpdateListener>()
|
val listeners = arrayListOf<HistoryUpdateListener>()
|
||||||
|
|
||||||
operator fun get(i: Int) = entries[i]
|
operator fun get(i: Int) = entries[i]
|
||||||
@@ -34,6 +36,19 @@ class CommandHistory {
|
|||||||
listeners.forEach { it.onNewEntry(entry) }
|
listeners.forEach { it.onNewEntry(entry) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun lastUnprocessedEntry(): CommandHistory.Entry? {
|
||||||
|
if (processedEntriesCount < size) {
|
||||||
|
return get(processedEntriesCount)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun entryProcessed() {
|
||||||
|
processedEntriesCount++
|
||||||
|
}
|
||||||
|
|
||||||
val size: Int
|
val size: Int
|
||||||
get() = entries.size
|
get() = entries.size
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.intellij.execution.process.OSProcessHandler
|
|||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import org.jetbrains.kotlin.console.actions.logError
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.xml.sax.InputSource
|
import org.xml.sax.InputSource
|
||||||
@@ -69,6 +70,12 @@ class ReplOutputHandler(
|
|||||||
"COMPILE_ERROR" -> outputProcessor.highlightCompilerErrors(createCompilerMessages(content))
|
"COMPILE_ERROR" -> outputProcessor.highlightCompilerErrors(createCompilerMessages(content))
|
||||||
"RUNTIME_ERROR" -> outputProcessor.printRuntimeError("${content.trim()}\n")
|
"RUNTIME_ERROR" -> outputProcessor.printRuntimeError("${content.trim()}\n")
|
||||||
"INTERNAL_ERROR" -> outputProcessor.printInternalErrorMessage(content)
|
"INTERNAL_ERROR" -> outputProcessor.printInternalErrorMessage(content)
|
||||||
|
"SUCCESS" -> Unit
|
||||||
|
else -> logError(ReplOutputHandler::class.java, "Unexpected output type:\n$outputType")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputType in setOf("SUCCESS", "COMPILE_ERROR", "INTERNAL_ERROR", "RUNTIME_ERROR")) {
|
||||||
|
runner.commandHistory.entryProcessed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,11 @@ public class ReplOutputProcessor(
|
|||||||
|
|
||||||
fun highlightCompilerErrors(compilerMessages: List<SeverityDetails>) = WriteCommandAction.runWriteCommandAction(project) {
|
fun highlightCompilerErrors(compilerMessages: List<SeverityDetails>) = WriteCommandAction.runWriteCommandAction(project) {
|
||||||
val commandHistory = runner.commandHistory
|
val commandHistory = runner.commandHistory
|
||||||
val lastCommandStartOffset = historyDocument.textLength - commandHistory[commandHistory.size - 1].entryText.length - 1
|
val lastUnprocessedHistoryEntry = commandHistory.lastUnprocessedEntry() ?: return@runWriteCommandAction logError(
|
||||||
|
ReplOutputProcessor::class.java,
|
||||||
|
"Processed more commands than were sent. Sent commands: ${commandHistory.size}. Processed: ${commandHistory.processedEntriesCount}"
|
||||||
|
)
|
||||||
|
val lastCommandStartOffset = lastUnprocessedHistoryEntry.rangeInHistoryDocument.startOffset
|
||||||
val lastCommandStartLine = historyDocument.getLineNumber(lastCommandStartOffset)
|
val lastCommandStartLine = historyDocument.getLineNumber(lastCommandStartOffset)
|
||||||
val historyCommandRunIndicator = historyMarkup.allHighlighters.filter {
|
val historyCommandRunIndicator = historyMarkup.allHighlighters.filter {
|
||||||
historyDocument.getLineNumber(it.startOffset) == lastCommandStartLine && it.gutterIconRenderer != null
|
historyDocument.getLineNumber(it.startOffset) == lastCommandStartLine && it.gutterIconRenderer != null
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class KotlinReplTest : PlatformTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test fun testOnePlusOne() = testSimpleCommand("1 + 1", "2")
|
@Test fun testOnePlusOne() = testSimpleCommand("1 + 1", "2")
|
||||||
@Test fun testPrintlnText() = "Hello, console world!" let { testSimpleCommand("println(\"$it\")", it) }
|
@Test fun testPrintlnText() = "Hello, console world!".let { testSimpleCommand("println(\"$it\")", it) }
|
||||||
@Test fun testDivisionByZeroException() = testSimpleCommand("1 / 0", "java.lang.ArithmeticException: / by zero")
|
@Test fun testDivisionByZeroException() = testSimpleCommand("1 / 0", "java.lang.ArithmeticException: / by zero")
|
||||||
|
|
||||||
@Test fun testMultilineSupport() {
|
@Test fun testMultilineSupport() {
|
||||||
@@ -125,4 +125,11 @@ public class KotlinReplTest : PlatformTestCase() {
|
|||||||
sendCommand("b")
|
sendCommand("b")
|
||||||
waitForExpectedOutput(readLineTextB)
|
waitForExpectedOutput(readLineTextB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun testCorrectAfterError() {
|
||||||
|
val message = "MyMessage"
|
||||||
|
sendCommand("fun f() { println(x)\n println(y) ")
|
||||||
|
sendCommand("println(\"$message\")")
|
||||||
|
waitForExpectedOutput(message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user