[ide-console][cli-repl] Add more icons for readLine commands
This commit is contained in:
committed by
Pavel V. Talanov
parent
724b208a5d
commit
b4224bf9f3
@@ -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
-1
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user