Add kotlin console repl
This commit is contained in:
committed by
Pavel V. Talanov
parent
80cbee83ee
commit
a11f411f7d
Generated
+1
@@ -46,6 +46,7 @@
|
|||||||
<element id="module-output" name="container" />
|
<element id="module-output" name="container" />
|
||||||
<element id="module-output" name="rmi-interface" />
|
<element id="module-output" name="rmi-interface" />
|
||||||
<element id="module-output" name="kotlinr" />
|
<element id="module-output" name="kotlinr" />
|
||||||
|
<element id="module-output" name="idea-repl" />
|
||||||
</element>
|
</element>
|
||||||
<element id="library" level="project" name="javax.inject" />
|
<element id="library" level="project" name="javax.inject" />
|
||||||
<element id="directory" name="jps">
|
<element id="directory" name="jps">
|
||||||
|
|||||||
Generated
+1
@@ -36,6 +36,7 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/idea/idea-core/idea-core.iml" filepath="$PROJECT_DIR$/idea/idea-core/idea-core.iml" group="ide" />
|
<module fileurl="file://$PROJECT_DIR$/idea/idea-core/idea-core.iml" filepath="$PROJECT_DIR$/idea/idea-core/idea-core.iml" group="ide" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/idea/idea-jps-common/idea-jps-common.iml" filepath="$PROJECT_DIR$/idea/idea-jps-common/idea-jps-common.iml" group="ide" />
|
<module fileurl="file://$PROJECT_DIR$/idea/idea-jps-common/idea-jps-common.iml" filepath="$PROJECT_DIR$/idea/idea-jps-common/idea-jps-common.iml" group="ide" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/idea/idea-js/idea-js.iml" filepath="$PROJECT_DIR$/idea/idea-js/idea-js.iml" group="ide" />
|
<module fileurl="file://$PROJECT_DIR$/idea/idea-js/idea-js.iml" filepath="$PROJECT_DIR$/idea/idea-js/idea-js.iml" group="ide" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/idea/idea-repl/idea-repl.iml" filepath="$PROJECT_DIR$/idea/idea-repl/idea-repl.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/idea-runner/idea-runner.iml" filepath="$PROJECT_DIR$/idea-runner/idea-runner.iml" group="ide" />
|
<module fileurl="file://$PROJECT_DIR$/idea-runner/idea-runner.iml" filepath="$PROJECT_DIR$/idea-runner/idea-runner.iml" group="ide" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/idea/idea-test-framework/idea-test-framework.iml" filepath="$PROJECT_DIR$/idea/idea-test-framework/idea-test-framework.iml" group="ide" />
|
<module fileurl="file://$PROJECT_DIR$/idea/idea-test-framework/idea-test-framework.iml" filepath="$PROJECT_DIR$/idea/idea-test-framework/idea-test-framework.iml" group="ide" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/compiler/preloader/instrumentation/instrumentation.iml" filepath="$PROJECT_DIR$/compiler/preloader/instrumentation/instrumentation.iml" group="compiler/cli" />
|
<module fileurl="file://$PROJECT_DIR$/compiler/preloader/instrumentation/instrumentation.iml" filepath="$PROJECT_DIR$/compiler/preloader/instrumentation/instrumentation.iml" group="compiler/cli" />
|
||||||
|
|||||||
+1
-1
@@ -47,4 +47,4 @@
|
|||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+30
@@ -242,6 +242,36 @@ public final class AnalyzerWithCompilerReport {
|
|||||||
return new SyntaxErrorReport(visitor.hasErrors, visitor.allErrorsAtEof);
|
return new SyntaxErrorReport(visitor.hasErrors, visitor.allErrorsAtEof);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SyntaxErrorReport reportSyntaxErrorsWithDiagnostics(@NotNull final PsiElement file, @NotNull final MessageCollector messageCollector,
|
||||||
|
@NotNull final List<Diagnostic> diagnostics) {
|
||||||
|
class ErrorReportingVisitor extends AnalyzingUtils.PsiErrorElementVisitor {
|
||||||
|
boolean hasErrors = false;
|
||||||
|
boolean allErrorsAtEof = true;
|
||||||
|
|
||||||
|
private <E extends PsiElement> void reportDiagnostic(E element, DiagnosticFactory0<E> factory, String message) {
|
||||||
|
MyDiagnostic<?> diagnostic = new MyDiagnostic<E>(element, factory, message);
|
||||||
|
AnalyzerWithCompilerReport.reportDiagnostic(diagnostic, messageCollector);
|
||||||
|
if (element.getTextRange().getStartOffset() != file.getTextRange().getEndOffset()) {
|
||||||
|
allErrorsAtEof = false;
|
||||||
|
}
|
||||||
|
hasErrors = true;
|
||||||
|
|
||||||
|
diagnostics.add(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitErrorElement(PsiErrorElement element) {
|
||||||
|
String description = element.getErrorDescription();
|
||||||
|
reportDiagnostic(element, SYNTAX_ERROR_FACTORY, StringUtil.isEmpty(description) ? "Syntax error" : description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ErrorReportingVisitor visitor = new ErrorReportingVisitor();
|
||||||
|
|
||||||
|
file.accept(visitor);
|
||||||
|
|
||||||
|
return new SyntaxErrorReport(visitor.hasErrors, visitor.allErrorsAtEof);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public AnalysisResult getAnalysisResult() {
|
public AnalysisResult getAnalysisResult() {
|
||||||
return analysisResult;
|
return analysisResult;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.cli.jvm.repl;
|
|||||||
|
|
||||||
import com.intellij.openapi.Disposable;
|
import com.intellij.openapi.Disposable;
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
import com.intellij.openapi.util.io.FileUtil;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.testFramework.LightVirtualFile;
|
||||||
import jline.console.ConsoleReader;
|
import jline.console.ConsoleReader;
|
||||||
import jline.console.history.FileHistory;
|
import jline.console.history.FileHistory;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -26,6 +28,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration;
|
|||||||
import org.jetbrains.kotlin.utils.UtilsPackage;
|
import org.jetbrains.kotlin.utils.UtilsPackage;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -36,6 +39,9 @@ public class ReplFromTerminal {
|
|||||||
private Throwable replInitializationFailed;
|
private Throwable replInitializationFailed;
|
||||||
private final Object waitRepl = new Object();
|
private final Object waitRepl = new Object();
|
||||||
|
|
||||||
|
private final boolean ideMode;
|
||||||
|
private ReplSystemOutWrapper replWriter;
|
||||||
|
|
||||||
private final ConsoleReader consoleReader;
|
private final ConsoleReader consoleReader;
|
||||||
|
|
||||||
public ReplFromTerminal(
|
public ReplFromTerminal(
|
||||||
@@ -56,8 +62,24 @@ public class ReplFromTerminal {
|
|||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
|
|
||||||
|
String replIdeMode = System.getProperty("repl.ideMode");
|
||||||
|
ideMode = replIdeMode != null && replIdeMode.equals("true");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
consoleReader = new ConsoleReader("kotlin", System.in, System.out, null);
|
OutputStream outStream = System.out;
|
||||||
|
if (ideMode) {
|
||||||
|
// consoleReader duplicates his input in his output stream;
|
||||||
|
// to prevent such behaviour we redirect his output to dummy output stream
|
||||||
|
VirtualFile consoleOutputRedirect = new LightVirtualFile("kotlinConsoleReplRedirect");
|
||||||
|
outStream = consoleOutputRedirect.getOutputStream(null);
|
||||||
|
|
||||||
|
// wrapper is required to escape every input;
|
||||||
|
// if user calls [System.setOut(...)] then undefined behaviour
|
||||||
|
replWriter = new ReplSystemOutWrapper(System.out);
|
||||||
|
System.setOut(replWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
consoleReader = new ConsoleReader("kotlin", System.in, outStream, null);
|
||||||
consoleReader.setHistoryEnabled(true);
|
consoleReader.setHistoryEnabled(true);
|
||||||
consoleReader.setExpandEvents(false);
|
consoleReader.setExpandEvents(false);
|
||||||
consoleReader.setHistory(new FileHistory(new File(new File(System.getProperty("user.home")), ".kotlin_history")));
|
consoleReader.setHistory(new FileHistory(new File(new File(System.getProperty("user.home")), ".kotlin_history")));
|
||||||
@@ -65,6 +87,8 @@ public class ReplFromTerminal {
|
|||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw UtilsPackage.rethrow(e);
|
throw UtilsPackage.rethrow(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getReplInterpreter().setIdeMode(ideMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReplInterpreter getReplInterpreter() {
|
private ReplInterpreter getReplInterpreter() {
|
||||||
@@ -122,7 +146,9 @@ public class ReplFromTerminal {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private WhatNextAfterOneLine one(@NotNull WhatNextAfterOneLine next) {
|
private WhatNextAfterOneLine one(@NotNull WhatNextAfterOneLine next) {
|
||||||
try {
|
try {
|
||||||
String line = consoleReader.readLine(next == WhatNextAfterOneLine.INCOMPLETE ? "... " : ">>> ");
|
String prompt = getPrompt(next);
|
||||||
|
String line = consoleReader.readLine(prompt);
|
||||||
|
|
||||||
if (line == null) {
|
if (line == null) {
|
||||||
return WhatNextAfterOneLine.QUIT;
|
return WhatNextAfterOneLine.QUIT;
|
||||||
}
|
}
|
||||||
@@ -145,6 +171,15 @@ public class ReplFromTerminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getPrompt(@NotNull WhatNextAfterOneLine next) {
|
||||||
|
String prompt = null;
|
||||||
|
// consoleReader always print prompt; in [ideMode] we don't allow it
|
||||||
|
if (!ideMode) {
|
||||||
|
prompt = next == WhatNextAfterOneLine.INCOMPLETE ? "... " : ">>> ";
|
||||||
|
}
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private ReplInterpreter.LineResultType eval(@NotNull String line) {
|
private ReplInterpreter.LineResultType eval(@NotNull String line) {
|
||||||
ReplInterpreter.LineResult lineResult = getReplInterpreter().eval(line);
|
ReplInterpreter.LineResult lineResult = getReplInterpreter().eval(line);
|
||||||
@@ -156,7 +191,11 @@ public class ReplFromTerminal {
|
|||||||
else if (lineResult.getType() == ReplInterpreter.LineResultType.INCOMPLETE) {
|
else if (lineResult.getType() == ReplInterpreter.LineResultType.INCOMPLETE) {
|
||||||
}
|
}
|
||||||
else if (lineResult.getType() == ReplInterpreter.LineResultType.ERROR) {
|
else if (lineResult.getType() == ReplInterpreter.LineResultType.ERROR) {
|
||||||
System.out.print(lineResult.getErrorText());
|
if (ideMode) {
|
||||||
|
replWriter.printlnWithEscaping(lineResult.getErrorText(), EscapeType.REPORT);
|
||||||
|
} else {
|
||||||
|
System.out.print(lineResult.getErrorText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalStateException("unknown line result type: " + lineResult);
|
throw new IllegalStateException("unknown line result type: " + lineResult);
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import com.google.common.collect.Lists;
|
|||||||
import com.intellij.openapi.Disposable;
|
import com.intellij.openapi.Disposable;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
|
import com.intellij.openapi.util.TextRange;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFileFactory;
|
import com.intellij.psi.PsiFileFactory;
|
||||||
@@ -47,6 +49,7 @@ import org.jetbrains.kotlin.context.MutableModuleContext;
|
|||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider;
|
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.kotlin.idea.JetLanguage;
|
import org.jetbrains.kotlin.idea.JetLanguage;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.parsing.JetParserDefinition;
|
import org.jetbrains.kotlin.parsing.JetParserDefinition;
|
||||||
@@ -65,18 +68,30 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
|||||||
import org.jetbrains.kotlin.types.JetType;
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
import org.jetbrains.kotlin.utils.UtilsPackage;
|
import org.jetbrains.kotlin.utils.UtilsPackage;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
import org.w3c.dom.Attr;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.ls.DOMImplementationLS;
|
||||||
|
import org.w3c.dom.ls.LSSerializer;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerConfigurationException;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.getJvmClasspathRoots;
|
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.getJvmClasspathRoots;
|
||||||
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.getModuleName;
|
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.getModuleName;
|
||||||
@@ -102,6 +117,8 @@ public class ReplInterpreter {
|
|||||||
private final ResolveSession resolveSession;
|
private final ResolveSession resolveSession;
|
||||||
private final ScriptMutableDeclarationProviderFactory scriptDeclarationFactory;
|
private final ScriptMutableDeclarationProviderFactory scriptDeclarationFactory;
|
||||||
|
|
||||||
|
private boolean ideMode;
|
||||||
|
|
||||||
public ReplInterpreter(@NotNull Disposable disposable, @NotNull CompilerConfiguration configuration) {
|
public ReplInterpreter(@NotNull Disposable disposable, @NotNull CompilerConfiguration configuration) {
|
||||||
KotlinCoreEnvironment environment =
|
KotlinCoreEnvironment environment =
|
||||||
KotlinCoreEnvironment.createForProduction(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
KotlinCoreEnvironment.createForProduction(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||||
@@ -159,12 +176,21 @@ public class ReplInterpreter {
|
|||||||
c.getScripts().clear();
|
c.getScripts().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setIdeMode(boolean ideMode) {
|
||||||
|
this.ideMode = ideMode;
|
||||||
|
}
|
||||||
|
|
||||||
public enum LineResultType {
|
public enum LineResultType {
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
ERROR,
|
ERROR,
|
||||||
INCOMPLETE,
|
INCOMPLETE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum ErrorType {
|
||||||
|
CODE_ERROR,
|
||||||
|
THROWABLE
|
||||||
|
}
|
||||||
|
|
||||||
public static class LineResult {
|
public static class LineResult {
|
||||||
private final Object value;
|
private final Object value;
|
||||||
private final boolean unit;
|
private final boolean unit;
|
||||||
@@ -208,16 +234,77 @@ public class ReplInterpreter {
|
|||||||
return new LineResult(value, unit, null, LineResultType.SUCCESS);
|
return new LineResult(value, unit, null, LineResultType.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LineResult error(@NotNull String errorText) {
|
public static LineResult error(@NotNull String errorText, boolean ideMode,
|
||||||
|
@NotNull ErrorType errType, @Nullable Collection<Diagnostic> diagnostics
|
||||||
|
) {
|
||||||
if (errorText.isEmpty()) {
|
if (errorText.isEmpty()) {
|
||||||
errorText = "<unknown error>";
|
errorText = "<unknown error>";
|
||||||
}
|
}
|
||||||
else if (!errorText.endsWith("\n")) {
|
|
||||||
|
String[] lines = errorTextToLinesWithPreprocessing(errorText);
|
||||||
|
|
||||||
|
if (ideMode && errType == ErrorType.CODE_ERROR) {
|
||||||
|
assert diagnostics != null : "diagnostics should not be null in not-throwable case";
|
||||||
|
errorText = convertLinesToXML(lines, diagnostics);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorText = StringUtil.join(lines, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errorText.endsWith("\n")) {
|
||||||
errorText += "\n";
|
errorText += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LineResult(null, false, errorText, LineResultType.ERROR);
|
return new LineResult(null, false, errorText, LineResultType.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String[] errorTextToLinesWithPreprocessing(@NotNull String errorText) {
|
||||||
|
// cut "/line_i.kts:row:column" prefix and capitalize "error:" and "warning:"
|
||||||
|
String[] lines = errorText.split("\\n");
|
||||||
|
for (int i = 0; i < lines.length; i++) {
|
||||||
|
if (lines[i].contains("error:")) {
|
||||||
|
int pos = lines[i].indexOf("error:");
|
||||||
|
lines[i] = "E" + lines[i].substring(pos + 1);
|
||||||
|
}
|
||||||
|
else if (lines[i].contains("warning:")) {
|
||||||
|
int pos = lines[i].indexOf("warning:");
|
||||||
|
lines[i] = "W" + lines[i].substring(pos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String convertLinesToXML(@NotNull String[] lines, @NotNull Collection<Diagnostic> diagnostics) {
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||||
|
Document errorReport = docBuilder.newDocument();
|
||||||
|
|
||||||
|
Element rootElement = errorReport.createElement("report");
|
||||||
|
errorReport.appendChild(rootElement);
|
||||||
|
|
||||||
|
Iterator<Diagnostic> di = diagnostics.iterator();
|
||||||
|
for (String s : lines) {
|
||||||
|
if (s.startsWith("Error:") || s.startsWith("Warning:")) {
|
||||||
|
TextRange errorRange = di.hasNext() ? di.next().getTextRanges().get(0) : TextRange.EMPTY_RANGE;
|
||||||
|
|
||||||
|
Element reportEntry = errorReport.createElement("reportEntry");
|
||||||
|
reportEntry.setAttribute("rangeStart", String.valueOf(errorRange.getStartOffset()));
|
||||||
|
reportEntry.setAttribute("rangeEnd", String.valueOf(errorRange.getEndOffset()));
|
||||||
|
reportEntry.appendChild(errorReport.createTextNode(StringUtil.escapeXml(s)));
|
||||||
|
|
||||||
|
rootElement.appendChild(reportEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMImplementationLS domImplementation = (DOMImplementationLS) errorReport.getImplementation();
|
||||||
|
LSSerializer lsSerializer = domImplementation.createLSSerializer();
|
||||||
|
return lsSerializer.writeToString(errorReport);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw UtilsPackage.rethrow(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static LineResult incomplete() {
|
public static LineResult incomplete() {
|
||||||
return new LineResult(null, false, null, LineResultType.INCOMPLETE);
|
return new LineResult(null, false, null, LineResultType.INCOMPLETE);
|
||||||
}
|
}
|
||||||
@@ -242,9 +329,10 @@ public class ReplInterpreter {
|
|||||||
assert psiFile != null : "Script file not analyzed at line " + lineNumber + ": " + fullText;
|
assert psiFile != null : "Script file not analyzed at line " + lineNumber + ": " + fullText;
|
||||||
|
|
||||||
ReplMessageCollectorWrapper errorCollector = new ReplMessageCollectorWrapper();
|
ReplMessageCollectorWrapper errorCollector = new ReplMessageCollectorWrapper();
|
||||||
|
List<Diagnostic> syntaxDiagnostics = new ArrayList<Diagnostic>();
|
||||||
|
|
||||||
AnalyzerWithCompilerReport.SyntaxErrorReport syntaxErrorReport =
|
AnalyzerWithCompilerReport.SyntaxErrorReport syntaxErrorReport =
|
||||||
AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorCollector.getMessageCollector());
|
AnalyzerWithCompilerReport.reportSyntaxErrorsWithDiagnostics(psiFile, errorCollector.getMessageCollector(), syntaxDiagnostics);
|
||||||
|
|
||||||
if (syntaxErrorReport.isHasErrors() && syntaxErrorReport.isAllErrorsAtEof()) {
|
if (syntaxErrorReport.isHasErrors() && syntaxErrorReport.isAllErrorsAtEof()) {
|
||||||
previousIncompleteLines.add(line);
|
previousIncompleteLines.add(line);
|
||||||
@@ -254,7 +342,7 @@ public class ReplInterpreter {
|
|||||||
previousIncompleteLines.clear();
|
previousIncompleteLines.clear();
|
||||||
|
|
||||||
if (syntaxErrorReport.isHasErrors()) {
|
if (syntaxErrorReport.isHasErrors()) {
|
||||||
return LineResult.error(errorCollector.getString());
|
return LineResult.error(errorCollector.getString(), ideMode, ErrorType.CODE_ERROR, syntaxDiagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareForTheNextReplLine(topDownAnalysisContext);
|
prepareForTheNextReplLine(topDownAnalysisContext);
|
||||||
@@ -265,7 +353,7 @@ public class ReplInterpreter {
|
|||||||
|
|
||||||
ScriptDescriptor scriptDescriptor = doAnalyze(psiFile, errorCollector);
|
ScriptDescriptor scriptDescriptor = doAnalyze(psiFile, errorCollector);
|
||||||
if (scriptDescriptor == null) {
|
if (scriptDescriptor == null) {
|
||||||
return LineResult.error(errorCollector.getString());
|
return LineResult.error(errorCollector.getString(), ideMode, ErrorType.CODE_ERROR, trace.getBindingContext().getDiagnostics().all());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Pair<ScriptDescriptor, Type>> earlierScripts = Lists.newArrayList();
|
List<Pair<ScriptDescriptor, Type>> earlierScripts = Lists.newArrayList();
|
||||||
@@ -303,7 +391,7 @@ public class ReplInterpreter {
|
|||||||
scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs);
|
scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs);
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
return LineResult.error(renderStackTrace(e.getCause()));
|
return LineResult.error(renderStackTrace(e.getCause()), ideMode, ErrorType.THROWABLE, null);
|
||||||
}
|
}
|
||||||
Field rvField = scriptClass.getDeclaredField("rv");
|
Field rvField = scriptClass.getDeclaredField("rv");
|
||||||
rvField.setAccessible(true);
|
rvField.setAccessible(true);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli.jvm.repl
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import java.io.PrintStream
|
||||||
|
|
||||||
|
enum class EscapeType {
|
||||||
|
ORDINARY, REPORT
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReplSystemOutWrapper(private val standardOut: PrintStream) : PrintStream(standardOut, true) {
|
||||||
|
private val XML_PREFIX = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
|
||||||
|
|
||||||
|
private fun xmlEscape(s: String, escapeType: EscapeType): String {
|
||||||
|
val singleLine = StringUtil.escapeLineBreak(s)
|
||||||
|
return "$XML_PREFIX<output type=\"$escapeType\">${StringUtil.escapeXml(singleLine)}</output>"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun print(x: Any) = printWithEscaping(x.toString())
|
||||||
|
private fun printWithEscaping(text: String, escapeType: EscapeType = EscapeType.ORDINARY) = super.print(xmlEscape(text, escapeType))
|
||||||
|
|
||||||
|
override fun println(x: String) = printlnWithEscaping(x)
|
||||||
|
override fun println(x: Any) = printlnWithEscaping(x.toString())
|
||||||
|
public fun printlnWithEscaping(text: String, escapeType: EscapeType = EscapeType.ORDINARY): Unit = super.println(xmlEscape(text, escapeType))
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="library" name="idea-full" level="project" />
|
||||||
|
<orderEntry type="module" module-name="frontend" />
|
||||||
|
<orderEntry type="module" module-name="util" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.execution.configurations.GeneralCommandLine
|
||||||
|
import com.intellij.execution.configurations.JavaParameters
|
||||||
|
import com.intellij.openapi.components.ServiceManager
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.projectRoots.JavaSdkType
|
||||||
|
import com.intellij.openapi.projectRoots.JdkUtil
|
||||||
|
import com.intellij.openapi.projectRoots.SimpleJavaSdkType
|
||||||
|
import com.intellij.openapi.roots.ModuleRootManager
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.util.SystemProperties
|
||||||
|
import org.jetbrains.kotlin.console.actions.errorNotification
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.platform.platformStatic
|
||||||
|
|
||||||
|
public class KotlinConsoleKeeper(val project: Project) {
|
||||||
|
private val consoleMap: MutableMap<VirtualFile, KotlinConsoleRunner> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
fun getConsoleByVirtualFile(virtualFile: VirtualFile) = consoleMap.get(virtualFile)
|
||||||
|
fun putVirtualFileToConsole(virtualFile: VirtualFile, console: KotlinConsoleRunner) = consoleMap.put(virtualFile, console)
|
||||||
|
fun removeConsole(virtualFile: VirtualFile?) = consoleMap.remove(virtualFile)
|
||||||
|
|
||||||
|
fun run(module: Module): KotlinConsoleRunner? {
|
||||||
|
val path = module.moduleFilePath
|
||||||
|
val cmdLine = createCommandLine(module)
|
||||||
|
if (cmdLine == null) {
|
||||||
|
errorNotification(project, "<p>Module SDK not found</p>")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val consoleRunner = KotlinConsoleRunner(path, cmdLine, project, REPL_TITLE)
|
||||||
|
consoleRunner.initAndRun()
|
||||||
|
consoleRunner.setupGutters()
|
||||||
|
|
||||||
|
return consoleRunner
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCommandLine(module: Module): GeneralCommandLine? {
|
||||||
|
val javaParameters = createJavaParametersWithSdk(module)
|
||||||
|
val sdk = javaParameters.jdk ?: return null
|
||||||
|
val sdkType = sdk.sdkType
|
||||||
|
val exePath = (sdkType as JavaSdkType).getVMExecutablePath(sdk)
|
||||||
|
|
||||||
|
val commandLine = JdkUtil.setupJVMCommandLine(exePath, javaParameters, true)
|
||||||
|
|
||||||
|
// set parameters to run compiler
|
||||||
|
val paramList = commandLine.parametersList
|
||||||
|
paramList.clearAll()
|
||||||
|
|
||||||
|
// use to debug repl process
|
||||||
|
//paramList.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")
|
||||||
|
|
||||||
|
// set classpath for process to compiler
|
||||||
|
paramList.add("-cp")
|
||||||
|
paramList.add("${PathUtil.getKotlinPathsForIdeaPlugin().libPath.absolutePath}/*")
|
||||||
|
|
||||||
|
// set param to prevent process from repeating input backwards
|
||||||
|
paramList.add("-Drepl.ideMode=true")
|
||||||
|
|
||||||
|
// path to compiler and his options
|
||||||
|
paramList.add("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler")
|
||||||
|
|
||||||
|
return commandLine
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createJavaParametersWithSdk(module: Module?): JavaParameters {
|
||||||
|
val params = JavaParameters()
|
||||||
|
params.charset = null
|
||||||
|
|
||||||
|
if (module != null) {
|
||||||
|
val sdk = ModuleRootManager.getInstance(module).sdk
|
||||||
|
if (sdk != null && sdk.sdkType is JavaSdkType && File(sdk.homePath).exists()) {
|
||||||
|
params.jdk = sdk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params.jdk == null) {
|
||||||
|
params.jdk = SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome())
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val REPL_TITLE = "Kotlin REPL"
|
||||||
|
|
||||||
|
platformStatic fun getInstance(project: Project) = ServiceManager.getService(project, javaClass<KotlinConsoleKeeper>())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.execution.Executor
|
||||||
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
|
import com.intellij.execution.console.*
|
||||||
|
import com.intellij.execution.process.*
|
||||||
|
import com.intellij.execution.runners.AbstractConsoleRunnerWithHistory
|
||||||
|
import com.intellij.execution.ui.RunContentDescriptor
|
||||||
|
import com.intellij.icons.AllIcons
|
||||||
|
import com.intellij.openapi.actionSystem.*
|
||||||
|
import com.intellij.openapi.editor.colors.EditorColors
|
||||||
|
import com.intellij.openapi.editor.event.DocumentAdapter
|
||||||
|
import com.intellij.openapi.editor.event.DocumentEvent
|
||||||
|
import com.intellij.openapi.editor.ex.EditorEx
|
||||||
|
import com.intellij.openapi.editor.markup.*
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction
|
||||||
|
import org.jetbrains.kotlin.console.actions.logError
|
||||||
|
import org.jetbrains.kotlin.idea.JetLanguage
|
||||||
|
import java.awt.Color
|
||||||
|
import javax.swing.Icon
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
public class KotlinConsoleRunner(
|
||||||
|
val title: String,
|
||||||
|
private val cmdLine: GeneralCommandLine,
|
||||||
|
myProject: Project,
|
||||||
|
path: String?
|
||||||
|
) : AbstractConsoleRunnerWithHistory<LanguageConsoleView>(myProject, title, path) {
|
||||||
|
companion object {
|
||||||
|
private val HISTORY_GUTTER_ICON = AllIcons.Debugger.Console
|
||||||
|
private val EDITOR_GUTTER_ICON = AllIcons.Debugger.CommandLine
|
||||||
|
}
|
||||||
|
|
||||||
|
private val keyEventListener = KtConsoleKeyListener(this)
|
||||||
|
private var historyHighlighter: KotlinReplResultHighlighter by Delegates.notNull()
|
||||||
|
val history: MutableList<String> = arrayListOf()
|
||||||
|
|
||||||
|
override fun createProcess() = cmdLine.createProcess()
|
||||||
|
|
||||||
|
override fun createConsoleView(): LanguageConsoleView? {
|
||||||
|
val consoleView = LanguageConsoleBuilder().build(project, JetLanguage.INSTANCE)
|
||||||
|
consoleView.prompt = null
|
||||||
|
|
||||||
|
val historyEditor = consoleView.historyViewer
|
||||||
|
val consoleEditor = consoleView.consoleEditor
|
||||||
|
consoleEditor.contentComponent.addKeyListener(keyEventListener)
|
||||||
|
|
||||||
|
historyEditor.document.addDocumentListener(object : DocumentAdapter() {
|
||||||
|
override fun documentChanged(e: DocumentEvent): Unit =
|
||||||
|
if (historyEditor.document.textLength == 0) addGutterIcon(historyEditor, HISTORY_GUTTER_ICON)
|
||||||
|
})
|
||||||
|
|
||||||
|
historyHighlighter = KotlinReplResultHighlighter(historyEditor)
|
||||||
|
historyEditor.document.addDocumentListener(historyHighlighter)
|
||||||
|
|
||||||
|
consoleEditor.setPlaceholder("<Ctrl+Enter> to execute")
|
||||||
|
consoleEditor.setShowPlaceholderWhenFocused(true)
|
||||||
|
val placeholderAttrs = consoleEditor.foldingModel.placeholderAttributes
|
||||||
|
placeholderAttrs.foregroundColor = Color.GRAY
|
||||||
|
|
||||||
|
val executeAction = KtExecuteCommandAction(consoleView.virtualFile)
|
||||||
|
executeAction.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, consoleView.consoleEditor.component)
|
||||||
|
|
||||||
|
return consoleView
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createProcessHandler(process: Process): OSProcessHandler {
|
||||||
|
val processHandler = KotlinReplOutputHandler(process, cmdLine.commandLineString)
|
||||||
|
historyHighlighter.rangeQueue = processHandler.rangeQueue
|
||||||
|
val consoleFile = consoleView.virtualFile
|
||||||
|
val keeper = KotlinConsoleKeeper.getInstance(project)
|
||||||
|
|
||||||
|
keeper.putVirtualFileToConsole(consoleFile, this)
|
||||||
|
processHandler.addProcessListener(object : ProcessAdapter() {
|
||||||
|
override fun processTerminated(event: ProcessEvent) {
|
||||||
|
keeper.removeConsole(consoleFile)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return processHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createExecuteActionHandler() = object : ProcessBackedConsoleExecuteActionHandler(processHandler, false) {
|
||||||
|
override fun sendText(line: String) {
|
||||||
|
submitCommand(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fillToolBarActions(toolbarActions: DefaultActionGroup,
|
||||||
|
defaultExecutor: Executor,
|
||||||
|
contentDescriptor: RunContentDescriptor
|
||||||
|
): List<AnAction> {
|
||||||
|
val actionList = arrayListOf<AnAction>(
|
||||||
|
createCloseAction(defaultExecutor, contentDescriptor),
|
||||||
|
createConsoleExecAction(consoleExecuteActionHandler)
|
||||||
|
)
|
||||||
|
toolbarActions.addAll(actionList)
|
||||||
|
return actionList
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createConsoleExecAction(consoleExecuteActionHandler: ProcessBackedConsoleExecuteActionHandler)
|
||||||
|
= ConsoleExecuteAction(consoleView, consoleExecuteActionHandler, "KotlinShellExecute", consoleExecuteActionHandler)
|
||||||
|
|
||||||
|
fun setupGutters() {
|
||||||
|
fun configureEditorGutter(editor: EditorEx, color: Color, icon: Icon) {
|
||||||
|
editor.settings.isLineMarkerAreaShown = true // hack to show gutter
|
||||||
|
editor.settings.isFoldingOutlineShown = true
|
||||||
|
editor.gutterComponentEx.setPaintBackground(true)
|
||||||
|
val editorColorScheme = editor.colorsScheme
|
||||||
|
editorColorScheme.setColor(EditorColors.GUTTER_BACKGROUND, color)
|
||||||
|
editor.colorsScheme = editorColorScheme
|
||||||
|
|
||||||
|
addGutterIcon(editor, icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
val consoleView = consoleView
|
||||||
|
val lightGray = Color(0xF2, 0xF2, 0xF2)
|
||||||
|
val lightBlue = Color(0x93, 0xDE, 0xFF)
|
||||||
|
configureEditorGutter(consoleView.historyViewer, lightGray, HISTORY_GUTTER_ICON)
|
||||||
|
configureEditorGutter(consoleView.consoleEditor, lightBlue, EDITOR_GUTTER_ICON)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addGutterIcon(editor: EditorEx, icon: Icon) {
|
||||||
|
val editorMarkup = editor.markupModel
|
||||||
|
val highlighter = editorMarkup.addRangeHighlighter(0, editor.document.textLength, HighlighterLayer.LAST, null, HighlighterTargetArea.LINES_IN_RANGE)
|
||||||
|
highlighter.gutterIconRenderer = object : GutterIconRenderer() {
|
||||||
|
override fun getIcon() = icon
|
||||||
|
override fun hashCode() = System.identityHashCode(this)
|
||||||
|
override fun equals(other: Any?) = this === other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun submitCommand(command: String) {
|
||||||
|
val res = command.trim()
|
||||||
|
if (res.isEmpty()) return
|
||||||
|
|
||||||
|
history.add(res)
|
||||||
|
keyEventListener.resetHistoryPosition()
|
||||||
|
|
||||||
|
val processInputOS = processHandler.processInput ?: return logError(javaClass, "<p>Broken process stream</p>")
|
||||||
|
val charset = (processHandler as? BaseOSProcessHandler)?.charset ?: Charsets.UTF_8
|
||||||
|
val bytes = ("$res\n").toByteArray(charset)
|
||||||
|
processInputOS.write(bytes)
|
||||||
|
processInputOS.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.execution.process.OSProcessHandler
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import org.xml.sax.InputSource
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
|
||||||
|
public class KotlinReplOutputHandler(
|
||||||
|
process: Process,
|
||||||
|
commandLine: String
|
||||||
|
) : OSProcessHandler(process, commandLine) {
|
||||||
|
private val dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||||
|
val rangeQueue: Queue<TextRange> = ConcurrentLinkedQueue()
|
||||||
|
|
||||||
|
override fun notifyTextAvailable(text: String, key: Key<*>?) {
|
||||||
|
// skip "/usr/lib/jvm/java-8-oracle/bin/java -cp ..." intro
|
||||||
|
if (!text.startsWith("<?xml version=")) return super.notifyTextAvailable(text, key)
|
||||||
|
|
||||||
|
val output = dBuilder.parse(strToSource(text))
|
||||||
|
val root = output.firstChild as Element
|
||||||
|
val outputType = root.getAttribute("type")
|
||||||
|
val content = StringUtil.unescapeStringCharacters(root.textContent).trim()
|
||||||
|
|
||||||
|
when (outputType) {
|
||||||
|
"ORDINARY" -> super.notifyTextAvailable("$content\n", key)
|
||||||
|
"REPORT" -> {
|
||||||
|
val report = dBuilder.parse(strToSource(content, Charsets.UTF_16BE))
|
||||||
|
val entries = report.getElementsByTagName("reportEntry")
|
||||||
|
for (i in 0..entries.length - 1) {
|
||||||
|
val reportEntry = entries.item(i) as Element
|
||||||
|
val rangeStart = reportEntry.getAttribute("rangeStart").toInt()
|
||||||
|
val rangeEnd = reportEntry.getAttribute("rangeEnd").toInt()
|
||||||
|
|
||||||
|
rangeQueue.add(TextRange(rangeStart, rangeEnd))
|
||||||
|
super.notifyTextAvailable("${StringUtil.unescapeXml(reportEntry.textContent)}\n", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun strToSource(s: String, encoding: Charset = Charsets.UTF_8) = InputSource(ByteArrayInputStream(s.toByteArray(encoding)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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.execution.console.BasicGutterContentProvider
|
||||||
|
import com.intellij.openapi.editor.event.DocumentAdapter
|
||||||
|
import com.intellij.openapi.editor.event.DocumentEvent
|
||||||
|
import com.intellij.openapi.editor.ex.EditorEx
|
||||||
|
import com.intellij.openapi.editor.markup.EffectType
|
||||||
|
import com.intellij.openapi.editor.markup.HighlighterLayer
|
||||||
|
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||||
|
import com.intellij.openapi.editor.markup.TextAttributes
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.ui.JBColor
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
public class KotlinReplResultHighlighter(private val editor: EditorEx) : DocumentAdapter() {
|
||||||
|
private val EVAL_MARKERS_LENGTH = BasicGutterContentProvider.EVAL_IN_MARKER.length()
|
||||||
|
private val ERROR_PREFIX = "Error: "
|
||||||
|
private val WARNING_PREFIX = "Warning: "
|
||||||
|
|
||||||
|
var rangeQueue: Queue<TextRange> by Delegates.notNull()
|
||||||
|
private var curLine = 0
|
||||||
|
|
||||||
|
private enum class LineType(val color: JBColor) {
|
||||||
|
ERROR(JBColor.RED), WARNING(JBColor.YELLOW), USUAL(JBColor.BLACK)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lineTypeByPrefix(s: String) =
|
||||||
|
if (s.startsWith(ERROR_PREFIX))
|
||||||
|
LineType.ERROR
|
||||||
|
else if (s.startsWith(WARNING_PREFIX))
|
||||||
|
LineType.WARNING
|
||||||
|
else
|
||||||
|
LineType.USUAL
|
||||||
|
|
||||||
|
override fun documentChanged(e: DocumentEvent) {
|
||||||
|
val document = editor.document
|
||||||
|
val docText = document.text
|
||||||
|
if (docText.isEmpty()) {
|
||||||
|
curLine = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val lastErrorPos = docText.lastIndexOf(ERROR_PREFIX)
|
||||||
|
val lastWarningPos = docText.lastIndexOf(WARNING_PREFIX)
|
||||||
|
if (lastErrorPos <= curLine && lastWarningPos <= curLine) return
|
||||||
|
|
||||||
|
val text = document.text
|
||||||
|
val totalLines = document.lineCount
|
||||||
|
var codeLineOffset = -1
|
||||||
|
while (curLine < totalLines) {
|
||||||
|
val lineStart = document.getLineStartOffset(curLine)
|
||||||
|
val lineEnd = document.getLineEndOffset(curLine)
|
||||||
|
val lineText = text.substring(lineStart, lineEnd)
|
||||||
|
val lineType = lineTypeByPrefix(lineText)
|
||||||
|
|
||||||
|
if (lineType != LineType.USUAL) {
|
||||||
|
if (codeLineOffset == -1) codeLineOffset = document.getLineStartOffset(curLine - 1) + EVAL_MARKERS_LENGTH
|
||||||
|
highlightLine(codeLineOffset, lineStart, lineEnd, lineType)
|
||||||
|
}
|
||||||
|
curLine++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun highlightLine(codeLineOffset: Int, msgLineStart: Int, msgLineEne: Int, lineType: LineType) {
|
||||||
|
val historyMarkup = editor.markupModel
|
||||||
|
|
||||||
|
// highlight error or warning message
|
||||||
|
val msgTextAttributes = TextAttributes()
|
||||||
|
msgTextAttributes.foregroundColor = lineType.color
|
||||||
|
msgTextAttributes.backgroundColor = JBColor.LIGHT_GRAY
|
||||||
|
historyMarkup.addRangeHighlighter(msgLineStart, msgLineEne, HighlighterLayer.LAST, msgTextAttributes, HighlighterTargetArea.LINES_IN_RANGE)
|
||||||
|
|
||||||
|
// highlight range in [codeLine]
|
||||||
|
val range = rangeQueue.poll()
|
||||||
|
val highlightedPlaceStart = codeLineOffset + range.startOffset
|
||||||
|
val highlightedPlaceSEnd = codeLineOffset + range.endOffset + if (range.endOffset == range.startOffset) 1 else 0
|
||||||
|
|
||||||
|
val errorWaveAttrs = TextAttributes()
|
||||||
|
errorWaveAttrs.effectType = EffectType.WAVE_UNDERSCORE
|
||||||
|
errorWaveAttrs.effectColor = lineType.color
|
||||||
|
historyMarkup.addRangeHighlighter(highlightedPlaceStart, highlightedPlaceSEnd, HighlighterLayer.LAST, errorWaveAttrs, HighlighterTargetArea.EXACT_RANGE)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.command.WriteCommandAction
|
||||||
|
import java.awt.event.KeyAdapter
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
|
||||||
|
public class KtConsoleKeyListener(private val ktConsole: KotlinConsoleRunner) : KeyAdapter() {
|
||||||
|
private var historyPos = 0
|
||||||
|
private var prevCaretOffset = -1
|
||||||
|
private var unfinishedCommand = ""
|
||||||
|
|
||||||
|
private enum class HistoryMove {
|
||||||
|
UP, DOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun resetHistoryPosition() {
|
||||||
|
historyPos = ktConsole.history.size()
|
||||||
|
prevCaretOffset = -1
|
||||||
|
unfinishedCommand = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyReleased(e: KeyEvent): Unit = when (e.keyCode) {
|
||||||
|
KeyEvent.VK_UP -> moveHistoryCursor(HistoryMove.UP)
|
||||||
|
KeyEvent.VK_DOWN -> moveHistoryCursor(HistoryMove.DOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun moveHistoryCursor(move: HistoryMove) {
|
||||||
|
val history = ktConsole.history
|
||||||
|
if (history.isEmpty()) return
|
||||||
|
|
||||||
|
val caret = ktConsole.consoleView.consoleEditor.caretModel
|
||||||
|
val document = ktConsole.consoleView.editorDocument
|
||||||
|
|
||||||
|
val curOffset = caret.offset
|
||||||
|
val curLine = document.getLineNumber(curOffset)
|
||||||
|
val totalLines = document.lineCount
|
||||||
|
val isMultiline = totalLines > 1
|
||||||
|
|
||||||
|
when (move) {
|
||||||
|
HistoryMove.UP -> {
|
||||||
|
if (curLine != 0 || (isMultiline && prevCaretOffset != 0)) {
|
||||||
|
prevCaretOffset = curOffset
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (historyPos == history.size()) {
|
||||||
|
unfinishedCommand = document.text
|
||||||
|
}
|
||||||
|
|
||||||
|
historyPos = Math.max(historyPos - 1, 0)
|
||||||
|
WriteCommandAction.runWriteCommandAction(ktConsole.project) {
|
||||||
|
document.setText(history[historyPos])
|
||||||
|
caret.moveToOffset(0)
|
||||||
|
prevCaretOffset = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HistoryMove.DOWN -> {
|
||||||
|
if (curLine != totalLines - 1 || (isMultiline && prevCaretOffset != document.textLength)) {
|
||||||
|
prevCaretOffset = curOffset
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
historyPos = Math.min(historyPos + 1, history.size())
|
||||||
|
WriteCommandAction.runWriteCommandAction(ktConsole.project) {
|
||||||
|
document.setText(if (historyPos == history.size()) unfinishedCommand else history[historyPos])
|
||||||
|
caret.moveToOffset(document.textLength)
|
||||||
|
prevCaretOffset = document.textLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.actions
|
||||||
|
|
||||||
|
import com.intellij.execution.console.LanguageConsoleImpl
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.command.WriteCommandAction
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
|
||||||
|
|
||||||
|
public class KtExecuteCommandAction(private val consoleFile: VirtualFile) : AnAction() {
|
||||||
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
|
val project = e.project ?: return errorNotification(null, "<p>Cannot find project</p>")
|
||||||
|
val ktConsole = KotlinConsoleKeeper.getInstance(project).getConsoleByVirtualFile(consoleFile) ?: return errorNotification(project, "<p>Action performed in not valid console</p>")
|
||||||
|
|
||||||
|
WriteCommandAction.runWriteCommandAction(project) {
|
||||||
|
val consoleView = ktConsole.consoleView
|
||||||
|
val document = consoleView.editorDocument
|
||||||
|
val command = document.text
|
||||||
|
|
||||||
|
document.setText(command)
|
||||||
|
LanguageConsoleImpl.printWithHighlighting(consoleView, consoleView.consoleEditor, TextRange(0, command.length()))
|
||||||
|
document.setText("")
|
||||||
|
|
||||||
|
ktConsole.submitCommand(command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.actions
|
||||||
|
|
||||||
|
import com.intellij.notification.Notification
|
||||||
|
import com.intellij.notification.NotificationType
|
||||||
|
import com.intellij.notification.Notifications
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.module.ModuleManager
|
||||||
|
import com.intellij.openapi.module.ModuleUtilCore
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
|
||||||
|
|
||||||
|
fun errorNotification(project: Project?, message: String) {
|
||||||
|
val tag = "KOTLIN REPL ERROR"
|
||||||
|
val title = "Kotlin REPL Configuration Error"
|
||||||
|
Notifications.Bus.notify(Notification(tag, title, message, NotificationType.ERROR), project)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logError(cl: Class<*>, message: String) {
|
||||||
|
val logger = Logger.getInstance(cl)
|
||||||
|
logger.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RunKotlinConsoleAction : AnAction() {
|
||||||
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
|
val project = e.project ?: return errorNotification(null, "<p>Project not found</p>")
|
||||||
|
val module = getModule(e) ?: return errorNotification(project, "<p>Module not found</p>")
|
||||||
|
|
||||||
|
KotlinConsoleKeeper.getInstance(project).run(module)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getModule(e: AnActionEvent): Module? {
|
||||||
|
val project = e.project ?: return null
|
||||||
|
val file = CommonDataKeys.VIRTUAL_FILE.getData(e.dataContext)
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
val moduleForFile = ModuleUtilCore.findModuleForFile(file, project)
|
||||||
|
if (moduleForFile != null) return moduleForFile
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModuleManager.getInstance(project).modules.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,5 +51,6 @@
|
|||||||
<orderEntry type="module" module-name="js.serializer" />
|
<orderEntry type="module" module-name="js.serializer" />
|
||||||
<orderEntry type="module" module-name="idea-js" scope="TEST" />
|
<orderEntry type="module" module-name="idea-js" scope="TEST" />
|
||||||
<orderEntry type="module" module-name="kotlinr" />
|
<orderEntry type="module" module-name="kotlinr" />
|
||||||
|
<orderEntry type="module" module-name="idea-repl" scope="TEST" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+142
-127
@@ -38,20 +38,20 @@
|
|||||||
</component>
|
</component>
|
||||||
</project-components>
|
</project-components>
|
||||||
|
|
||||||
<application-components>
|
<application-components>
|
||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.PluginStartupComponent</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.PluginStartupComponent</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.versions.KotlinUpdatePluginComponent</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.versions.KotlinUpdatePluginComponent</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<interface-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptMetaFileSystem</interface-class>
|
<interface-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptMetaFileSystem</interface-class>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptMetaFileSystem</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptMetaFileSystem</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
</application-components>
|
</application-components>
|
||||||
|
|
||||||
<module-components>
|
<module-components>
|
||||||
<component>
|
<component>
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action id="ShowKotlinBytecode" class="org.jetbrains.kotlin.idea.actions.ShowKotlinBytecodeAction"
|
<action id="ShowKotlinBytecode" class="org.jetbrains.kotlin.idea.actions.ShowKotlinBytecodeAction"
|
||||||
text="Show Kotlin Bytecode">
|
text="Show Kotlin Bytecode">
|
||||||
<add-to-group group-id="KotlinToolsGroup"/>
|
<add-to-group group-id="KotlinToolsGroup"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
@@ -108,14 +108,14 @@
|
|||||||
|
|
||||||
<action id="IntroduceProperty" class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.IntroducePropertyAction"
|
<action id="IntroduceProperty" class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.IntroducePropertyAction"
|
||||||
text="P_roperty..." use-shortcut-of="IntroduceField">
|
text="P_roperty..." use-shortcut-of="IntroduceField">
|
||||||
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceField"/>
|
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceField"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action id="IntroduceLambdaParameter"
|
<action id="IntroduceLambdaParameter"
|
||||||
class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.IntroduceLambdaParameterAction"
|
class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.IntroduceLambdaParameterAction"
|
||||||
text="La_mbda Parameter...">
|
text="La_mbda Parameter...">
|
||||||
<keyboard-shortcut keymap="$default" first-keystroke="control shift P"/>
|
<keyboard-shortcut keymap="$default" first-keystroke="control shift P"/>
|
||||||
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceParameter"/>
|
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceParameter"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action id="CopyAsDiagnosticTest" class="org.jetbrains.kotlin.idea.actions.internal.CopyAsDiagnosticTestAction"
|
<action id="CopyAsDiagnosticTest" class="org.jetbrains.kotlin.idea.actions.internal.CopyAsDiagnosticTestAction"
|
||||||
@@ -125,12 +125,12 @@
|
|||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action id="CheckPartialBodyResolve" class="org.jetbrains.kotlin.idea.actions.internal.CheckPartialBodyResolveAction"
|
<action id="CheckPartialBodyResolve" class="org.jetbrains.kotlin.idea.actions.internal.CheckPartialBodyResolveAction"
|
||||||
text="Check Partial Body Resolve">
|
text="Check Partial Body Resolve">
|
||||||
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action id="FindImplicitNothingAction" class="org.jetbrains.kotlin.idea.actions.internal.FindImplicitNothingAction"
|
<action id="FindImplicitNothingAction" class="org.jetbrains.kotlin.idea.actions.internal.FindImplicitNothingAction"
|
||||||
text="Find Implicit Nothing Calls">
|
text="Find Implicit Nothing Calls">
|
||||||
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
@@ -147,6 +147,18 @@
|
|||||||
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift M"/>
|
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift M"/>
|
||||||
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractFunction"/>
|
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractFunction"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<!-- Kotlin Console REPL-->
|
||||||
|
<action id="KotlinConsoleREPL" class="org.jetbrains.kotlin.console.actions.RunKotlinConsoleAction"
|
||||||
|
text="Kotlin console...">
|
||||||
|
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<action id="KotlinShellExecute" class="com.intellij.openapi.actionSystem.EmptyAction"
|
||||||
|
text="Execute Kotlin Code"
|
||||||
|
description="Execute Kotlin code in console">
|
||||||
|
<keyboard-shortcut first-keystroke="control ENTER" keymap="$default"/>
|
||||||
|
</action>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
@@ -166,7 +178,7 @@
|
|||||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.FileAttributeServiceImpl"/>
|
serviceImplementation="org.jetbrains.kotlin.idea.caches.FileAttributeServiceImpl"/>
|
||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.util.ImportInsertHelper"
|
<projectService serviceInterface="org.jetbrains.kotlin.idea.util.ImportInsertHelper"
|
||||||
serviceImplementation="org.jetbrains.kotlin.util.ImportInsertHelperImpl"/>
|
serviceImplementation="org.jetbrains.kotlin.util.ImportInsertHelperImpl"/>
|
||||||
|
|
||||||
<applicationService serviceInterface="org.jetbrains.kotlin.psi.KotlinDeclarationNavigationPolicy"
|
<applicationService serviceInterface="org.jetbrains.kotlin.psi.KotlinDeclarationNavigationPolicy"
|
||||||
serviceImplementation="org.jetbrains.kotlin.idea.decompiler.navigation.KotlinDeclarationNavigationPolicyImpl"/>
|
serviceImplementation="org.jetbrains.kotlin.idea.decompiler.navigation.KotlinDeclarationNavigationPolicyImpl"/>
|
||||||
@@ -184,7 +196,7 @@
|
|||||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDELightClassGenerationSupport"/>
|
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDELightClassGenerationSupport"/>
|
||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer"
|
<projectService serviceInterface="org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer"
|
||||||
serviceImplementation="org.jetbrains.kotlin.resolve.DummyCodeAnalyzerInitializer"/>
|
serviceImplementation="org.jetbrains.kotlin.resolve.DummyCodeAnalyzerInitializer"/>
|
||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.parsing.JetScriptDefinitionProvider"
|
<projectService serviceInterface="org.jetbrains.kotlin.parsing.JetScriptDefinitionProvider"
|
||||||
serviceImplementation="org.jetbrains.kotlin.parsing.JetScriptDefinitionProvider"/>
|
serviceImplementation="org.jetbrains.kotlin.parsing.JetScriptDefinitionProvider"/>
|
||||||
@@ -237,6 +249,9 @@
|
|||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"
|
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"
|
||||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"/>
|
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"/>
|
||||||
|
|
||||||
|
<projectService serviceInterface="org.jetbrains.kotlin.console.KotlinConsoleKeeper"
|
||||||
|
serviceImplementation="org.jetbrains.kotlin.console.KotlinConsoleKeeper"/>
|
||||||
|
|
||||||
<errorHandler implementation="org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter"/>
|
<errorHandler implementation="org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter"/>
|
||||||
|
|
||||||
@@ -920,13 +935,13 @@
|
|||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.ConvertFunctionToPropertyIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.ConvertPropertyToFunctionIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
@@ -989,20 +1004,20 @@
|
|||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.AddNameToArgumentIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.AddNameToArgumentIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.RemoveArgumentNameIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.RemoveArgumentNameIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.IterateExpressionIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.IterateExpressionIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxIntention</className>
|
||||||
@@ -1014,91 +1029,91 @@
|
|||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="INFO"
|
level="INFO"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ConvertToStringTemplateInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ConvertToStringTemplateInspection"
|
||||||
displayName="Convert string concatenation to string template"
|
displayName="Convert string concatenation to string template"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="INFO"
|
level="INFO"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ExplicitGetInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ExplicitGetInspection"
|
||||||
displayName="Explicit 'get'"
|
displayName="Explicit 'get'"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="false"
|
enabledByDefault="false"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisInspection"
|
||||||
displayName="If-Then foldable to '?:'"
|
displayName="If-Then foldable to '?:'"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessInspection"
|
||||||
displayName="If-Then foldable to '?.'"
|
displayName="If-Then foldable to '?.'"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.IfNullToElvisInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.IfNullToElvisInspection"
|
||||||
displayName="If-Null return/break/... foldable to '?:'"
|
displayName="If-Null return/break/... foldable to '?:'"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsInspection"
|
||||||
displayName="Type arguments are unnecessary"
|
displayName="Type arguments are unnecessary"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveExplicitSuperQualifierInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveExplicitSuperQualifierInspection"
|
||||||
displayName="Supertype qualification is unnecessary"
|
displayName="Supertype qualification is unnecessary"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.SimplifyNegatedBinaryExpressionInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.SimplifyNegatedBinaryExpressionInspection"
|
||||||
displayName="Simplify negated binary expression"
|
displayName="Simplify negated binary expression"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ReplaceWithOperatorAssignmentInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ReplaceWithOperatorAssignmentInspection"
|
||||||
displayName="Replace with operator-assignment"
|
displayName="Replace with operator-assignment"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IntroduceWhenSubjectInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IntroduceWhenSubjectInspection"
|
||||||
displayName="Introduce argument to 'when'"
|
displayName="Introduce argument to 'when'"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveCurlyBracesFromTemplateInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveCurlyBracesFromTemplateInspection"
|
||||||
displayName="Remove redundant curly braces in string template"
|
displayName="Remove redundant curly braces in string template"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.SimplifyBooleanWithConstantsInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.SimplifyBooleanWithConstantsInspection"
|
||||||
displayName="Simplify boolean expression with constants"
|
displayName="Simplify boolean expression with constants"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WEAK WARNING"
|
level="WEAK WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxInspection"
|
||||||
displayName="Use property access syntax"
|
displayName="Use property access syntax"
|
||||||
@@ -1109,18 +1124,18 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection"
|
||||||
displayName="Unused symbol"
|
displayName="Unused symbol"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedReceiverParameterInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedReceiverParameterInspection"
|
||||||
displayName="Unused receiver parameter"
|
displayName="Unused receiver parameter"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedImportInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedImportInspection"
|
||||||
displayName="Unused import directive"
|
displayName="Unused import directive"
|
||||||
@@ -1137,26 +1152,26 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.kdoc.KDocUnresolvedReferenceInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.kdoc.KDocUnresolvedReferenceInspection"
|
||||||
displayName="Unresolved reference in KDoc"
|
displayName="Unresolved reference in KDoc"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.refactoring.move.changePackage.PackageDirectoryMismatchInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.refactoring.move.changePackage.PackageDirectoryMismatchInspection"
|
||||||
displayName="Package name does not match containing directory"
|
displayName="Package name does not match containing directory"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinCleanupInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinCleanupInspection"
|
||||||
shortName="KotlinDeprecation"
|
shortName="KotlinDeprecation"
|
||||||
displayName="Usage of redundant or deprecated syntax or deprecated symbols"
|
displayName="Usage of redundant or deprecated syntax or deprecated symbols"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
cleanupTool="true"
|
cleanupTool="true"
|
||||||
level="WARNING"/>
|
level="WARNING"/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.RemoveForLoopIndicesInspection"
|
||||||
displayName="Index is unused"
|
displayName="Index is unused"
|
||||||
@@ -1188,8 +1203,8 @@
|
|||||||
</extensionPoints>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
<xi:include href="extensions/kotlin2jvm.xml" xpointer="xpointer(/idea-plugin/extensions/*)"/>
|
<xi:include href="extensions/kotlin2jvm.xml" xpointer="xpointer(/idea-plugin/extensions/*)"/>
|
||||||
<xi:include href="extensions/kotlin2js.xml" xpointer="xpointer(/idea-plugin/extensions/*)"/>
|
<xi:include href="extensions/kotlin2js.xml" xpointer="xpointer(/idea-plugin/extensions/*)"/>
|
||||||
<quickFixContributor implementation="org.jetbrains.kotlin.idea.quickfix.QuickFixRegistrar"/>
|
<quickFixContributor implementation="org.jetbrains.kotlin.idea.quickfix.QuickFixRegistrar"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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.idea.console
|
||||||
|
|
||||||
|
import com.intellij.execution.impl.ConsoleViewImpl
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.testFramework.PlatformTestCase
|
||||||
|
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
|
||||||
|
import org.jetbrains.kotlin.console.KotlinConsoleRunner
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
public class KotlinReplTest : PlatformTestCase() {
|
||||||
|
private var consoleRunner: KotlinConsoleRunner by Delegates.notNull()
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
val consoleView = consoleRunner.consoleView
|
||||||
|
|
||||||
|
consoleRunner.processHandler.destroyProcess()
|
||||||
|
|
||||||
|
// dispose RunContentDescriptor by reflection
|
||||||
|
val getNodeMethod = Disposer.getTree().javaClass.getDeclaredMethod("getNode", Object().javaClass)
|
||||||
|
getNodeMethod.isAccessible = true
|
||||||
|
val consoleNode = getNodeMethod(Disposer.getTree(), consoleView)
|
||||||
|
val getParentMethod = consoleNode.javaClass.getDeclaredMethod("getParent")
|
||||||
|
getParentMethod.isAccessible = true
|
||||||
|
val consoleParent = getParentMethod(consoleNode)
|
||||||
|
val getObjectMethod = consoleParent.javaClass.getDeclaredMethod("getObject")
|
||||||
|
getObjectMethod.isAccessible = true
|
||||||
|
val descriptor = getObjectMethod(consoleParent) as Disposable
|
||||||
|
|
||||||
|
Disposer.dispose(descriptor)
|
||||||
|
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkHistoryUpdate(maxIter: Int = 20, sleepTime: Long = 500, p: (String) -> Boolean): String {
|
||||||
|
val consoleView = consoleRunner.consoleView as ConsoleViewImpl
|
||||||
|
var docHistory: String = ""
|
||||||
|
|
||||||
|
for (i in 1..maxIter) {
|
||||||
|
docHistory = consoleRunner.consoleView.historyViewer.document.text.trim()
|
||||||
|
|
||||||
|
if (p(docHistory)) break
|
||||||
|
|
||||||
|
Thread.sleep(sleepTime)
|
||||||
|
consoleView.flushDeferredText()
|
||||||
|
}
|
||||||
|
|
||||||
|
return docHistory
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun testOnRunPossibility() {
|
||||||
|
val allOk = { x: String -> x.contains(":help for help") }
|
||||||
|
val hasErrors = { x: String -> x.contains("Process finished with exit code 1") || x.contains("Exception in") || x.contains("Error") }
|
||||||
|
val historyText = checkHistoryUpdate { hasErrors(it) || allOk(it) }
|
||||||
|
|
||||||
|
assertFalse(hasErrors(historyText), "Cannot run kotlin repl")
|
||||||
|
assertTrue(allOk(historyText), "Successful run should contain text: ':help for help'")
|
||||||
|
assertFalse(consoleRunner.processHandler.isProcessTerminated, "Process accidentally terminated")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun testSimpleCommand() {
|
||||||
|
consoleRunner.submitCommand("1 + 1")
|
||||||
|
val docHistory = checkHistoryUpdate { x: String -> x.endsWith('2') }
|
||||||
|
|
||||||
|
assertTrue(docHistory.endsWith('2'), "1 + 1 should be equal 2, but document history is: '$docHistory'")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user