From 0fe3ef7cf4a1f90539e19cb899009d203112af0c Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 22 Oct 2015 19:06:29 +0300 Subject: [PATCH] Repl: refactor ide code More accurate class names Move all shared state to KotlinConsoleRunner class --- ...nConsoleExecutor.kt => CommandExecutor.kt} | 32 +++++++----- .../kotlin/console/CommandHistory.kt | 43 +++++++++++++++ ...ilerHelper.kt => ConsoleCompilerHelper.kt} | 2 +- ...istoryManager.kt => HistoryKeyListener.kt} | 33 +++++------- ...istoryHighlighter.kt => HistoryUpdater.kt} | 32 ++++-------- .../kotlin/console/KotlinConsoleKeeper.kt | 8 +-- .../kotlin/console/KotlinConsoleRunner.kt | 52 +++++++++++-------- .../console/{highlight => }/ReplColors.kt | 8 +-- ...lOutputHandler.kt => ReplOutputHandler.kt} | 28 +++++----- ...tHighlighter.kt => ReplOutputProcessor.kt} | 34 ++++++------ ...ModuleDialog.kt => ConsoleModuleDialog.kt} | 6 +-- .../console/actions/RunExecuteActions.kt | 2 +- ...rorRenderer.kt => ConsoleErrorRenderer.kt} | 2 +- ...der.kt => ConsoleGutterContentProvider.kt} | 2 +- ...enderer.kt => ConsoleIndicatorRenderer.kt} | 4 +- .../kotlin/idea/console/KotlinReplTest.kt | 2 +- 16 files changed, 160 insertions(+), 130 deletions(-) rename idea/idea-repl/src/org/jetbrains/kotlin/console/{KotlinConsoleExecutor.kt => CommandExecutor.kt} (73%) create mode 100644 idea/idea-repl/src/org/jetbrains/kotlin/console/CommandHistory.kt rename idea/idea-repl/src/org/jetbrains/kotlin/console/{KotlinConsoleCompilerHelper.kt => ConsoleCompilerHelper.kt} (97%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/{KotlinConsoleHistoryManager.kt => HistoryKeyListener.kt} (78%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/{highlight/KotlinHistoryHighlighter.kt => HistoryUpdater.kt} (75%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/{highlight => }/ReplColors.kt (87%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/{KotlinReplOutputHandler.kt => ReplOutputHandler.kt} (77%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/{highlight/KotlinReplOutputHighlighter.kt => ReplOutputProcessor.kt} (87%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/actions/{KotlinConsoleModuleDialog.kt => ConsoleModuleDialog.kt} (91%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/{KotlinConsoleErrorRenderer.kt => ConsoleErrorRenderer.kt} (92%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/{KotlinConsoleGutterContentProvider.kt => ConsoleGutterContentProvider.kt} (92%) rename idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/{KotlinConsoleIndicatorRenderer.kt => ConsoleIndicatorRenderer.kt} (81%) diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleExecutor.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/CommandExecutor.kt similarity index 73% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleExecutor.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/CommandExecutor.kt index 2f3f8844c50..8eb2e07b1ef 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleExecutor.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/CommandExecutor.kt @@ -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 = "" -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, "

Broken process stream

") val charset = (processHandler as? BaseOSProcessHandler)?.charset ?: Charsets.UTF_8 diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/CommandHistory.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/CommandHistory.kt new file mode 100644 index 00000000000..beb228e3f98 --- /dev/null +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/CommandHistory.kt @@ -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() + val listeners = arrayListOf() + + 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) +} \ No newline at end of file diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleCompilerHelper.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt similarity index 97% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleCompilerHelper.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt index 6b05b9c3cb6..ad245ebe23e 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleCompilerHelper.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt @@ -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, diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt similarity index 78% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt index 6431560dd61..65a52301c6d 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt @@ -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() - +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) } diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinHistoryHighlighter.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryUpdater.kt similarity index 75% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinHistoryHighlighter.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryUpdater.kt index 2718887d3ab..c319dd29a30 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinHistoryHighlighter.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryUpdater.kt @@ -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 diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt index acc836fca2d..06eb535492f 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt @@ -40,15 +40,15 @@ private val REPL_TITLE = "Kotlin REPL" public class KotlinConsoleKeeper(val project: Project) { private val consoleMap: MutableMap = 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" diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt index 63ec3c6034f..1ccd8e8328c 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt @@ -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(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() private var disposableDescriptor by Delegates.notNull() - 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 { disposableDescriptor = contentDescriptor - compilerHelper = KotlinConsoleCompilerHelper(project, module, defaultExecutor, contentDescriptor) + compilerHelper = ConsoleCompilerHelper(project, module, defaultExecutor, contentDescriptor) val actionList = arrayListOf( 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() { diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/ReplColors.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplColors.kt similarity index 87% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/ReplColors.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/ReplColors.kt index f11388bc922..baa72ae6124 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/ReplColors.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplColors.kt @@ -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 } ) } \ No newline at end of file diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinReplOutputHandler.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt similarity index 77% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinReplOutputHandler.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt index 1f9aa79fdc7..0d985cc6760 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinReplOutputHandler.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt @@ -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 = 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))) diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputProcessor.kt similarity index 87% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputProcessor.kt index 14bab5c5619..7d7f7c0946e 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputProcessor.kt @@ -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 { 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) = 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) } } diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/KotlinConsoleModuleDialog.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/ConsoleModuleDialog.kt similarity index 91% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/actions/KotlinConsoleModuleDialog.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/actions/ConsoleModuleDialog.kt index 8ab1392132b..bf054e10943 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/KotlinConsoleModuleDialog.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/ConsoleModuleDialog.kt @@ -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( diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/RunExecuteActions.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/RunExecuteActions.kt index f586202c54e..c4ecc056d29 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/RunExecuteActions.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/actions/RunExecuteActions.kt @@ -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) } } diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleErrorRenderer.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleErrorRenderer.kt similarity index 92% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleErrorRenderer.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleErrorRenderer.kt index 84064a56d82..2337ef027b3 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleErrorRenderer.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleErrorRenderer.kt @@ -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) : GutterIconRenderer() { +public class ConsoleErrorRenderer(private val messages: List) : GutterIconRenderer() { private fun msgType(severity: Severity) = when (severity) { Severity.ERROR -> "Error:" Severity.WARNING -> "Warning:" diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleGutterContentProvider.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleGutterContentProvider.kt similarity index 92% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleGutterContentProvider.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleGutterContentProvider.kt index 7f2b8a619db..165c910c81a 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleGutterContentProvider.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleGutterContentProvider.kt @@ -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. diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleIndicatorRenderer.kt similarity index 81% rename from idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt rename to idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleIndicatorRenderer.kt index 9afb08c243b..fe7d616c55e 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/ConsoleIndicatorRenderer.kt @@ -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 } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/console/KotlinReplTest.kt b/idea/tests/org/jetbrains/kotlin/idea/console/KotlinReplTest.kt index 094fbcbd164..4e926cc9bb6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/console/KotlinReplTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/console/KotlinReplTest.kt @@ -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() {