Repl: refactor ide code
More accurate class names Move all shared state to KotlinConsoleRunner class
This commit is contained in:
+18
-14
@@ -20,29 +20,33 @@ import com.intellij.execution.process.BaseOSProcessHandler
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.console.actions.logError
|
||||
import org.jetbrains.kotlin.console.highlight.KotlinHistoryHighlighter
|
||||
|
||||
private val XML_PREAMBLE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
|
||||
public class KotlinConsoleExecutor(
|
||||
private val runner: KotlinConsoleRunner,
|
||||
private val historyManager: KotlinConsoleHistoryManager,
|
||||
private val historyHighlighter: KotlinHistoryHighlighter
|
||||
) {
|
||||
public class CommandExecutor(private val runner: KotlinConsoleRunner) {
|
||||
private val commandHistory = runner.commandHistory
|
||||
private val historyUpdater = HistoryUpdater(runner)
|
||||
|
||||
fun executeCommand() = WriteCommandAction.runWriteCommandAction(runner.project) {
|
||||
val commandText = getTrimmedCommandText()
|
||||
|
||||
if (commandText.isEmpty()) {
|
||||
return@runWriteCommandAction
|
||||
}
|
||||
|
||||
val historyDocumentRange = historyUpdater.printNewCommandInHistory(commandText)
|
||||
commandHistory.addEntry(CommandHistory.Entry(commandText, historyDocumentRange))
|
||||
sendCommandToProcess(commandText)
|
||||
}
|
||||
|
||||
private fun getTrimmedCommandText(): String {
|
||||
val consoleView = runner.consoleView
|
||||
val document = consoleView.editorDocument
|
||||
val inputText = document.text.trim()
|
||||
|
||||
if (inputText.isNotEmpty()) {
|
||||
historyHighlighter.printNewCommandInHistory(inputText)
|
||||
submitCommand(inputText)
|
||||
}
|
||||
return inputText
|
||||
}
|
||||
|
||||
private fun submitCommand(command: String) {
|
||||
historyManager.updateHistory(command)
|
||||
|
||||
private fun sendCommandToProcess(command: String) {
|
||||
val processHandler = runner.processHandler
|
||||
val processInputOS = processHandler.processInput ?: return logError(javaClass, "<p>Broken process stream</p>")
|
||||
val charset = (processHandler as? BaseOSProcessHandler)?.charset ?: Charsets.UTF_8
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.console
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
|
||||
class CommandHistory {
|
||||
class Entry(
|
||||
val entryText: String,
|
||||
val rangeInHistoryDocument: TextRange
|
||||
)
|
||||
|
||||
private val entries = arrayListOf<Entry>()
|
||||
val listeners = arrayListOf<HistoryUpdateListener>()
|
||||
|
||||
operator fun get(i: Int) = entries[i]
|
||||
|
||||
fun addEntry(entry: Entry) {
|
||||
entries.add(entry)
|
||||
listeners.forEach { it.onNewEntry(entry) }
|
||||
}
|
||||
|
||||
val size: Int
|
||||
get() = entries.size
|
||||
}
|
||||
|
||||
interface HistoryUpdateListener {
|
||||
fun onNewEntry(entry: CommandHistory.Entry)
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@ import com.intellij.openapi.compiler.CompilerManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
public class KotlinConsoleCompilerHelper(
|
||||
public class ConsoleCompilerHelper(
|
||||
private val project: Project,
|
||||
private val module: Module,
|
||||
private val executor: Executor,
|
||||
+13
-20
@@ -20,27 +20,20 @@ import com.intellij.codeInsight.lookup.LookupManager
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.editor.ex.EditorEx
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import java.awt.event.KeyAdapter
|
||||
import java.awt.event.KeyEvent
|
||||
|
||||
public class KotlinConsoleHistoryManager(private val runner: KotlinConsoleRunner) : KeyAdapter() {
|
||||
private val project = runner.project
|
||||
private val consoleEditor: EditorEx by lazy { runner.consoleView.consoleEditor } // [consoleEditor] is null at the moment if instantiation
|
||||
|
||||
private val history = arrayListOf<String>()
|
||||
|
||||
class HistoryKeyListener(
|
||||
private val project: Project, private val consoleEditor: EditorEx, private val history: CommandHistory
|
||||
) : KeyAdapter(), HistoryUpdateListener {
|
||||
private var historyPos = 0
|
||||
private var prevCaretOffset = -1
|
||||
private var unfinishedCommand = ""
|
||||
|
||||
val lastCommandLength: Int
|
||||
get() = history.last().length()
|
||||
|
||||
public fun updateHistory(command: String) {
|
||||
history.add(command)
|
||||
|
||||
override fun onNewEntry(entry: CommandHistory.Entry) {
|
||||
// reset history positions
|
||||
historyPos = history.size()
|
||||
historyPos = history.size
|
||||
prevCaretOffset = -1
|
||||
unfinishedCommand = ""
|
||||
}
|
||||
@@ -50,13 +43,13 @@ public class KotlinConsoleHistoryManager(private val runner: KotlinConsoleRunner
|
||||
}
|
||||
|
||||
override fun keyReleased(e: KeyEvent): Unit = when (e.keyCode) {
|
||||
KeyEvent.VK_UP -> moveHistoryCursor(HistoryMove.UP)
|
||||
KeyEvent.VK_UP -> moveHistoryCursor(HistoryMove.UP)
|
||||
KeyEvent.VK_DOWN -> moveHistoryCursor(HistoryMove.DOWN)
|
||||
KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT -> prevCaretOffset = consoleEditor.caretModel.offset
|
||||
}
|
||||
|
||||
private fun moveHistoryCursor(move: HistoryMove) {
|
||||
if (history.isEmpty()) return
|
||||
if (history.size == 0) return
|
||||
if (LookupManager.getInstance(project).activeLookup != null) return
|
||||
|
||||
val caret = consoleEditor.caretModel
|
||||
@@ -74,29 +67,29 @@ public class KotlinConsoleHistoryManager(private val runner: KotlinConsoleRunner
|
||||
return
|
||||
}
|
||||
|
||||
if (historyPos == history.size()) {
|
||||
if (historyPos == history.size) {
|
||||
unfinishedCommand = document.text
|
||||
}
|
||||
|
||||
historyPos = Math.max(historyPos - 1, 0)
|
||||
WriteCommandAction.runWriteCommandAction(project) {
|
||||
document.setText(history[historyPos])
|
||||
document.setText(history[historyPos].entryText)
|
||||
EditorUtil.scrollToTheEnd(consoleEditor)
|
||||
prevCaretOffset = 0
|
||||
caret.moveToOffset(0)
|
||||
}
|
||||
}
|
||||
HistoryMove.DOWN -> {
|
||||
if (historyPos == history.size()) return
|
||||
if (historyPos == history.size) return
|
||||
|
||||
if (curLine != totalLines - 1 || (isMultiline && prevCaretOffset != document.textLength)) {
|
||||
prevCaretOffset = curOffset
|
||||
return
|
||||
}
|
||||
|
||||
historyPos = Math.min(historyPos + 1, history.size())
|
||||
historyPos = Math.min(historyPos + 1, history.size)
|
||||
WriteCommandAction.runWriteCommandAction(project) {
|
||||
document.setText(if (historyPos == history.size()) unfinishedCommand else history[historyPos])
|
||||
document.setText(if (historyPos == history.size) unfinishedCommand else history[historyPos].entryText)
|
||||
prevCaretOffset = document.textLength
|
||||
EditorUtil.scrollToTheEnd(consoleEditor)
|
||||
}
|
||||
+11
-21
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.console.highlight
|
||||
package org.jetbrains.kotlin.console
|
||||
|
||||
import com.intellij.execution.console.LanguageConsoleImpl
|
||||
import com.intellij.openapi.editor.ex.EditorEx
|
||||
@@ -22,28 +22,17 @@ import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||
import com.intellij.openapi.editor.markup.HighlighterLayer
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleRunner
|
||||
import org.jetbrains.kotlin.console.gutter.KotlinConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ReplIcons
|
||||
|
||||
public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner ) {
|
||||
public class HistoryUpdater(private val runner: KotlinConsoleRunner) {
|
||||
private val consoleView: LanguageConsoleImpl by lazy { runner.consoleView as LanguageConsoleImpl }
|
||||
|
||||
var isReadLineMode: Boolean = false
|
||||
set(value) {
|
||||
if (value)
|
||||
runner.changeConsoleEditorIndicator(ReplIcons.EDITOR_READLINE_INDICATOR)
|
||||
else
|
||||
runner.changeConsoleEditorIndicator(ReplIcons.EDITOR_INDICATOR)
|
||||
|
||||
field = value
|
||||
}
|
||||
|
||||
fun printNewCommandInHistory(trimmedCommandText: String) {
|
||||
fun printNewCommandInHistory(trimmedCommandText: String): TextRange {
|
||||
val historyEditor = consoleView.historyViewer
|
||||
addLineBreakIfNeeded(historyEditor)
|
||||
val startOffset = historyEditor.document.textLength
|
||||
val endOffset = startOffset + trimmedCommandText.length()
|
||||
val endOffset = startOffset + trimmedCommandText.length
|
||||
|
||||
addCommandTextToHistoryEditor(trimmedCommandText)
|
||||
EditorUtil.scrollToTheEnd(historyEditor)
|
||||
@@ -52,9 +41,10 @@ public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner )
|
||||
historyEditor.markupModel.addRangeHighlighter(
|
||||
startOffset, endOffset, HighlighterLayer.LAST, null, HighlighterTargetArea.EXACT_RANGE
|
||||
).apply {
|
||||
val historyMarker = if (isReadLineMode) ReplIcons.READLINE_MARKER else ReplIcons.COMMAND_MARKER
|
||||
gutterIconRenderer = KotlinConsoleIndicatorRenderer(historyMarker)
|
||||
val historyMarker = if (runner.isReadLineMode) ReplIcons.READLINE_MARKER else ReplIcons.COMMAND_MARKER
|
||||
gutterIconRenderer = ConsoleIndicatorRenderer(historyMarker)
|
||||
}
|
||||
return TextRange(startOffset, endOffset)
|
||||
}
|
||||
|
||||
private fun addCommandTextToHistoryEditor(trimmedCommandText: String) {
|
||||
@@ -67,11 +57,11 @@ public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner )
|
||||
}
|
||||
|
||||
private fun addLineBreakIfNeeded(historyEditor: EditorEx) {
|
||||
if (isReadLineMode) return
|
||||
if (runner.isReadLineMode) return
|
||||
|
||||
val historyDocument = historyEditor.document
|
||||
val historyText = historyDocument.text
|
||||
val textLength = historyText.length()
|
||||
val textLength = historyText.length
|
||||
|
||||
if (!historyText.endsWith('\n')) {
|
||||
historyDocument.insertString(textLength, "\n")
|
||||
@@ -88,7 +78,7 @@ public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner )
|
||||
|
||||
private fun addFoldingRegion(historyEditor: EditorEx, startOffset: Int, endOffset: Int, command: String) {
|
||||
val cmdLines = command.lines()
|
||||
val linesCount = cmdLines.size()
|
||||
val linesCount = cmdLines.size
|
||||
if (linesCount < 2) return
|
||||
|
||||
val foldingModel = historyEditor.foldingModel
|
||||
@@ -40,15 +40,15 @@ private val REPL_TITLE = "Kotlin REPL"
|
||||
public class KotlinConsoleKeeper(val project: Project) {
|
||||
private val consoleMap: MutableMap<VirtualFile, KotlinConsoleRunner> = ConcurrentHashMap()
|
||||
|
||||
fun getConsoleByVirtualFile(virtualFile: VirtualFile) = consoleMap.get(virtualFile)
|
||||
fun getConsoleByVirtualFile(virtualFile: VirtualFile) = consoleMap[virtualFile]
|
||||
fun putVirtualFileToConsole(virtualFile: VirtualFile, console: KotlinConsoleRunner) = consoleMap.put(virtualFile, console)
|
||||
fun removeConsole(virtualFile: VirtualFile) = consoleMap.remove(virtualFile)
|
||||
|
||||
fun run(module: Module, testMode: Boolean = false, previousCompilationFailed: Boolean = false): KotlinConsoleRunner? {
|
||||
fun run(module: Module, previousCompilationFailed: Boolean = false): KotlinConsoleRunner? {
|
||||
val path = module.moduleFilePath
|
||||
val cmdLine = createCommandLine(module) ?: return run { errorNotification(project, "Module SDK not found"); null }
|
||||
|
||||
val consoleRunner = KotlinConsoleRunner(module, cmdLine, testMode, previousCompilationFailed, project, REPL_TITLE, path)
|
||||
val consoleRunner = KotlinConsoleRunner(module, cmdLine, previousCompilationFailed, project, REPL_TITLE, path)
|
||||
consoleRunner.initAndRun()
|
||||
consoleRunner.setupGutters()
|
||||
|
||||
@@ -103,7 +103,7 @@ public class KotlinConsoleKeeper(val project: Project) {
|
||||
}
|
||||
|
||||
private fun addPathToCompiledOutput(paramList: ParametersList, module: Module) {
|
||||
val compiledModulePath = CompilerPathsEx.getOutputPaths(arrayOf(module)).join(File.pathSeparator)
|
||||
val compiledModulePath = CompilerPathsEx.getOutputPaths(arrayOf(module)).joinToString(File.pathSeparator)
|
||||
val moduleDependencies = OrderEnumerator.orderEntries(module).recursively().pathsList.pathsString
|
||||
val compiledOutputClasspath = "$compiledModulePath${File.pathSeparator}$moduleDependencies"
|
||||
|
||||
|
||||
@@ -47,12 +47,9 @@ import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.console.actions.BuildAndRestartConsoleAction
|
||||
import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction
|
||||
import org.jetbrains.kotlin.console.gutter.IconWithTooltip
|
||||
import org.jetbrains.kotlin.console.gutter.KotlinConsoleGutterContentProvider
|
||||
import org.jetbrains.kotlin.console.gutter.KotlinConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ConsoleGutterContentProvider
|
||||
import org.jetbrains.kotlin.console.gutter.ConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ReplIcons
|
||||
import org.jetbrains.kotlin.console.highlight.KotlinHistoryHighlighter
|
||||
import org.jetbrains.kotlin.console.highlight.KotlinReplOutputHighlighter
|
||||
import org.jetbrains.kotlin.console.highlight.ReplColors
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.completion.doNotComplete
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -65,26 +62,38 @@ private val KOTLIN_SHELL_EXECUTE_ACTION_ID = "KotlinShellExecute"
|
||||
public class KotlinConsoleRunner(
|
||||
val module: Module,
|
||||
private val cmdLine: GeneralCommandLine,
|
||||
private val testMode: Boolean,
|
||||
private val previousCompilationFailed: Boolean,
|
||||
internal val previousCompilationFailed: Boolean,
|
||||
myProject: Project,
|
||||
title: String,
|
||||
path: String?
|
||||
) : AbstractConsoleRunnerWithHistory<LanguageConsoleView>(myProject, title, path) {
|
||||
private val historyManager = KotlinConsoleHistoryManager(this)
|
||||
private val historyHighlighter = KotlinHistoryHighlighter(this)
|
||||
internal val commandHistory = CommandHistory()
|
||||
|
||||
var isReadLineMode: Boolean = false
|
||||
set(value) {
|
||||
if (value)
|
||||
changeConsoleEditorIndicator(ReplIcons.EDITOR_READLINE_INDICATOR)
|
||||
else
|
||||
changeConsoleEditorIndicator(ReplIcons.EDITOR_INDICATOR)
|
||||
|
||||
field = value
|
||||
}
|
||||
|
||||
fun changeConsoleEditorIndicator(newIconWithTooltip: IconWithTooltip) = WriteCommandAction.runWriteCommandAction(project) {
|
||||
consoleEditorHighlighter.gutterIconRenderer = ConsoleIndicatorRenderer(newIconWithTooltip)
|
||||
}
|
||||
|
||||
private var consoleEditorHighlighter by Delegates.notNull<RangeHighlighter>()
|
||||
private var disposableDescriptor by Delegates.notNull<RunContentDescriptor>()
|
||||
|
||||
val executor = KotlinConsoleExecutor(this, historyManager, historyHighlighter)
|
||||
var compilerHelper: KotlinConsoleCompilerHelper by Delegates.notNull()
|
||||
val executor = CommandExecutor(this)
|
||||
var compilerHelper: ConsoleCompilerHelper by Delegates.notNull()
|
||||
|
||||
override fun createProcess() = cmdLine.createProcess()
|
||||
|
||||
override fun createConsoleView(): LanguageConsoleView? {
|
||||
val consoleView = LanguageConsoleBuilder()
|
||||
.gutterContentProvider(KotlinConsoleGutterContentProvider())
|
||||
.gutterContentProvider(ConsoleGutterContentProvider())
|
||||
.build(project, KotlinLanguage.INSTANCE)
|
||||
|
||||
consoleView.prompt = null
|
||||
@@ -94,7 +103,9 @@ public class KotlinConsoleRunner(
|
||||
val consoleEditor = consoleView.consoleEditor
|
||||
|
||||
setupPlaceholder(consoleEditor)
|
||||
consoleEditor.contentComponent.addKeyListener(historyManager)
|
||||
val historyKeyListener = HistoryKeyListener(module.project, consoleEditor, commandHistory)
|
||||
consoleEditor.contentComponent.addKeyListener(historyKeyListener)
|
||||
commandHistory.listeners.add(historyKeyListener)
|
||||
|
||||
val executeAction = KtExecuteCommandAction(consoleView.virtualFile)
|
||||
executeAction.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, consoleView.consoleEditor.component)
|
||||
@@ -103,9 +114,8 @@ public class KotlinConsoleRunner(
|
||||
}
|
||||
|
||||
override fun createProcessHandler(process: Process): OSProcessHandler {
|
||||
val processHandler = KotlinReplOutputHandler(
|
||||
historyHighlighter,
|
||||
KotlinReplOutputHighlighter(this, historyManager, testMode, previousCompilationFailed),
|
||||
val processHandler = ReplOutputHandler(
|
||||
this,
|
||||
process,
|
||||
cmdLine.commandLineString
|
||||
)
|
||||
@@ -131,7 +141,7 @@ public class KotlinConsoleRunner(
|
||||
contentDescriptor: RunContentDescriptor
|
||||
): List<AnAction> {
|
||||
disposableDescriptor = contentDescriptor
|
||||
compilerHelper = KotlinConsoleCompilerHelper(project, module, defaultExecutor, contentDescriptor)
|
||||
compilerHelper = ConsoleCompilerHelper(project, module, defaultExecutor, contentDescriptor)
|
||||
|
||||
val actionList = arrayListOf<AnAction>(
|
||||
BuildAndRestartConsoleAction(this),
|
||||
@@ -192,17 +202,13 @@ public class KotlinConsoleRunner(
|
||||
}
|
||||
|
||||
fun addGutterIndicator(editor: EditorEx, iconWithTooltip: IconWithTooltip): RangeHighlighter {
|
||||
val indicator = KotlinConsoleIndicatorRenderer(iconWithTooltip)
|
||||
val indicator = ConsoleIndicatorRenderer(iconWithTooltip)
|
||||
val editorMarkup = editor.markupModel
|
||||
val indicatorHighlighter = editorMarkup.addRangeHighlighter(
|
||||
0, editor.document.textLength, HighlighterLayer.LAST, null, HighlighterTargetArea.LINES_IN_RANGE
|
||||
)
|
||||
|
||||
return indicatorHighlighter apply { gutterIconRenderer = indicator }
|
||||
}
|
||||
|
||||
fun changeConsoleEditorIndicator(newIconWithTooltip: IconWithTooltip) = WriteCommandAction.runWriteCommandAction(project) {
|
||||
consoleEditorHighlighter.gutterIconRenderer = KotlinConsoleIndicatorRenderer(newIconWithTooltip)
|
||||
return indicatorHighlighter.apply { gutterIconRenderer = indicator }
|
||||
}
|
||||
|
||||
@TestOnly fun dispose() {
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.console.highlight
|
||||
package org.jetbrains.kotlin.console
|
||||
|
||||
import com.intellij.execution.ui.ConsoleViewContentType
|
||||
import com.intellij.openapi.editor.markup.TextAttributes
|
||||
@@ -31,16 +31,16 @@ public object ReplColors {
|
||||
public val WARNING_INFO_CONTENT_TYPE: ConsoleViewContentType =
|
||||
ConsoleViewContentType(
|
||||
"KOTLIN_CONSOLE_WARNING_INFO",
|
||||
TextAttributes() apply { fontType = Font.ITALIC; foregroundColor = JBColor.RED }
|
||||
TextAttributes().apply { fontType = Font.ITALIC; foregroundColor = JBColor.RED }
|
||||
)
|
||||
public val INITIAL_PROMPT_CONTENT_TYPE: ConsoleViewContentType =
|
||||
ConsoleViewContentType(
|
||||
"KOTLIN_CONSOLE_INITIAL_PROMPT",
|
||||
TextAttributes() apply { fontType = Font.BOLD }
|
||||
TextAttributes().apply { fontType = Font.BOLD }
|
||||
)
|
||||
public val USER_OUTPUT_CONTENT_TYPE: ConsoleViewContentType =
|
||||
ConsoleViewContentType(
|
||||
"KOTLIN_CONSOLE_USER_OUTPUT",
|
||||
TextAttributes() apply { fontType = Font.ITALIC; foregroundColor = Colors.DARK_GREEN }
|
||||
TextAttributes().apply { fontType = Font.ITALIC; foregroundColor = Colors.DARK_GREEN }
|
||||
)
|
||||
}
|
||||
+13
-15
@@ -20,8 +20,6 @@ import com.intellij.execution.process.OSProcessHandler
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.console.highlight.KotlinHistoryHighlighter
|
||||
import org.jetbrains.kotlin.console.highlight.KotlinReplOutputHighlighter
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.w3c.dom.Element
|
||||
import org.xml.sax.InputSource
|
||||
@@ -36,15 +34,15 @@ public val SOURCE_CHARS: Array<String> = arrayOf("\n", "#")
|
||||
|
||||
data class SeverityDetails(val severity: Severity, val description: String, val range: TextRange)
|
||||
|
||||
public class KotlinReplOutputHandler(
|
||||
private val historyHighlighter: KotlinHistoryHighlighter,
|
||||
private val outputHighlighter: KotlinReplOutputHighlighter,
|
||||
class ReplOutputHandler(
|
||||
private val runner: KotlinConsoleRunner,
|
||||
process: Process,
|
||||
commandLine: String
|
||||
) : OSProcessHandler(process, commandLine) {
|
||||
|
||||
private var isBuildInfoChecked = false
|
||||
private val dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
private val outputProcessor = ReplOutputProcessor(runner)
|
||||
|
||||
override fun isSilentlyDestroyOnClose() = true
|
||||
|
||||
@@ -62,24 +60,24 @@ public class KotlinReplOutputHandler(
|
||||
|
||||
when (outputType) {
|
||||
"INITIAL_PROMPT" -> buildWarningIfNeededBeforeInit(content)
|
||||
"HELP_PROMPT" -> outputHighlighter.printHelp(content)
|
||||
"USER_OUTPUT" -> outputHighlighter.printUserOutput(content)
|
||||
"REPL_RESULT" -> outputHighlighter.printResultWithGutterIcon(content)
|
||||
"READLINE_START" -> historyHighlighter.isReadLineMode = true
|
||||
"READLINE_END" -> historyHighlighter.isReadLineMode = false
|
||||
"HELP_PROMPT" -> outputProcessor.printHelp(content)
|
||||
"USER_OUTPUT" -> outputProcessor.printUserOutput(content)
|
||||
"REPL_RESULT" -> outputProcessor.printResultWithGutterIcon(content)
|
||||
"READLINE_START" -> runner.isReadLineMode = true
|
||||
"READLINE_END" -> runner.isReadLineMode = false
|
||||
"REPL_INCOMPLETE",
|
||||
"COMPILE_ERROR" -> outputHighlighter.highlightCompilerErrors(createCompilerMessages(content))
|
||||
"RUNTIME_ERROR" -> outputHighlighter.printRuntimeError("${content.trim()}\n")
|
||||
"INTERNAL_ERROR" -> outputHighlighter.printInternalErrorMessage(content)
|
||||
"COMPILE_ERROR" -> outputProcessor.highlightCompilerErrors(createCompilerMessages(content))
|
||||
"RUNTIME_ERROR" -> outputProcessor.printRuntimeError("${content.trim()}\n")
|
||||
"INTERNAL_ERROR" -> outputProcessor.printInternalErrorMessage(content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildWarningIfNeededBeforeInit(content: String) {
|
||||
if (!isBuildInfoChecked) {
|
||||
outputHighlighter.printBuildInfoWarningIfNeeded()
|
||||
outputProcessor.printBuildInfoWarningIfNeeded()
|
||||
isBuildInfoChecked = true
|
||||
}
|
||||
outputHighlighter.printInitialPrompt(content)
|
||||
outputProcessor.printInitialPrompt(content)
|
||||
}
|
||||
|
||||
private fun strToSource(s: String, encoding: Charset = Charsets.UTF_8) = InputSource(ByteArrayInputStream(s.toByteArray(encoding)))
|
||||
+15
-19
@@ -14,13 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.console.highlight
|
||||
package org.jetbrains.kotlin.console
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
|
||||
import com.intellij.execution.console.LanguageConsoleImpl
|
||||
import com.intellij.execution.ui.ConsoleViewContentType
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey
|
||||
@@ -28,21 +29,15 @@ import com.intellij.openapi.editor.markup.HighlighterLayer
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||
import com.intellij.openapi.editor.markup.TextAttributes
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleHistoryManager
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleRunner
|
||||
import org.jetbrains.kotlin.console.SeverityDetails
|
||||
import org.jetbrains.kotlin.console.actions.logError
|
||||
import org.jetbrains.kotlin.console.gutter.IconWithTooltip
|
||||
import org.jetbrains.kotlin.console.gutter.KotlinConsoleErrorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.KotlinConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ConsoleErrorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.ReplIcons
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
|
||||
public class KotlinReplOutputHighlighter(
|
||||
private val runner: KotlinConsoleRunner,
|
||||
private val historyManager: KotlinConsoleHistoryManager,
|
||||
private val testMode: Boolean,
|
||||
private val previousCompilationFailed: Boolean
|
||||
public class ReplOutputProcessor(
|
||||
private val runner: KotlinConsoleRunner
|
||||
) {
|
||||
private val project = runner.project
|
||||
private val consoleView = runner.consoleView as LanguageConsoleImpl
|
||||
@@ -53,7 +48,7 @@ public class KotlinReplOutputHighlighter(
|
||||
private fun textOffsets(text: String): Pair<Int, Int> {
|
||||
consoleView.flushDeferredText() // flush before getting offsets to calculate them properly
|
||||
val oldLen = historyDocument.textLength
|
||||
val newLen = oldLen + text.length()
|
||||
val newLen = oldLen + text.length
|
||||
|
||||
return Pair(oldLen, newLen)
|
||||
}
|
||||
@@ -68,7 +63,7 @@ public class KotlinReplOutputHighlighter(
|
||||
|
||||
historyMarkup.addRangeHighlighter(
|
||||
startOffset, endOffset, HighlighterLayer.LAST, null, HighlighterTargetArea.EXACT_RANGE
|
||||
) apply { gutterIconRenderer = KotlinConsoleIndicatorRenderer(iconWithTooltip) }
|
||||
).apply { gutterIconRenderer = ConsoleIndicatorRenderer(iconWithTooltip) }
|
||||
}
|
||||
|
||||
private fun printWarningMessage(message: String, isAddHyperlink: Boolean) = WriteCommandAction.runWriteCommandAction(project) {
|
||||
@@ -86,8 +81,8 @@ public class KotlinReplOutputHighlighter(
|
||||
}
|
||||
|
||||
fun printBuildInfoWarningIfNeeded() {
|
||||
if (testMode) return
|
||||
if (previousCompilationFailed) return printWarningMessage("There were compilation errors in module ${runner.module.name}", false)
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) return
|
||||
if (runner.previousCompilationFailed) return printWarningMessage("There were compilation errors in module ${runner.module.name}", false)
|
||||
if (runner.compilerHelper.moduleIsUpToDate()) return
|
||||
|
||||
val compilerWarningMessage = "You’re running the REPL with outdated classes: "
|
||||
@@ -109,7 +104,8 @@ public class KotlinReplOutputHighlighter(
|
||||
}
|
||||
|
||||
fun highlightCompilerErrors(compilerMessages: List<SeverityDetails>) = WriteCommandAction.runWriteCommandAction(project) {
|
||||
val lastCommandStartOffset = historyDocument.textLength - historyManager.lastCommandLength - 1
|
||||
val commandHistory = runner.commandHistory
|
||||
val lastCommandStartOffset = historyDocument.textLength - commandHistory[commandHistory.size - 1].entryText.length - 1
|
||||
val lastCommandStartLine = historyDocument.getLineNumber(lastCommandStartOffset)
|
||||
val historyCommandRunIndicator = historyMarkup.allHighlighters.filter {
|
||||
historyDocument.getLineNumber(it.startOffset) == lastCommandStartLine && it.gutterIconRenderer != null
|
||||
@@ -120,7 +116,7 @@ public class KotlinReplOutputHighlighter(
|
||||
}.groupBy { message ->
|
||||
val cmdStart = lastCommandStartOffset + message.range.startOffset
|
||||
historyEditor.document.getLineNumber(cmdStart)
|
||||
}.values().map { messages ->
|
||||
}.values.map { messages ->
|
||||
val highlighters = messages.map { message ->
|
||||
val cmdStart = lastCommandStartOffset + message.range.startOffset
|
||||
val cmdEnd = lastCommandStartOffset + Math.max(message.range.endOffset, message.range.startOffset + 1)
|
||||
@@ -135,9 +131,9 @@ public class KotlinReplOutputHighlighter(
|
||||
|
||||
for ((highlighter, messages) in highlighterAndMessagesByLine) {
|
||||
if (historyDocument.getLineNumber(highlighter.startOffset) == lastCommandStartLine)
|
||||
historyCommandRunIndicator.gutterIconRenderer = KotlinConsoleErrorRenderer(messages)
|
||||
historyCommandRunIndicator.gutterIconRenderer = ConsoleErrorRenderer(messages)
|
||||
else
|
||||
highlighter.gutterIconRenderer = KotlinConsoleErrorRenderer(messages)
|
||||
highlighter.gutterIconRenderer = ConsoleErrorRenderer(messages)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
|
||||
|
||||
public class KotlinConsoleModuleDialog(private val project: Project) {
|
||||
public class ConsoleModuleDialog(private val project: Project) {
|
||||
private val TITLE = "Choose context module..."
|
||||
|
||||
public fun showIfNeeded(dataContext: DataContext) {
|
||||
@@ -34,9 +34,9 @@ public class KotlinConsoleModuleDialog(private val project: Project) {
|
||||
val modules = ModuleManager.getInstance(project).modules
|
||||
|
||||
if (modules.isEmpty()) return errorNotification(project, "No modules were found")
|
||||
if (modules.size() == 1) return runConsole(modules.first())
|
||||
if (modules.size == 1) return runConsole(modules.first())
|
||||
|
||||
val moduleActions = modules sortedBy { it.name } map { createRunAction(it) }
|
||||
val moduleActions = modules.sortedBy { it.name }.map { createRunAction(it) }
|
||||
val moduleGroup = DefaultActionGroup(moduleActions)
|
||||
|
||||
val modulePopup = JBPopupFactory.getInstance().createActionGroupPopup(
|
||||
@@ -40,7 +40,7 @@ public class RunKotlinConsoleAction : AnAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return errorNotification(null, "Project not found")
|
||||
|
||||
KotlinConsoleModuleDialog(project).showIfNeeded(e.dataContext)
|
||||
ConsoleModuleDialog(project).showIfNeeded(e.dataContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import com.intellij.openapi.editor.markup.GutterIconRenderer
|
||||
import org.jetbrains.kotlin.console.SeverityDetails
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
|
||||
public class KotlinConsoleErrorRenderer(private val messages: List<SeverityDetails>) : GutterIconRenderer() {
|
||||
public class ConsoleErrorRenderer(private val messages: List<SeverityDetails>) : GutterIconRenderer() {
|
||||
private fun msgType(severity: Severity) = when (severity) {
|
||||
Severity.ERROR -> "Error:"
|
||||
Severity.WARNING -> "Warning:"
|
||||
+1
-1
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.console.gutter
|
||||
import com.intellij.execution.console.BasicGutterContentProvider
|
||||
import com.intellij.openapi.editor.Editor
|
||||
|
||||
public class KotlinConsoleGutterContentProvider : BasicGutterContentProvider() {
|
||||
public class ConsoleGutterContentProvider : BasicGutterContentProvider() {
|
||||
/**
|
||||
* This method overriding is needed to prevent [BasicGutterContentProvider] from adding some strange unicode
|
||||
* symbols of zero width and to ease range highlighting.
|
||||
+2
-2
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.console.gutter
|
||||
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer
|
||||
|
||||
public class KotlinConsoleIndicatorRenderer(iconWithTooltip: IconWithTooltip) : GutterIconRenderer() {
|
||||
public class ConsoleIndicatorRenderer(iconWithTooltip: IconWithTooltip) : GutterIconRenderer() {
|
||||
private val icon = iconWithTooltip.icon
|
||||
private val tooltip = iconWithTooltip.tooltip
|
||||
|
||||
@@ -26,5 +26,5 @@ public class KotlinConsoleIndicatorRenderer(iconWithTooltip: IconWithTooltip) :
|
||||
override fun getTooltipText() = tooltip
|
||||
|
||||
override fun hashCode() = icon.hashCode()
|
||||
override fun equals(other: Any?) = icon == (other as? KotlinConsoleIndicatorRenderer)?.icon ?: null
|
||||
override fun equals(other: Any?) = icon == (other as? ConsoleIndicatorRenderer)?.icon ?: null
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class KotlinReplTest : PlatformTestCase() {
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module, testMode = true)!!
|
||||
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!!
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
|
||||
Reference in New Issue
Block a user