From 3152792860f619a8c8f1a017e726a66768e77182 Mon Sep 17 00:00:00 2001 From: Dmitry Kovanikov Date: Tue, 25 Aug 2015 18:04:24 +0300 Subject: [PATCH] [ide-console][bug-fixes] Disable process on closed dialog window Fix history bugs (lost completion focus, occasional flush) Faster incomplete icon change Correct console window title Other small gui decorations --- .../console/KotlinConsoleHistoryManager.kt | 25 +++++++++++++------ .../kotlin/console/KotlinConsoleKeeper.kt | 6 ++--- .../kotlin/console/KotlinConsoleRunner.kt | 24 ++++++++++++------ .../kotlin/console/KotlinReplOutputHandler.kt | 2 ++ .../gutter/KotlinConsoleIndicatorRenderer.kt | 6 ++--- .../highlight/KotlinReplOutputHighlighter.kt | 9 ++++--- 6 files changed, 48 insertions(+), 24 deletions(-) diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt index 19299a27085..79173aea850 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleHistoryManager.kt @@ -16,12 +16,18 @@ package org.jetbrains.kotlin.console +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 org.jetbrains.kotlin.console.highlight.ReplOutputType import java.awt.event.KeyAdapter import java.awt.event.KeyEvent -public class KotlinConsoleHistoryManager(private val ktConsole: KotlinConsoleRunner) : KeyAdapter() { +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() private var historyPos = 0 @@ -52,14 +58,15 @@ public class KotlinConsoleHistoryManager(private val ktConsole: KotlinConsoleRun override fun keyReleased(e: KeyEvent): Unit = when (e.keyCode) { KeyEvent.VK_UP -> moveHistoryCursor(HistoryMove.UP) KeyEvent.VK_DOWN -> moveHistoryCursor(HistoryMove.DOWN) - KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT -> prevCaretOffset = ktConsole.consoleView.consoleEditor.caretModel.offset + KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT -> prevCaretOffset = consoleEditor.caretModel.offset } private fun moveHistoryCursor(move: HistoryMove) { if (history.isEmpty()) return + if (LookupManager.getInstance(project).activeLookup != null) return - val caret = ktConsole.consoleView.consoleEditor.caretModel - val document = ktConsole.consoleView.editorDocument + val caret = consoleEditor.caretModel + val document = consoleEditor.document val curOffset = caret.offset val curLine = document.getLineNumber(curOffset) @@ -78,23 +85,27 @@ public class KotlinConsoleHistoryManager(private val ktConsole: KotlinConsoleRun } historyPos = Math.max(historyPos - 1, 0) - WriteCommandAction.runWriteCommandAction(ktConsole.project) { + WriteCommandAction.runWriteCommandAction(project) { document.setText(history[historyPos].trim()) - caret.moveToOffset(0) + EditorUtil.scrollToTheEnd(consoleEditor) prevCaretOffset = 0 + caret.moveToOffset(0) } } HistoryMove.DOWN -> { + if (historyPos == history.size()) return + if (curLine != totalLines - 1 || (isMultiline && prevCaretOffset != document.textLength)) { prevCaretOffset = curOffset return } historyPos = Math.min(historyPos + 1, history.size()) - WriteCommandAction.runWriteCommandAction(ktConsole.project) { + WriteCommandAction.runWriteCommandAction(project) { document.setText(if (historyPos == history.size()) unfinishedCommand else history[historyPos].trim()) caret.moveToOffset(document.textLength) prevCaretOffset = document.textLength + EditorUtil.scrollToTheEnd(consoleEditor) } } } 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 8ecc4aabad2..0748bea03d0 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleKeeper.kt @@ -35,6 +35,8 @@ import org.jetbrains.kotlin.utils.PathUtil import java.io.File import java.util.concurrent.ConcurrentHashMap +private val REPL_TITLE = "Kotlin REPL" + public class KotlinConsoleKeeper(val project: Project) { private val consoleMap: MutableMap = ConcurrentHashMap() @@ -46,7 +48,7 @@ public class KotlinConsoleKeeper(val project: Project) { val path = module.moduleFilePath val cmdLine = createCommandLine(module) ?: return errorNotification(project, "Module SDK not found") let { null } - val consoleRunner = KotlinConsoleRunner(path, cmdLine, module, project, REPL_TITLE) + val consoleRunner = KotlinConsoleRunner(cmdLine, module, project, REPL_TITLE, path) consoleRunner.initAndRun() consoleRunner.setupGutters() @@ -110,8 +112,6 @@ public class KotlinConsoleKeeper(val project: Project) { } companion object { - private val REPL_TITLE = "Kotlin REPL" - jvmStatic fun getInstance(project: Project) = ServiceManager.getService(project, javaClass()) } } \ No newline at end of file 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 6f26e039c53..68c368c0cec 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt @@ -23,6 +23,7 @@ import com.intellij.execution.process.* import com.intellij.execution.runners.AbstractConsoleRunnerWithHistory import com.intellij.execution.ui.RunContentDescriptor import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.editor.colors.EditorColors import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.markup.* @@ -47,13 +48,13 @@ import java.util.concurrent.ConcurrentHashMap import javax.swing.Icon public class KotlinConsoleRunner( - private val title: String, private val cmdLine: GeneralCommandLine, private val module: Module, myProject: Project, + title: String, path: String? ) : AbstractConsoleRunnerWithHistory(myProject, title, path) { - private val editorToIndicator = ConcurrentHashMap() + private val editorToIndicator = ConcurrentHashMap() private val historyManager = KotlinConsoleHistoryManager(this) val executor = KotlinConsoleExecutor(this, historyManager) @@ -119,6 +120,8 @@ public class KotlinConsoleRunner( } } + override fun constructConsoleTitle(title: String) = "$title (in module ${module.name})" + private fun setupPlaceholder(editor: EditorEx) { editor.setPlaceholder(" to execute") editor.setShowPlaceholderWhenFocused(true) @@ -147,10 +150,16 @@ public class KotlinConsoleRunner( addGutterIndicator(editor, icon) } - configureEditorGutter(consoleView.historyViewer, ReplColors.HISTORY_GUTTER_COLOR, ReplIcons.HISTORY_INDICATOR) - configureEditorGutter(consoleView.consoleEditor, ReplColors.EDITOR_GUTTER_COLOR, ReplIcons.EDITOR_INDICATOR) + val historyEditor = consoleView.historyViewer + val consoleEditor = consoleView.consoleEditor - consoleView.consoleEditor.settings.isCaretRowShown = true + configureEditorGutter(historyEditor, ReplColors.HISTORY_GUTTER_COLOR, ReplIcons.HISTORY_INDICATOR) + configureEditorGutter(consoleEditor, ReplColors.EDITOR_GUTTER_COLOR, ReplIcons.EDITOR_INDICATOR) + + historyEditor.settings.isUseSoftWraps = true + + consoleEditor.settings.isCaretRowShown = true + consoleEditor.settings.additionalLinesCount = 2 } fun addGutterIndicator(editor: EditorEx, icon: Icon) { @@ -161,10 +170,11 @@ public class KotlinConsoleRunner( ) indicatorHighlighter.gutterIconRenderer = indicator - editorToIndicator[editor] = indicator + editorToIndicator[editor] = indicatorHighlighter } fun changeEditorIndicatorIcon(editor: EditorEx, newIcon: Icon) { - editorToIndicator[editor]?.indicatorIcon = newIcon + val oldHighlighter = editorToIndicator[editor] ?: return + WriteCommandAction.runWriteCommandAction(project) { oldHighlighter.gutterIconRenderer = KotlinConsoleIndicatorRenderer(newIcon) } } } \ 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/KotlinReplOutputHandler.kt index 73100365532..cb4880fdc31 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinReplOutputHandler.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinReplOutputHandler.kt @@ -44,6 +44,8 @@ public class KotlinReplOutputHandler( private val dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder() + override fun isSilentlyDestroyOnClose() = true + override fun notifyTextAvailable(text: String, key: Key<*>?) { // skip "/usr/lib/jvm/java-8-oracle/bin/java -cp ..." intro if (!text.startsWith(XML_PREFIX)) return super.notifyTextAvailable(text, key) diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt index 5e922e818cf..6b5dfbc8d39 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/gutter/KotlinConsoleIndicatorRenderer.kt @@ -19,8 +19,8 @@ package org.jetbrains.kotlin.console.gutter import com.intellij.openapi.editor.markup.GutterIconRenderer import javax.swing.Icon -public class KotlinConsoleIndicatorRenderer(var indicatorIcon: Icon) : GutterIconRenderer() { +public class KotlinConsoleIndicatorRenderer(private val indicatorIcon: Icon) : GutterIconRenderer() { override fun getIcon() = indicatorIcon - override fun hashCode() = System.identityHashCode(this) - override fun equals(other: Any?) = this === other + override fun hashCode() = indicatorIcon.hashCode() + override fun equals(other: Any?) = indicatorIcon == (other as? KotlinConsoleIndicatorRenderer)?.indicatorIcon ?: null } \ No newline at end of file diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt index ed2fcc2f66c..c8f274af405 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/highlight/KotlinReplOutputHighlighter.kt @@ -47,6 +47,7 @@ public class KotlinReplOutputHighlighter( private val runner: KotlinConsoleRunner, private val historyManager: KotlinConsoleHistoryManager ) { + private val project = runner.project private val consoleView = runner.consoleView private val historyEditor = consoleView.historyViewer private val historyDocument = historyEditor.document @@ -70,7 +71,7 @@ public class KotlinReplOutputHighlighter( consoleView.print(command, ReplColors.USER_OUTPUT_CONTENT_TYPE) } - fun printResultWithGutterIcon(result: String) = WriteCommandAction.runWriteCommandAction(runner.project) { + fun printResultWithGutterIcon(result: String) = WriteCommandAction.runWriteCommandAction(project) { resetConsoleEditorIndicator() historyManager.lastCommandType = ReplOutputType.RESULT @@ -85,7 +86,7 @@ public class KotlinReplOutputHighlighter( runner.changeEditorIndicatorIcon(consoleView.consoleEditor, ReplIcons.INCOMPLETE_INDICATOR) } - fun highlightCompilerErrors(compilerMessages: List) = WriteCommandAction.runWriteCommandAction(runner.project) { + fun highlightCompilerErrors(compilerMessages: List) = WriteCommandAction.runWriteCommandAction(project) { resetConsoleEditorIndicator() historyManager.lastCommandType = ReplOutputType.ERROR @@ -137,8 +138,8 @@ public class KotlinReplOutputHighlighter( ): TextAttributes { val highlightInfo = HighlightInfo.newHighlightInfo(infoType).range(start, end).severity(severity).textAttributes(insightColors).create() - val psiFile = PsiDocumentManager.getInstance(runner.project).getPsiFile(runner.consoleView.consoleEditor.document) - val colorScheme = runner.consoleView.consoleEditor.colorsScheme + val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(consoleView.consoleEditor.document) + val colorScheme = consoleView.consoleEditor.colorsScheme return highlightInfo?.getTextAttributes(psiFile, colorScheme) ?: TextAttributes() }