[ide-console][cli-repl] Add more icons for readLine commands

This commit is contained in:
Dmitry Kovanikov
2015-09-04 16:19:40 +03:00
committed by Pavel V. Talanov
parent 724b208a5d
commit b4224bf9f3
8 changed files with 64 additions and 16 deletions
@@ -54,10 +54,16 @@ public class ReplFromTerminal {
String replIdeMode = System.getProperty("repl.ideMode"); String replIdeMode = System.getProperty("repl.ideMode");
ideMode = replIdeMode != null && replIdeMode.equals("true"); ideMode = replIdeMode != null && replIdeMode.equals("true");
// wrapper for `out` is required to escape every input in [ideMode];
// if [ideMode == false] then just redirects all input to [System.out]
// if user calls [System.setOut(...)] then undefined behaviour
replWriter = new ReplSystemOutWrapper(ideMode, System.out);
System.setOut(replWriter);
// wrapper for `in` is required to give user possibility of calling // wrapper for `in` is required to give user possibility of calling
// [readLine] from ide-console repl // [readLine] from ide-console repl
if (ideMode) { if (ideMode) {
replReader = new ReplSystemInWrapper(System.in); replReader = new ReplSystemInWrapper(System.in, replWriter);
System.setIn(replReader); System.setIn(replReader);
} }
@@ -76,12 +82,6 @@ public class ReplFromTerminal {
} }
}.start(); }.start();
// wrapper for `out` is required to escape every input in [ideMode];
// if [ideMode == false] then just redirects all input to [System.out]
// if user calls [System.setOut(...)] then undefined behaviour
replWriter = new ReplSystemOutWrapper(ideMode, System.out);
System.setOut(replWriter);
try { try {
OutputStream outStream = System.out; OutputStream outStream = System.out;
if (ideMode) { if (ideMode) {
@@ -19,7 +19,10 @@ package org.jetbrains.kotlin.cli.jvm.repl.messages
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.InputStream import java.io.InputStream
public class ReplSystemInWrapper(private val stdin: InputStream) : InputStream() { public class ReplSystemInWrapper(
private val stdin: InputStream,
private val replWriter: ReplSystemOutWrapper
) : InputStream() {
private var isXmlIncomplete = true private var isXmlIncomplete = true
private var isLastScriptByteProcessed = false private var isLastScriptByteProcessed = false
private var byteBuilder = ByteArrayOutputStream() private var byteBuilder = ByteArrayOutputStream()
@@ -30,6 +33,14 @@ public class ReplSystemInWrapper(private val stdin: InputStream) : InputStream()
get() = curBytePos == inputByteArray.size() get() = curBytePos == inputByteArray.size()
var isReplScriptExecuting = false var isReplScriptExecuting = false
set(value) {
if (value)
replWriter.printlnReadLineStart()
else
replWriter.printlnReadLineEnd()
$isReplScriptExecuting = value
}
override synchronized fun read(): Int { override synchronized fun read(): Int {
if (isLastScriptByteProcessed && isReplScriptExecuting) { if (isLastScriptByteProcessed && isReplScriptExecuting) {
@@ -29,6 +29,8 @@ public class ReplSystemOutWrapper(private val ideMode: Boolean, standardOut: Pri
HELP_PROMPT, HELP_PROMPT,
USER_OUTPUT, USER_OUTPUT,
REPL_RESULT, REPL_RESULT,
READLINE_START,
READLINE_END,
REPL_INCOMPLETE, REPL_INCOMPLETE,
COMPILE_ERROR, COMPILE_ERROR,
RUNTIME_ERROR, RUNTIME_ERROR,
@@ -61,6 +63,8 @@ public class ReplSystemOutWrapper(private val ideMode: Boolean, standardOut: Pri
fun printlnInit(x: String) = printlnWithEscaping(x, EscapeType.INITIAL_PROMPT) fun printlnInit(x: String) = printlnWithEscaping(x, EscapeType.INITIAL_PROMPT)
fun printlnHelp(x: String) = printlnWithEscaping(x, EscapeType.HELP_PROMPT) fun printlnHelp(x: String) = printlnWithEscaping(x, EscapeType.HELP_PROMPT)
fun printlnResult(x: Any?) = printlnWithEscaping(x.toString(), EscapeType.REPL_RESULT) fun printlnResult(x: Any?) = printlnWithEscaping(x.toString(), EscapeType.REPL_RESULT)
fun printlnReadLineStart() = printlnWithEscaping("", EscapeType.READLINE_START)
fun printlnReadLineEnd() = printlnWithEscaping("", EscapeType.READLINE_END)
fun printlnIncomplete() = printlnWithEscaping("", EscapeType.REPL_INCOMPLETE) fun printlnIncomplete() = printlnWithEscaping("", EscapeType.REPL_INCOMPLETE)
fun printlnCompileError(x: String) = printlnWithEscaping(x, EscapeType.COMPILE_ERROR) fun printlnCompileError(x: String) = printlnWithEscaping(x, EscapeType.COMPILE_ERROR)
fun printlnRuntimeError(x: String) = printlnWithEscaping(x, EscapeType.RUNTIME_ERROR) fun printlnRuntimeError(x: String) = printlnWithEscaping(x, EscapeType.RUNTIME_ERROR)
@@ -26,10 +26,9 @@ private val XML_PREAMBLE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
public class KotlinConsoleExecutor( public class KotlinConsoleExecutor(
private val runner: KotlinConsoleRunner, private val runner: KotlinConsoleRunner,
private val historyManager: KotlinConsoleHistoryManager private val historyManager: KotlinConsoleHistoryManager,
private val historyHighlighter: KotlinHistoryHighlighter
) { ) {
private val historyHighlighter = KotlinHistoryHighlighter(runner)
fun executeCommand() = WriteCommandAction.runWriteCommandAction(runner.project) { fun executeCommand() = WriteCommandAction.runWriteCommandAction(runner.project) {
val consoleView = runner.consoleView val consoleView = runner.consoleView
val document = consoleView.editorDocument val document = consoleView.editorDocument
@@ -34,11 +34,13 @@ import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction
import org.jetbrains.kotlin.console.gutter.KotlinConsoleGutterContentProvider import org.jetbrains.kotlin.console.gutter.KotlinConsoleGutterContentProvider
import org.jetbrains.kotlin.console.gutter.KotlinConsoleIndicatorRenderer import org.jetbrains.kotlin.console.gutter.KotlinConsoleIndicatorRenderer
import org.jetbrains.kotlin.console.gutter.ReplIcons 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.KotlinReplOutputHighlighter
import org.jetbrains.kotlin.console.highlight.ReplColors import org.jetbrains.kotlin.console.highlight.ReplColors
import org.jetbrains.kotlin.idea.JetLanguage import org.jetbrains.kotlin.idea.JetLanguage
import java.awt.Color import java.awt.Color
import java.awt.Font import java.awt.Font
import java.util.concurrent.ConcurrentHashMap
import javax.swing.Icon import javax.swing.Icon
import kotlin.properties.Delegates import kotlin.properties.Delegates
@@ -51,10 +53,12 @@ public class KotlinConsoleRunner(
title: String, title: String,
path: String? path: String?
) : AbstractConsoleRunnerWithHistory<LanguageConsoleView>(myProject, title, path) { ) : AbstractConsoleRunnerWithHistory<LanguageConsoleView>(myProject, title, path) {
private val editorToHighlighter = ConcurrentHashMap<EditorEx, RangeHighlighter>()
private val historyManager = KotlinConsoleHistoryManager(this) private val historyManager = KotlinConsoleHistoryManager(this)
private val historyHighlighter = KotlinHistoryHighlighter(this)
private var disposableDescriptor: RunContentDescriptor by Delegates.notNull() private var disposableDescriptor: RunContentDescriptor by Delegates.notNull()
val executor = KotlinConsoleExecutor(this, historyManager) val executor = KotlinConsoleExecutor(this, historyManager, historyHighlighter)
var compilerHelper: KotlinConsoleCompilerHelper by Delegates.notNull() var compilerHelper: KotlinConsoleCompilerHelper by Delegates.notNull()
override fun createProcess() = cmdLine.createProcess() override fun createProcess() = cmdLine.createProcess()
@@ -79,7 +83,10 @@ public class KotlinConsoleRunner(
override fun createProcessHandler(process: Process): OSProcessHandler { override fun createProcessHandler(process: Process): OSProcessHandler {
val processHandler = KotlinReplOutputHandler( val processHandler = KotlinReplOutputHandler(
KotlinReplOutputHighlighter(this, historyManager, testMode, previousCompilationFailed), process, cmdLine.commandLineString historyHighlighter,
KotlinReplOutputHighlighter(this, historyManager, testMode, previousCompilationFailed),
process,
cmdLine.commandLineString
) )
val consoleFile = consoleView.virtualFile val consoleFile = consoleView.virtualFile
val keeper = KotlinConsoleKeeper.getInstance(project) val keeper = KotlinConsoleKeeper.getInstance(project)
@@ -162,9 +169,15 @@ public class KotlinConsoleRunner(
0, editor.document.textLength, HighlighterLayer.LAST, null, HighlighterTargetArea.LINES_IN_RANGE 0, editor.document.textLength, HighlighterLayer.LAST, null, HighlighterTargetArea.LINES_IN_RANGE
) )
editorToHighlighter[editor] = indicatorHighlighter
indicatorHighlighter.gutterIconRenderer = indicator indicatorHighlighter.gutterIconRenderer = indicator
} }
fun changeConsoleEditorIndicator(newIcon: Icon) {
val editorHighlighter = editorToHighlighter[consoleView.consoleEditor]
editorHighlighter?.gutterIconRenderer = KotlinConsoleIndicatorRenderer(newIcon)
}
// this method shouldn't be called in normal usage; it is for test purpose only // this method shouldn't be called in normal usage; it is for test purpose only
fun dispose() { fun dispose() {
processHandler.destroyProcess() processHandler.destroyProcess()
@@ -21,6 +21,7 @@ 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.console.actions.logError
import org.jetbrains.kotlin.console.highlight.KotlinHistoryHighlighter
import org.jetbrains.kotlin.console.highlight.KotlinReplOutputHighlighter import org.jetbrains.kotlin.console.highlight.KotlinReplOutputHighlighter
import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.Severity
import org.w3c.dom.Element import org.w3c.dom.Element
@@ -37,6 +38,7 @@ public val SOURCE_CHARS: Array<String> = arrayOf("\n", "#")
data class SeverityDetails(val severity: Severity, val description: String, val range: TextRange) data class SeverityDetails(val severity: Severity, val description: String, val range: TextRange)
public class KotlinReplOutputHandler( public class KotlinReplOutputHandler(
private val historyHighlighter: KotlinHistoryHighlighter,
private val outputHighlighter: KotlinReplOutputHighlighter, private val outputHighlighter: KotlinReplOutputHighlighter,
process: Process, process: Process,
commandLine: String commandLine: String
@@ -61,6 +63,8 @@ public class KotlinReplOutputHandler(
"HELP_PROMPT" -> outputHighlighter.printHelp(content) "HELP_PROMPT" -> outputHighlighter.printHelp(content)
"USER_OUTPUT" -> outputHighlighter.printUserOutput(content) "USER_OUTPUT" -> outputHighlighter.printUserOutput(content)
"REPL_RESULT" -> outputHighlighter.printResultWithGutterIcon(content) "REPL_RESULT" -> outputHighlighter.printResultWithGutterIcon(content)
"READLINE_START" -> historyHighlighter.isReadLineMode = true
"READLINE_END" -> historyHighlighter.isReadLineMode = false
"REPL_INCOMPLETE", "REPL_INCOMPLETE",
"COMPILE_ERROR" -> outputHighlighter.highlightCompilerErrors(createCompilerMessages(content)) "COMPILE_ERROR" -> outputHighlighter.highlightCompilerErrors(createCompilerMessages(content))
"RUNTIME_ERROR" -> outputHighlighter.printRuntimeError(content) "RUNTIME_ERROR" -> outputHighlighter.printRuntimeError(content)
@@ -21,11 +21,12 @@ import org.jetbrains.kotlin.idea.JetIcons
import javax.swing.Icon import javax.swing.Icon
public object ReplIcons { public object ReplIcons {
public val BUILD_WARNING_INDICATOR: Icon = AllIcons.General.Information public val BUILD_WARNING_INDICATOR: Icon = AllIcons.Ide.Warning_notifications
public val HISTORY_INDICATOR: Icon = AllIcons.General.MessageHistory public val HISTORY_INDICATOR: Icon = AllIcons.General.MessageHistory
public val EDITOR_INDICATOR: Icon = JetIcons.LAUNCH public val EDITOR_INDICATOR: Icon = JetIcons.LAUNCH
public val INCOMPLETE_INDICATOR: Icon = AllIcons.Nodes.Desktop public val EDITOR_READLINE_INDICATOR: Icon = AllIcons.General.Balloon
public val COMMAND_MARKER: Icon = AllIcons.General.Run public val COMMAND_MARKER: Icon = AllIcons.General.Run
public val READLINE_MARKER: Icon = AllIcons.Icons.Ide.SpeedSearchPrompt
// command result icons // command result icons
public val SYSTEM_HELP: Icon = AllIcons.Actions.Menu_help public val SYSTEM_HELP: Icon = AllIcons.Actions.Menu_help
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.console.highlight package org.jetbrains.kotlin.console.highlight
import com.intellij.execution.console.LanguageConsoleImpl import com.intellij.execution.console.LanguageConsoleImpl
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.ex.util.EditorUtil import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.editor.markup.HighlighterLayer import com.intellij.openapi.editor.markup.HighlighterLayer
@@ -29,6 +30,18 @@ import org.jetbrains.kotlin.console.gutter.ReplIcons
public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner ) { public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner ) {
private val consoleView: LanguageConsoleImpl by lazy { runner.consoleView as LanguageConsoleImpl } private val consoleView: LanguageConsoleImpl by lazy { runner.consoleView as LanguageConsoleImpl }
var isReadLineMode: Boolean = false
set(value) {
WriteCommandAction.runWriteCommandAction(runner.project) {
if (value)
runner.changeConsoleEditorIndicator(ReplIcons.EDITOR_READLINE_INDICATOR)
else
runner.changeConsoleEditorIndicator(ReplIcons.EDITOR_INDICATOR)
}
$isReadLineMode = value
}
fun printNewCommandInHistory(trimmedCommandText: String) { fun printNewCommandInHistory(trimmedCommandText: String) {
val historyEditor = consoleView.historyViewer val historyEditor = consoleView.historyViewer
@@ -50,11 +63,14 @@ public class KotlinHistoryHighlighter(private val runner: KotlinConsoleRunner )
historyEditor.markupModel let { historyEditor.markupModel let {
it.addRangeHighlighter(startOffset, endOffset, HighlighterLayer.LAST, null, HighlighterTargetArea.EXACT_RANGE) it.addRangeHighlighter(startOffset, endOffset, HighlighterLayer.LAST, null, HighlighterTargetArea.EXACT_RANGE)
} apply { } apply {
gutterIconRenderer = KotlinConsoleIndicatorRenderer(ReplIcons.COMMAND_MARKER) val historyMarker = if (isReadLineMode) ReplIcons.READLINE_MARKER else ReplIcons.COMMAND_MARKER
gutterIconRenderer = KotlinConsoleIndicatorRenderer(historyMarker)
} }
} }
private fun addLineBreakIfNeeded(historyEditor: EditorEx) { private fun addLineBreakIfNeeded(historyEditor: EditorEx) {
if (isReadLineMode) return
val historyDocument = historyEditor.document val historyDocument = historyEditor.document
val historyText = historyDocument.text val historyText = historyDocument.text
val textLength = historyText.length() val textLength = historyText.length()