Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added code completion for intellij plugin (now use Shift-Enter to exe…

…cute expressions). Related to #22
  • Loading branch information...
commit 70e48825b6f245c8cea51c45d1d8dba6f582d732 1 parent 5e3b3e6
@albertlatacz authored
View
10 intellij-plugin/java-repl-intellij-plugin.iml
@@ -7,15 +7,7 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
- <orderEntry type="module-library" exported="">
- <library>
- <CLASSES>
- <root url="jar://$MODULE_DIR$/../build/artifacts/javarepl-dev.build.jar!/" />
- </CLASSES>
- <JAVADOC />
- <SOURCES />
- </library>
- </orderEntry>
+ <orderEntry type="module" module-name="java-repl" />
</component>
</module>
View
6 intellij-plugin/src/META-INF/plugin.xml
@@ -34,12 +34,6 @@
<keyboard-shortcut first-keystroke="alt shift J" keymap="$default"/>
</action>
- <action id="JavaREPL.Console.Execute"
- class="com.intellij.openapi.actionSystem.EmptyAction"
- text="Execute Current Java Statement">
- <keyboard-shortcut keymap="$default" first-keystroke="ENTER"/>
- </action>
-
<action id="JavaREPL.Console.Execute.Immediately"
class="com.intellij.openapi.actionSystem.EmptyAction"
text="Execute Current Java Statement">
View
5 intellij-plugin/src/javarepl/plugin/JavaREPLConsoleExecuteActionHandler.java
@@ -1,6 +1,5 @@
package javarepl.plugin;
-import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.process.ConsoleHistoryModel;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.ide.highlighter.JavaFileType;
@@ -50,7 +49,7 @@ public void processLine(String line) {
}
}
- public void runExecuteAction(final LanguageConsoleImpl console,
+ public void runExecuteAction(final JavaREPLLanguageConsole console,
boolean executeImmediately) {
if (executeImmediately) {
@@ -88,7 +87,7 @@ protected void run(Result result) throws Throwable {
execute(console, consoleHistoryModel);
}
- private void execute(LanguageConsoleImpl languageConsole,
+ private void execute(JavaREPLLanguageConsole languageConsole,
ConsoleHistoryModel consoleHistoryModel) {
final Document document = languageConsole.getCurrentEditor().getDocument();
View
493 intellij-plugin/src/javarepl/plugin/JavaREPLConsoleHistoryController.java
@@ -0,0 +1,493 @@
+package javarepl.plugin;
+
+/*
+ * Copied from IntelliJ 12 sourcecode and heavily modified
+ *
+ * Copyright 2000-2012 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.
+ */
+
+import com.intellij.codeInsight.lookup.LookupManager;
+import com.intellij.execution.process.ConsoleHistoryModel;
+import com.intellij.lang.Language;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.EmptyAction;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.command.undo.UndoConstants;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.*;
+import com.intellij.openapi.editor.actions.ContentChooser;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
+import com.intellij.openapi.keymap.KeymapUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ex.ProjectEx;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.CharFilter;
+import com.intellij.openapi.util.text.StringHash;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileFactory;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.util.ObjectUtils;
+import com.intellij.util.io.SafeFileOutputStream;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.xml.XppReader;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.awt.event.KeyEvent;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * @author gregsh
+ */
+public class JavaREPLConsoleHistoryController {
+
+ private static final Logger LOG = Logger.getInstance("com.intellij.execution.console.ConsoleHistoryController");
+
+ private final JavaREPLLanguageConsole myConsole;
+ private final AnAction myHistoryNext = new MyAction(true);
+ private final AnAction myHistoryPrev = new MyAction(false);
+ private final AnAction myBrowseHistory = new MyBrowseAction();
+ private boolean myMultiline;
+ private ModelHelper myHelper;
+ private long myLastSaveStamp;
+
+ public JavaREPLConsoleHistoryController(@NotNull final String type,
+ @Nullable final String persistenceId,
+ @NotNull final JavaREPLLanguageConsole console,
+ @NotNull final ConsoleHistoryModel model) {
+ this(type, persistenceId, console, model, Charset.defaultCharset());
+ }
+
+ public JavaREPLConsoleHistoryController(@NotNull final String type,
+ @Nullable final String persistenceId,
+ @NotNull final JavaREPLLanguageConsole console,
+ @NotNull final ConsoleHistoryModel model,
+ @NotNull final Charset charset) {
+ String id = persistenceId == null || StringUtil.isEmpty(persistenceId) ? console.getProject().getPresentableUrl() : persistenceId;
+ myHelper = new ModelHelper(type, id, model, charset);
+ myConsole = console;
+ }
+
+ public boolean isMultiline() {
+ return myMultiline;
+ }
+
+ public JavaREPLConsoleHistoryController setMultiline(boolean multiline) {
+ myMultiline = multiline;
+ return this;
+ }
+
+ public ConsoleHistoryModel getModel() {
+ return myHelper.getModel();
+ }
+
+ public void install() {
+ if (myHelper.getId() != null) {
+ ApplicationManager.getApplication().getMessageBus().connect(myConsole).subscribe(
+ ProjectEx.ProjectSaved.TOPIC, new ProjectEx.ProjectSaved() {
+ @Override
+ public void saved(@NotNull final Project project) {
+ saveHistory();
+ }
+ });
+ Disposer.register(myConsole, new Disposable() {
+ @Override
+ public void dispose() {
+ saveHistory();
+ }
+ });
+ loadHistory(myHelper.getId());
+ }
+ configureActions();
+ myLastSaveStamp = getCurrentTimeStamp();
+ }
+
+ private long getCurrentTimeStamp() {
+ return getModel().getModificationCount() + myConsole.getEditorDocument().getModificationStamp();
+ }
+
+ private void configureActions() {
+ EmptyAction.setupAction(myHistoryNext, "Console.History.Next", null);
+ EmptyAction.setupAction(myHistoryPrev, "Console.History.Previous", null);
+ EmptyAction.setupAction(myBrowseHistory, "Console.History.Browse", null);
+ if (!myMultiline) {
+ EmptyAction.setupAction(myBrowseHistory, "Console.History.BrowseTW", null);
+ myHistoryNext.registerCustomShortcutSet(KeyEvent.VK_UP, 0, null);
+ myHistoryPrev.registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, null);
+ }
+ myHistoryNext.registerCustomShortcutSet(myHistoryNext.getShortcutSet(), myConsole.getCurrentEditor().getComponent());
+ myHistoryPrev.registerCustomShortcutSet(myHistoryPrev.getShortcutSet(), myConsole.getCurrentEditor().getComponent());
+ myBrowseHistory.registerCustomShortcutSet(myBrowseHistory.getShortcutSet(), myConsole.getCurrentEditor().getComponent());
+ }
+
+ /**
+ * Use this method if you decided to change the id for your console but don't want your users to loose their current histories
+ *
+ * @param id previous id id
+ * @return true if some text has been loaded; otherwise false
+ */
+ public boolean loadHistory(String id) {
+ String prev = myHelper.getContent();
+ boolean result = myHelper.loadHistory(id);
+ String userValue = myHelper.getContent();
+ if (prev != userValue && userValue != null) {
+ setConsoleText(userValue, false, false);
+ }
+ return result;
+ }
+
+ private void saveHistory() {
+ if (myLastSaveStamp == getCurrentTimeStamp()) return;
+ myHelper.setContent(myConsole.getEditorDocument().getText());
+ myHelper.saveHistory();
+ myLastSaveStamp = getCurrentTimeStamp();
+ }
+
+ private static void cleanupOldFiles(final File dir) {
+ final long keep10weeks = 10 * 1000L * 60 * 60 * 24 * 7;
+ final long curTime = System.currentTimeMillis();
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isFile() && file.getName().endsWith(".hist.xml") && curTime - file.lastModified() > keep10weeks) {
+ file.delete();
+ }
+ }
+ }
+ }
+
+ public AnAction getHistoryNext() {
+ return myHistoryNext;
+ }
+
+ public AnAction getHistoryPrev() {
+ return myHistoryPrev;
+ }
+
+ public AnAction getBrowseHistory() {
+ return myBrowseHistory;
+ }
+
+ protected void setConsoleText(final String command, final boolean storeUserText, final boolean regularMode) {
+ final Editor editor = myConsole.getCurrentEditor();
+ final Document document = editor.getDocument();
+ new WriteCommandAction.Simple(myConsole.getProject()) {
+ @Override
+ public void run() {
+ if (storeUserText) {
+ myHelper.setContent(document.getText());
+ }
+ String text = StringUtil.notNullize(command);
+ int offset;
+ if (regularMode) {
+ if (myMultiline) {
+ if (text.isEmpty()) return;
+ int selectionStart = editor.getSelectionModel().getSelectionStart();
+ int selectionEnd = editor.getSelectionModel().getSelectionEnd();
+ int caretOffset = editor.getCaretModel().getOffset();
+ int line = document.getLineNumber(caretOffset);
+ int lineStartOffset = document.getLineStartOffset(line);
+ if (selectionStart == lineStartOffset) document.deleteString(selectionStart, selectionEnd);
+ String trimmedLine = document.getText(new TextRange(lineStartOffset, document.getLineEndOffset(line))).trim();
+ if (StringUtil.findFirst(trimmedLine, new CharFilter() {
+ @Override
+ public boolean accept(char ch) {
+ return ch == '\'' || ch == '\"' || ch == '_' || Character.isLetterOrDigit(ch);
+ }
+ }) > -1) {
+ text += "\n";
+ }
+ document.insertString(lineStartOffset, text);
+ offset = lineStartOffset;
+ editor.getSelectionModel().setSelection(lineStartOffset, lineStartOffset + text.length());
+ } else {
+ document.setText(text);
+ offset = document.getTextLength();
+ }
+ } else {
+ offset = 0;
+ try {
+ document.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
+ document.setText(text);
+ } finally {
+ document.putUserData(UndoConstants.DONT_RECORD_UNDO, null);
+ }
+ }
+ editor.getCaretModel().moveToOffset(offset);
+ editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ }
+ }.execute();
+ }
+
+
+ private class MyAction extends AnAction {
+ private boolean myNext;
+
+ public MyAction(final boolean next) {
+ myNext = next;
+ getTemplatePresentation().setVisible(false);
+ }
+
+ @Override
+ public void actionPerformed(final AnActionEvent e) {
+ final String command;
+ if (myNext) {
+ command = getModel().getHistoryNext();
+ if (!myMultiline && command == null) return;
+ } else {
+ if (!myMultiline && getModel().getHistoryCursor() < 0) return;
+ command = ObjectUtils.chooseNotNull(getModel().getHistoryPrev(), myMultiline ? "" : StringUtil.notNullize(myHelper.getContent()));
+ }
+ setConsoleText(command, myNext && getModel().getHistoryCursor() == 0, true);
+ }
+
+ @Override
+ public void update(final AnActionEvent e) {
+ super.update(e);
+ e.getPresentation().setEnabled(myMultiline || canMoveInEditor(myNext));
+ }
+ }
+
+ private boolean canMoveInEditor(final boolean next) {
+ final Editor consoleEditor = myConsole.getCurrentEditor();
+ final Document document = consoleEditor.getDocument();
+ final CaretModel caretModel = consoleEditor.getCaretModel();
+
+ if (LookupManager.getActiveLookup(consoleEditor) != null) return false;
+
+ if (next) {
+ return document.getLineNumber(caretModel.getOffset()) == 0;
+ } else {
+ final int lineCount = document.getLineCount();
+ return (lineCount == 0 || document.getLineNumber(caretModel.getOffset()) == lineCount - 1) &&
+ StringUtil.isEmptyOrSpaces(document.getText().substring(caretModel.getOffset()));
+ }
+ }
+
+
+ private class MyBrowseAction extends AnAction {
+
+ @Override
+ public void update(final AnActionEvent e) {
+ e.getPresentation().setEnabled(getModel().getHistorySize() > 0);
+ }
+
+ @Override
+ public void actionPerformed(final AnActionEvent e) {
+ String s1 = KeymapUtil.getFirstKeyboardShortcutText(myHistoryNext);
+ String s2 = KeymapUtil.getFirstKeyboardShortcutText(myHistoryPrev);
+ String title = myConsole.getTitle() + " History" +
+ (StringUtil.isNotEmpty(s1) && StringUtil.isNotEmpty(s2) ? " (" + s1 + " and " + s2 + " while in editor)" : "");
+ final ContentChooser<String> chooser = new ContentChooser<String>(myConsole.getProject(), title, true) {
+
+ @Override
+ protected void removeContentAt(String content) {
+ getModel().removeFromHistory(content);
+ }
+
+ @Override
+ protected String getStringRepresentationFor(String content) {
+ return content;
+ }
+
+ @Override
+ protected List<String> getContents() {
+ return getModel().getHistory();
+ }
+
+ @Override
+ protected Editor createIdeaEditor(String text) {
+ PsiFile consoleFile = myConsole.getFile();
+ Language language = consoleFile.getLanguage();
+ Project project = consoleFile.getProject();
+
+ PsiFile psiFile = PsiFileFactory.getInstance(project).createFileFromText(
+ "a." + consoleFile.getFileType().getDefaultExtension(),
+ language,
+ StringUtil.convertLineSeparators(new String(text)), false, true);
+ VirtualFile virtualFile = psiFile.getViewProvider().getVirtualFile();
+ if (virtualFile instanceof LightVirtualFile) ((LightVirtualFile) virtualFile).setWritable(false);
+ Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
+ EditorFactory editorFactory = EditorFactory.getInstance();
+ EditorEx editor = (EditorEx) editorFactory.createViewer(document, project);
+ editor.getSettings().setFoldingOutlineShown(false);
+ editor.getSettings().setLineMarkerAreaShown(false);
+ editor.getSettings().setIndentGuidesShown(false);
+
+ SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(language, project, psiFile.getViewProvider().getVirtualFile());
+ editor.setHighlighter(new LexerEditorHighlighter(highlighter, editor.getColorsScheme()));
+ return editor;
+ }
+ };
+ chooser.setContentIcon(null);
+ chooser.setSplitterOrientation(false);
+ chooser.setSelectedIndex(Math.max(getModel().getHistoryCursor(), 0));
+ chooser.show();
+ if (chooser.isOK()) {
+ setConsoleText(chooser.getSelectedText(), false, true);
+ }
+ }
+ }
+
+ public static class ModelHelper {
+ private final String myType;
+ private final String myId;
+ private final ConsoleHistoryModel myModel;
+ private String myContent;
+ @NotNull
+ private final Charset myCharset;
+
+ public ModelHelper(String type, String id, ConsoleHistoryModel model, @NotNull Charset charset) {
+ myType = type;
+ myId = id;
+ myModel = model;
+ myCharset = charset;
+ }
+
+ public ConsoleHistoryModel getModel() {
+ return myModel;
+ }
+
+ public void setContent(String userValue) {
+ myContent = userValue;
+ }
+
+ public String getId() {
+ return myId;
+ }
+
+ public String getContent() {
+ return myContent;
+ }
+
+ private String getHistoryFilePath(final String id) {
+ return PathManager.getSystemPath() + File.separator +
+ "userHistory" + File.separator +
+ myType + Long.toHexString(StringHash.calc(id)) + ".hist.xml";
+ }
+
+ public boolean loadHistory(String id) {
+ File file = new File(getHistoryFilePath(id));
+ if (!file.exists()) return false;
+ HierarchicalStreamReader xmlReader = null;
+ try {
+ xmlReader = new XppReader(new InputStreamReader(new FileInputStream(file), myCharset));
+ String text = loadHistory(xmlReader, id);
+ if (text != null) {
+ myContent = text;
+ return true;
+ }
+ } catch (Exception ex) {
+ LOG.error(ex);
+ } finally {
+ if (xmlReader != null) {
+ xmlReader.close();
+ }
+ }
+ return false;
+ }
+
+ private void saveHistory() {
+ final File file = new File(getHistoryFilePath(myId));
+ final File dir = file.getParentFile();
+ if (!dir.exists() && !dir.mkdirs() || !dir.isDirectory()) {
+ LOG.error("failed to create folder: " + dir.getAbsolutePath());
+ return;
+ }
+
+ OutputStream os = null;
+ try {
+ final XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
+ try {
+ serializer.setProperty("http://xmlpull.org/v1/doc/properties.html#serializer-indentation", " ");
+ } catch (Exception e) {
+ // not recognized
+ }
+ serializer.setOutput(os = new SafeFileOutputStream(file), myCharset.name());
+ saveHistory(serializer);
+ } catch (Exception ex) {
+ LOG.error(ex);
+ } finally {
+ try {
+ os.close();
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ cleanupOldFiles(dir);
+ }
+
+ @Nullable
+ private String loadHistory(final HierarchicalStreamReader in, final String expectedId) {
+ if (!in.getNodeName().equals("console-history")) return null;
+ final String id = in.getAttribute("id");
+ if (!expectedId.equals(id)) return null;
+ final ArrayList<String> entries = new ArrayList<String>();
+ String consoleContent = null;
+ while (in.hasMoreChildren()) {
+ in.moveDown();
+ if ("history-entry".equals(in.getNodeName())) {
+ entries.add(in.getValue());
+ } else if ("console-content".equals(in.getNodeName())) {
+ consoleContent = in.getValue();
+ }
+ in.moveUp();
+ }
+ for (ListIterator<String> iterator = entries.listIterator(entries.size()); iterator.hasPrevious(); ) {
+ final String entry = iterator.previous();
+ getModel().addToHistory(entry);
+ }
+ return consoleContent;
+ }
+
+ private void saveHistory(final XmlSerializer out) throws IOException {
+ out.startDocument(CharsetToolkit.UTF8, null);
+ out.startTag(null, "console-history");
+ out.attribute(null, "id", myId);
+ for (String s : getModel().getHistory()) {
+ out.startTag(null, "history-entry");
+ out.text(s);
+ out.endTag(null, "history-entry");
+ }
+ String current = myContent;
+ if (StringUtil.isNotEmpty(current)) {
+ out.startTag(null, "console-content");
+ out.text(current);
+ out.endTag(null, "console-content");
+ }
+ out.endTag(null, "console-history");
+ out.endDocument();
+ }
+ }
+
+}
View
41 intellij-plugin/src/javarepl/plugin/JavaREPLConsoleRunner.java
@@ -4,9 +4,6 @@
import com.intellij.execution.configurations.CommandLineBuilder;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.JavaParameters;
-import com.intellij.execution.console.ConsoleHistoryController;
-import com.intellij.execution.console.LanguageConsoleImpl;
-import com.intellij.execution.console.LanguageConsoleViewImpl;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.process.*;
import com.intellij.execution.ui.ConsoleViewContentType;
@@ -33,6 +30,7 @@
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.PathUtil;
import javarepl.Main;
+import javarepl.client.JavaREPLClient;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,22 +40,24 @@
import java.io.IOException;
import java.util.*;
+import static javarepl.Utils.randomServerPort;
+
public class JavaREPLConsoleRunner {
public static final String REPL_TITLE = "Java REPL";
public static final String REPL_MAIN_CLASS = "javarepl.Main";
public static final String EXECUTE_ACTION_IMMEDIATELY_ID = "JavaREPL.Console.Execute.Immediately";
- public static final String EXECUTE_ACTION_ID = "JavaREPL.Console.Execute";
private final Module module;
private final Project project;
private final String consoleTitle;
private final String workingDir;
+ public Integer port;
private final ConsoleHistoryModel consoleHistoryModel;
- private LanguageConsoleViewImpl languageConsoleView;
- private LanguageConsoleImpl languageConsole;
+ private JavaREPLLanguageConsoleView languageConsoleView;
+ private JavaREPLLanguageConsole languageConsole;
private ProcessHandler processHandler;
private JavaREPLConsoleExecuteActionHandler consoleExecuteActionHandler;
@@ -90,16 +90,17 @@ public static void run(@NotNull final Module module,
}
public void initAndRun(final String... statements) throws ExecutionException, IOException {
+ port = randomServerPort();
- languageConsole = new LanguageConsoleImpl(project, consoleTitle, JavaLanguage.INSTANCE);
- languageConsoleView = new LanguageConsoleViewImpl(languageConsole);
+ languageConsole = new JavaREPLLanguageConsole(project, consoleTitle, JavaLanguage.INSTANCE, new JavaREPLClient("localhost", port));
+ languageConsoleView = new JavaREPLLanguageConsoleView(languageConsole);
GeneralCommandLine commandLine = createCommandLine(module, workingDir);
processHandler = new ColoredProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString()) {
@Override
protected void textAvailable(String text, Key attributes) {
languageConsole.setPrompt("java> ");
- LanguageConsoleImpl.printToConsole(languageConsole, StringUtil.convertLineSeparators(text).replace("java> ", ""), ConsoleViewContentType.NORMAL_OUTPUT, null);
+ JavaREPLLanguageConsole.printToConsole(languageConsole, StringUtil.convertLineSeparators(text).replace("java> ", ""), ConsoleViewContentType.NORMAL_OUTPUT, null);
}
};
@@ -141,8 +142,6 @@ public void run() {
registerActionShortcuts(actions, panel);
panel.updateUI();
- createAndRegisterEnterAction(panel);
-
ExecutionManager.getInstance(project).getContentManager().showRunContent(defaultExecutor, myDescriptor);
final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(defaultExecutor.getId());
@@ -154,27 +153,16 @@ public void run() {
processHandler.startNotify();
- final LanguageConsoleImpl console = languageConsoleView.getConsole();
+ final JavaREPLLanguageConsole console = languageConsoleView.getConsole();
for (String statement : statements) {
final String st = statement + "\n";
final ConsoleViewContentType outputType = ConsoleViewContentType.NORMAL_OUTPUT;
- LanguageConsoleImpl.printToConsole(console, st, outputType, null);
+ JavaREPLLanguageConsole.printToConsole(console, st, outputType, null);
final JavaREPLConsoleExecuteActionHandler actionHandler = consoleExecuteActionHandler;
actionHandler.processLine(st);
}
-
- }
-
- private void createAndRegisterEnterAction(JPanel panel) {
- final AnAction enterAction = new JavaREPLExecuteActionBase(languageConsole, processHandler, JavaREPLConsoleRunner.EXECUTE_ACTION_ID) {
- public void actionPerformed(AnActionEvent anActionEvent) {
- consoleExecuteActionHandler.runExecuteAction(languageConsole, false);
- }
- };
- enterAction.registerCustomShortcutSet(enterAction.getShortcutSet(), languageConsole.getConsoleEditor().getComponent());
- enterAction.registerCustomShortcutSet(enterAction.getShortcutSet(), panel);
}
private static void registerActionShortcuts(final AnAction[] actions, final JComponent component) {
@@ -224,7 +212,7 @@ public void setSelected(AnActionEvent e, boolean state) {
return actions;
}
- public ArrayList<AnAction> createConsoleExecActions(final LanguageConsoleImpl languageConsole,
+ public ArrayList<AnAction> createConsoleExecActions(final JavaREPLLanguageConsole languageConsole,
final ProcessHandler processHandler,
final ConsoleHistoryModel historyModel) {
@@ -234,7 +222,7 @@ public void actionPerformed(AnActionEvent anActionEvent) {
}
};
- final ConsoleHistoryController historyController = new ConsoleHistoryController("JavaREPL", null, languageConsole, historyModel);
+ final JavaREPLConsoleHistoryController historyController = new JavaREPLConsoleHistoryController("JavaREPL", null, languageConsole, historyModel);
historyController.install();
final AnAction upAction = historyController.getHistoryPrev();
@@ -286,6 +274,7 @@ private GeneralCommandLine createCommandLine(Module module, String workingDir) t
envParams.putAll(System.getenv());
line.setEnvParams(envParams);
line.addParameter("--simpleConsole");
+ line.addParameter("--port=" + port);
return line;
}
View
59 intellij-plugin/src/javarepl/plugin/JavaREPLExecuteActionBase.java
@@ -4,7 +4,6 @@
import com.intellij.codeInsight.completion.CompletionService;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
-import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.EmptyAction;
@@ -12,39 +11,39 @@
import com.intellij.openapi.util.IconLoader;
public abstract class JavaREPLExecuteActionBase extends DumbAwareAction {
- public static final String ACTIONS_EXECUTE_ICON = "/actions/execute.png";
-
- protected final LanguageConsoleImpl languageConsole;
- protected final ProcessHandler myProcessHandler;
-
- public JavaREPLExecuteActionBase(LanguageConsoleImpl languageConsole,
- ProcessHandler processHandler,
- String actionId) {
- super(null, null, IconLoader.getIcon(ACTIONS_EXECUTE_ICON));
- this.languageConsole = languageConsole;
- myProcessHandler = processHandler;
- EmptyAction.setupAction(this, actionId, null);
- }
-
- public void update(final AnActionEvent e) {
- e.getPresentation().setEnabled(isActionEnabled());
- }
-
- private boolean isActionEnabled() {
- if (myProcessHandler.isProcessTerminated()) {
- return false;
+ public static final String ACTIONS_EXECUTE_ICON = "/actions/execute.png";
+
+ protected final JavaREPLLanguageConsole languageConsole;
+ protected final ProcessHandler myProcessHandler;
+
+ public JavaREPLExecuteActionBase(JavaREPLLanguageConsole languageConsole,
+ ProcessHandler processHandler,
+ String actionId) {
+ super(null, null, IconLoader.getIcon(ACTIONS_EXECUTE_ICON));
+ this.languageConsole = languageConsole;
+ this.myProcessHandler = processHandler;
+ EmptyAction.setupAction(this, actionId, null);
}
- final Lookup lookup = LookupManager.getActiveLookup(languageConsole.getConsoleEditor());
- if (lookup == null || !lookup.isCompletion()) {
- return true;
+ public void update(final AnActionEvent e) {
+ e.getPresentation().setEnabled(isActionEnabled());
}
- CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion();
- if (completion != null && completion.isAutopopupCompletion() && !lookup.isSelectionTouched()) {
- return true;
+ private boolean isActionEnabled() {
+ if (myProcessHandler.isProcessTerminated()) {
+ return false;
+ }
+
+ final Lookup lookup = LookupManager.getActiveLookup(languageConsole.getConsoleEditor());
+ if (lookup == null || !lookup.isCompletion()) {
+ return true;
+ }
+
+ CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion();
+ if (completion != null && completion.isAutopopupCompletion() && !lookup.isSelectionTouched()) {
+ return true;
+ }
+ return false;
}
- return false;
- }
}
View
773 intellij-plugin/src/javarepl/plugin/JavaREPLLanguageConsole.java
@@ -0,0 +1,773 @@
+package javarepl.plugin;
+
+/*
+ * Copied from IntelliJ 12 sourcecode and heavily modified
+ *
+ * Copyright 2000-2011 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.
+ */
+
+import com.intellij.execution.impl.ConsoleViewUtil;
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.ide.DataManager;
+import com.intellij.ide.highlighter.HighlighterFactory;
+import com.intellij.ide.impl.TypeSafeDataProviderAdapter;
+import com.intellij.injected.editor.EditorWindow;
+import com.intellij.lang.Language;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.*;
+import com.intellij.openapi.editor.actions.EditorActionUtil;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.colors.impl.DelegateColorScheme;
+import com.intellij.openapi.editor.event.*;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.ex.FocusChangeListener;
+import com.intellij.openapi.editor.ex.util.EditorUtil;
+import com.intellij.openapi.editor.highlighter.EditorHighlighter;
+import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
+import com.intellij.openapi.editor.highlighter.HighlighterIterator;
+import com.intellij.openapi.editor.impl.DocumentMarkupModel;
+import com.intellij.openapi.editor.impl.EditorFactoryImpl;
+import com.intellij.openapi.editor.markup.HighlighterLayer;
+import com.intellij.openapi.editor.markup.HighlighterTargetArea;
+import com.intellij.openapi.editor.markup.MarkupModel;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.fileEditor.*;
+import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
+import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
+import com.intellij.openapi.fileTypes.FileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.PsiDocumentManagerImpl;
+import com.intellij.psi.impl.PsiManagerEx;
+import com.intellij.psi.impl.file.impl.FileManager;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.ui.SideBorder;
+import com.intellij.util.Function;
+import com.intellij.util.ObjectUtils;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.AbstractLayoutManager;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.update.MergingUpdateQueue;
+import com.intellij.util.ui.update.Update;
+import javarepl.client.ExpressionTemplate;
+import javarepl.client.JavaREPLClient;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static javarepl.Utils.randomIdentifier;
+
+/**
+ * @author Gregory.Shrago
+ */
+public class JavaREPLLanguageConsole implements Disposable, TypeSafeDataProvider {
+ private static final Logger LOG = Logger.getInstance("#" + JavaREPLLanguageConsole.class.getName());
+ private static final int SEPARATOR_THICKNESS = 1;
+ private final Project myProject;
+
+ private final EditorEx myConsoleEditor;
+ private final EditorEx myHistoryViewer;
+ private final Document myEditorDocument;
+ private LightVirtualFile myVirtualFile;
+ private final JavaREPLClient replClient;
+
+ protected PsiFile myFile; // will change on language change
+
+ private final JPanel myPanel = new JPanel(new MyLayout());
+ private String myTitle;
+ @Nullable
+ private String myPrompt = "> ";
+ private final LightVirtualFile myHistoryFile;
+ private Editor myCurrentEditor;
+
+ private final AtomicBoolean myForceScrollToEnd = new AtomicBoolean(false);
+ private final MergingUpdateQueue myUpdateQueue;
+ private Runnable myUiUpdateRunnable;
+
+ private boolean myShowSeparatorLine = true;
+
+ private FocusChangeListener myFocusListener = new FocusChangeListener() {
+ @Override
+ public void focusGained(Editor editor) {
+ myCurrentEditor = editor;
+ }
+
+ @Override
+ public void focusLost(Editor editor) {
+ }
+ };
+
+ public JavaREPLLanguageConsole(Project project, String title, Language language, JavaREPLClient replClient) {
+ this(project, title, language, true, replClient);
+ }
+
+ public JavaREPLLanguageConsole(Project project, String title, Language language, boolean initComponents, JavaREPLClient replClient) {
+ this(project, title, new LightVirtualFile(title, language, ""), initComponents, replClient);
+ }
+
+ public JavaREPLLanguageConsole(Project project, String title, LightVirtualFile lightFile, boolean initComponents, JavaREPLClient replClient) {
+ myProject = project;
+ myTitle = title;
+ myVirtualFile = lightFile;
+ this.replClient = replClient;
+ EditorFactory editorFactory = EditorFactory.getInstance();
+ myHistoryFile = new LightVirtualFile(getTitle() + ".history.txt", FileTypes.PLAIN_TEXT, "");
+ myEditorDocument = FileDocumentManager.getInstance().getDocument(lightFile);
+ assert myEditorDocument != null;
+ myConsoleEditor = (EditorEx) editorFactory.createEditor(myEditorDocument, myProject);
+ myConsoleEditor.addFocusListener(myFocusListener);
+ myCurrentEditor = myConsoleEditor;
+ myHistoryViewer = (EditorEx) editorFactory.createViewer(((EditorFactoryImpl) editorFactory).createDocument(true), myProject);
+ myUpdateQueue = new MergingUpdateQueue("ConsoleUpdateQueue", 300, true, null);
+ Disposer.register(this, myUpdateQueue);
+
+ // action shortcuts are not yet registered
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ installEditorFactoryListener();
+ }
+ });
+
+ if (initComponents) {
+ initComponents();
+ }
+ }
+
+ public void initComponents() {
+ final EditorColorsScheme colorsScheme = myConsoleEditor.getColorsScheme();
+ final DelegateColorScheme scheme = new DelegateColorScheme(colorsScheme) {
+ @NotNull
+ @Override
+ public Color getDefaultBackground() {
+ final Color color = getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY);
+ return color == null ? super.getDefaultBackground() : color;
+ }
+ };
+ myConsoleEditor.setColorsScheme(scheme);
+ myHistoryViewer.setColorsScheme(scheme);
+ myPanel.add(myHistoryViewer.getComponent());
+ myPanel.add(myConsoleEditor.getComponent());
+ setupComponents();
+ DataManager.registerDataProvider(myPanel, new TypeSafeDataProviderAdapter(this));
+
+ myHistoryViewer.getComponent().addComponentListener(new ComponentAdapter() {
+ public void componentResized(ComponentEvent e) {
+ if (myForceScrollToEnd.getAndSet(false)) {
+ final JScrollBar scrollBar = myHistoryViewer.getScrollPane().getVerticalScrollBar();
+ scrollBar.setValue(scrollBar.getMaximum());
+ }
+ }
+
+ public void componentShown(ComponentEvent e) {
+ componentResized(e);
+ }
+ });
+ setPromptInner(myPrompt);
+ }
+
+ public void setConsoleEditorEnabled(boolean consoleEditorEnabled) {
+ if (isConsoleEditorEnabled() == consoleEditorEnabled) return;
+ final FileEditorManagerEx fileManager = FileEditorManagerEx.getInstanceEx(getProject());
+ if (consoleEditorEnabled) {
+ fileManager.closeFile(myVirtualFile);
+ myPanel.removeAll();
+ myPanel.add(myHistoryViewer.getComponent());
+ myPanel.add(myConsoleEditor.getComponent());
+
+ myHistoryViewer.setHorizontalScrollbarVisible(false);
+ myCurrentEditor = myConsoleEditor;
+ } else {
+ myPanel.removeAll();
+ myPanel.add(myHistoryViewer.getComponent(), BorderLayout.CENTER);
+ myHistoryViewer.setHorizontalScrollbarVisible(true);
+ }
+ }
+
+ public void setShowSeparatorLine(boolean showSeparatorLine) {
+ myShowSeparatorLine = showSeparatorLine;
+ }
+
+ private void setupComponents() {
+ setupEditorDefault(myConsoleEditor);
+ setupEditorDefault(myHistoryViewer);
+ myConsoleEditor.addEditorMouseListener(EditorActionUtil.createEditorPopupHandler(IdeActions.GROUP_CONSOLE_EDITOR_POPUP));
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ if (SEPARATOR_THICKNESS > 0 && myShowSeparatorLine) {
+ myHistoryViewer.getComponent().setBorder(new SideBorder(Color.LIGHT_GRAY, SideBorder.BOTTOM));
+ }
+ myHistoryViewer.getComponent().setMinimumSize(new Dimension(0, 0));
+ myHistoryViewer.getComponent().setPreferredSize(new Dimension(0, 0));
+ myConsoleEditor.getSettings().setAdditionalLinesCount(2);
+ myConsoleEditor.setHighlighter(EditorHighlighterFactory.getInstance().createEditorHighlighter(myProject, myVirtualFile));
+ myHistoryViewer.setCaretEnabled(false);
+ myConsoleEditor.setHorizontalScrollbarVisible(true);
+ final VisibleAreaListener areaListener = new VisibleAreaListener() {
+ public void visibleAreaChanged(VisibleAreaEvent e) {
+ final int offset = myConsoleEditor.getScrollingModel().getHorizontalScrollOffset();
+ final ScrollingModel model = myHistoryViewer.getScrollingModel();
+ final int historyOffset = model.getHorizontalScrollOffset();
+ if (historyOffset != offset) {
+ try {
+ model.disableAnimation();
+ model.scrollHorizontally(offset);
+ } finally {
+ model.enableAnimation();
+ }
+ }
+ }
+ };
+ myConsoleEditor.getScrollingModel().addVisibleAreaListener(areaListener);
+ final DocumentAdapter docListener = new DocumentAdapter() {
+ @Override
+ public void documentChanged(final DocumentEvent e) {
+ updateCodeCompletion();
+ queueUiUpdate(false);
+ }
+ };
+ myEditorDocument.addDocumentListener(docListener, this);
+ myHistoryViewer.getDocument().addDocumentListener(docListener, this);
+
+ myHistoryViewer.getContentComponent().addKeyListener(new KeyAdapter() {
+ public void keyTyped(KeyEvent event) {
+ if (isConsoleEditorEnabled() && UIUtil.isReallyTypedEvent(event)) {
+ myConsoleEditor.getContentComponent().requestFocus();
+ myConsoleEditor.processKeyTyped(event);
+ }
+ }
+ });
+ for (AnAction action : createActions()) {
+ action.registerCustomShortcutSet(action.getShortcutSet(), myConsoleEditor.getComponent());
+ }
+ EmptyAction.registerActionShortcuts(myHistoryViewer.getComponent(), myConsoleEditor.getComponent());
+ }
+
+ public boolean isConsoleEditorEnabled() {
+ return myPanel.getComponentCount() > 1;
+ }
+
+ protected AnAction[] createActions() {
+ return AnAction.EMPTY_ARRAY;
+ }
+
+ public void addTextToCurrentEditor(final String text) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ getCurrentEditor().getDocument().insertString(0, text);
+ }
+ });
+ queueUiUpdate(true);
+ }
+
+ private static void setupEditorDefault(EditorEx editor) {
+ ConsoleViewUtil.setupConsoleEditor(editor, false, false);
+ editor.getContentComponent().setFocusCycleRoot(false);
+ editor.setHorizontalScrollbarVisible(false);
+ editor.setVerticalScrollbarVisible(true);
+ editor.setBorder(null);
+
+ final EditorSettings editorSettings = editor.getSettings();
+ editorSettings.setAdditionalLinesCount(0);
+ editorSettings.setAdditionalColumnsCount(1);
+ editorSettings.setRightMarginShown(false);
+ }
+
+ public void setUiUpdateRunnable(Runnable uiUpdateRunnable) {
+ assert myUiUpdateRunnable == null : "can be set only once";
+ myUiUpdateRunnable = uiUpdateRunnable;
+ }
+
+ public void flushAllUiUpdates() {
+ myUpdateQueue.flush();
+ }
+
+ public LightVirtualFile getHistoryFile() {
+ return myHistoryFile;
+ }
+
+ @Nullable
+ public String getPrompt() {
+ return myPrompt;
+ }
+
+ public void setPrompt(@Nullable String prompt) {
+ // always add space to the prompt otherwise it may look ugly
+ myPrompt = prompt != null && !prompt.endsWith(" ") ? prompt + " " : prompt;
+ setPromptInner(myPrompt);
+ }
+
+ private void setPromptInner(final String prompt) {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ myConsoleEditor.setPrefixTextAndAttributes(prompt, ConsoleViewContentType.USER_INPUT.getAttributes());
+ if (myPanel.isVisible()) {
+ queueUiUpdate(false);
+ }
+ }
+ });
+ }
+
+ public void setEditable(boolean editable) {
+ myConsoleEditor.setRendererMode(!editable);
+ setPromptInner(editable ? myPrompt : "");
+ }
+
+ public boolean isEditable() {
+ return !myConsoleEditor.isRendererMode();
+ }
+
+ public PsiFile getFile() {
+ return myFile;
+ }
+
+ public VirtualFile getVirtualFile() {
+ return myVirtualFile;
+ }
+
+ public EditorEx getHistoryViewer() {
+ return myHistoryViewer;
+ }
+
+ public Document getEditorDocument() {
+ return myEditorDocument;
+ }
+
+ public EditorEx getConsoleEditor() {
+ return myConsoleEditor;
+ }
+
+ public Project getProject() {
+ return myProject;
+ }
+
+ public String getTitle() {
+ return myTitle;
+ }
+
+ public void setTitle(String title) {
+ this.myTitle = title;
+ }
+
+ public void addToHistory(final String text, final TextAttributes attributes) {
+ printToHistory(text, attributes);
+ }
+
+ public void printToHistory(@NotNull final List<Pair<String, TextAttributes>> attributedText) {
+ ApplicationManager.getApplication().assertIsDispatchThread();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("printToHistory(): " + attributedText.size());
+ }
+ final boolean scrollToEnd = shouldScrollHistoryToEnd();
+ final int[] offsets = new int[attributedText.size() + 1];
+ int i = 0;
+ offsets[i] = 0;
+ final StringBuilder sb = new StringBuilder();
+ for (final Pair<String, TextAttributes> pair : attributedText) {
+ final String str = StringUtil.convertLineSeparators(pair.getFirst());
+ final int lastOffset = offsets[i];
+ offsets[++i] = lastOffset + str.length();
+ sb.append(str);
+ }
+ LOG.debug("printToHistory(): text processed");
+ final Document history = myHistoryViewer.getDocument();
+ final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
+ final int oldHistoryLength = history.getTextLength();
+ appendToHistoryDocument(history, sb.toString());
+ assert (oldHistoryLength + offsets[i]) == history.getTextLength()
+ : "Last offset - " + offsets[i] + " history length: old " + oldHistoryLength + ", new - " + history.getTextLength();
+ LOG.debug("printToHistory(): text added");
+ i = 0;
+ for (final Pair<String, TextAttributes> pair : attributedText) {
+ markupModel.addRangeHighlighter(oldHistoryLength + offsets[i],
+ oldHistoryLength + offsets[i + 1],
+ HighlighterLayer.SYNTAX,
+ pair.getSecond(),
+ HighlighterTargetArea.EXACT_RANGE);
+ ++i;
+ }
+ LOG.debug("printToHistory(): markup added");
+ if (scrollToEnd) {
+ scrollHistoryToEnd();
+ }
+ queueUiUpdate(scrollToEnd);
+ LOG.debug("printToHistory(): completed");
+ }
+
+ public void printToHistory(String text, final TextAttributes attributes) {
+ ApplicationManager.getApplication().assertIsDispatchThread();
+ text = StringUtil.convertLineSeparators(text);
+ final boolean scrollToEnd = shouldScrollHistoryToEnd();
+ final Document history = myHistoryViewer.getDocument();
+ final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
+ final int offset = history.getTextLength();
+ appendToHistoryDocument(history, text);
+ markupModel.addRangeHighlighter(offset,
+ history.getTextLength(),
+ HighlighterLayer.SYNTAX,
+ attributes,
+ HighlighterTargetArea.EXACT_RANGE);
+ if (scrollToEnd) {
+ scrollHistoryToEnd();
+ }
+ queueUiUpdate(scrollToEnd);
+ }
+
+ public String addCurrentToHistory(final TextRange textRange, final boolean erase, final boolean preserveMarkup) {
+ return addToHistoryInner(textRange, myConsoleEditor, erase, preserveMarkup);
+ }
+
+ public String addToHistory(final TextRange textRange, final EditorEx editor, final boolean preserveMarkup) {
+ return addToHistoryInner(textRange, editor, false, preserveMarkup);
+ }
+
+ protected String addToHistoryInner(final TextRange textRange,
+ final EditorEx editor,
+ final boolean erase,
+ final boolean preserveMarkup) {
+ final Ref<String> ref = Ref.create("");
+ final Runnable action = new Runnable() {
+ public void run() {
+ ref.set(addTextRangeToHistory(textRange, editor, preserveMarkup));
+ if (erase) {
+ editor.getDocument().deleteString(textRange.getStartOffset(), textRange.getEndOffset());
+ }
+ }
+ };
+ if (erase) {
+ ApplicationManager.getApplication().runWriteAction(action);
+ } else {
+ ApplicationManager.getApplication().runReadAction(action);
+ }
+ // always scroll to end on user input
+ scrollHistoryToEnd();
+ queueUiUpdate(true);
+ return ref.get();
+ }
+
+ public boolean shouldScrollHistoryToEnd() {
+ final Rectangle visibleArea = myHistoryViewer.getScrollingModel().getVisibleArea();
+ final Dimension contentSize = myHistoryViewer.getContentSize();
+ return contentSize.getHeight() - visibleArea.getMaxY() < 2 * myHistoryViewer.getLineHeight();
+ }
+
+ private void scrollHistoryToEnd() {
+ final int lineCount = myHistoryViewer.getDocument().getLineCount();
+ if (lineCount == 0) return;
+ myHistoryViewer.getCaretModel().moveToOffset(myHistoryViewer.getDocument().getLineStartOffset(lineCount - 1), false);
+ myHistoryViewer.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
+ }
+
+ protected String addTextRangeToHistory(TextRange textRange, final EditorEx consoleEditor, boolean preserveMarkup) {
+ final Document history = myHistoryViewer.getDocument();
+ final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
+ if (myPrompt != null) {
+ appendToHistoryDocument(history, myPrompt);
+ }
+
+ final int localStartOffset = textRange.getStartOffset();
+ String text;
+ EditorHighlighter highlighter;
+ if (consoleEditor instanceof EditorWindow) {
+ EditorWindow editorWindow = (EditorWindow) consoleEditor;
+ EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
+ PsiFile file = editorWindow.getInjectedFile();
+ final VirtualFile virtualFile = file.getVirtualFile();
+ assert virtualFile != null;
+ highlighter = HighlighterFactory.createHighlighter(virtualFile, scheme, getProject());
+ String fullText = InjectedLanguageUtil.getUnescapedText(file, null, null);
+ highlighter.setText(fullText);
+ text = textRange.substring(fullText);
+ } else {
+ text = consoleEditor.getDocument().getText(textRange);
+ highlighter = consoleEditor.getHighlighter();
+ }
+ //offset can be changed after text trimming after insert due to buffer constraints
+ appendToHistoryDocument(history, text);
+ int offset = history.getTextLength() - text.length();
+
+ final HighlighterIterator iterator = highlighter.createIterator(localStartOffset);
+ final int localEndOffset = textRange.getEndOffset();
+ while (!iterator.atEnd()) {
+ final int itStart = iterator.getStart();
+ if (itStart > localEndOffset) break;
+ final int itEnd = iterator.getEnd();
+ if (itEnd >= localStartOffset) {
+ final int start = Math.max(itStart, localStartOffset) - localStartOffset + offset;
+ final int end = Math.min(itEnd, localEndOffset) - localStartOffset + offset;
+ markupModel.addRangeHighlighter(start, end, HighlighterLayer.SYNTAX, iterator.getTextAttributes(),
+ HighlighterTargetArea.EXACT_RANGE);
+ }
+ iterator.advance();
+ }
+ if (!text.endsWith("\n")) {
+ appendToHistoryDocument(history, "\n");
+ }
+ return text;
+ }
+
+ protected void appendToHistoryDocument(@NotNull Document history, @NotNull String text) {
+ history.insertString(history.getTextLength(), text);
+ }
+
+ public JComponent getComponent() {
+ return myPanel;
+ }
+
+ public void queueUiUpdate(final boolean forceScrollToEnd) {
+ myForceScrollToEnd.compareAndSet(false, forceScrollToEnd);
+ myUpdateQueue.queue(new Update("UpdateUi") {
+ public void run() {
+ if (Disposer.isDisposed(JavaREPLLanguageConsole.this)) return;
+ if (isConsoleEditorEnabled()) {
+ myPanel.revalidate();
+ myPanel.repaint();
+ }
+ if (myUiUpdateRunnable != null) {
+ ApplicationManager.getApplication().runReadAction(myUiUpdateRunnable);
+ }
+ }
+ });
+ }
+
+ public void dispose() {
+ final EditorFactory editorFactory = EditorFactory.getInstance();
+ editorFactory.releaseEditor(myConsoleEditor);
+ editorFactory.releaseEditor(myHistoryViewer);
+
+ final FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
+ final boolean isOpen = editorManager.isFileOpen(myVirtualFile);
+ if (isOpen) {
+ editorManager.closeFile(myVirtualFile);
+ }
+ }
+
+ public void calcData(DataKey key, DataSink sink) {
+ if (OpenFileDescriptor.NAVIGATE_IN_EDITOR == key) {
+ sink.put(OpenFileDescriptor.NAVIGATE_IN_EDITOR, myConsoleEditor);
+ return;
+ } else if (getProject().isInitialized()) {
+ FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
+ final Object o = ((FileEditorManagerImpl) editorManager).getData(key.getName(), myConsoleEditor, myVirtualFile);
+ sink.put(key, o);
+ }
+ }
+
+ private void installEditorFactoryListener() {
+ final FileEditorManagerAdapter fileEditorListener = new FileEditorManagerAdapter() {
+ @Override
+ public void fileOpened(FileEditorManager source, VirtualFile file) {
+ if (!Comparing.equal(file, myVirtualFile) || myConsoleEditor == null) return;
+ Editor selectedTextEditor = source.getSelectedTextEditor();
+ for (FileEditor fileEditor : source.getAllEditors(file)) {
+ if (!(fileEditor instanceof TextEditor)) continue;
+ final EditorEx editor = (EditorEx) ((TextEditor) fileEditor).getEditor();
+ editor.addFocusListener(myFocusListener);
+ if (selectedTextEditor == editor) { // already focused
+ myCurrentEditor = editor;
+ }
+ EmptyAction.registerActionShortcuts(editor.getComponent(), myConsoleEditor.getComponent());
+ editor.getCaretModel().addCaretListener(new CaretListener() {
+ public void caretPositionChanged(CaretEvent e) {
+ queueUiUpdate(false);
+ }
+ });
+ }
+ queueUiUpdate(false);
+ }
+
+ @Override
+ public void fileClosed(FileEditorManager source, VirtualFile file) {
+ if (!Comparing.equal(file, myVirtualFile)) return;
+ if (myUiUpdateRunnable != null && !Boolean.TRUE.equals(file.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) {
+ if (myCurrentEditor != null && myCurrentEditor.isDisposed()) myCurrentEditor = null;
+ ApplicationManager.getApplication().runReadAction(myUiUpdateRunnable);
+ }
+ }
+ };
+ myProject.getMessageBus().connect(this).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, fileEditorListener);
+ FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
+ if (editorManager.isFileOpen(myVirtualFile)) {
+ fileEditorListener.fileOpened(editorManager, myVirtualFile);
+ }
+ }
+
+ public Editor getCurrentEditor() {
+ return myCurrentEditor == null ? myConsoleEditor : myCurrentEditor;
+ }
+
+ public void setLanguage(Language language) {
+ myVirtualFile.setLanguage(language);
+ // setViewProvider() call is required otherwise psiFile will stay the same!
+ FileManager fileManager = ((PsiManagerEx) PsiManager.getInstance(myProject)).getFileManager();
+ fileManager.setViewProvider(myVirtualFile, fileManager.createFileViewProvider(myVirtualFile, true));
+ updateCodeCompletion();
+ }
+
+ public void setInputText(final String query) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ myConsoleEditor.getDocument().setText(query);
+ }
+ });
+ }
+
+ public static void printToConsole(
+ @NotNull final JavaREPLLanguageConsole console,
+ @NotNull final ConsoleViewContentType mainType,
+ @NotNull final List<Pair<String, ConsoleViewContentType>> textToPrint) {
+ final List<Pair<String, TextAttributes>> attributedText = ContainerUtil.map(
+ textToPrint,
+ new Function<Pair<String, ConsoleViewContentType>, Pair<String, TextAttributes>>() {
+ @Override
+ public Pair<String, TextAttributes> fun(Pair<String, ConsoleViewContentType> input) {
+ final TextAttributes mainAttributes = mainType.getAttributes();
+ final TextAttributes attributes;
+ if (input.getSecond() == null) {
+ attributes = mainAttributes;
+ } else {
+ attributes = input.getSecond().getAttributes().clone();
+ attributes.setBackgroundColor(mainAttributes.getBackgroundColor());
+ }
+ return Pair.create(input.getFirst(), attributes);
+ }
+ }
+ );
+
+ Application application = ApplicationManager.getApplication();
+ if (application.isDispatchThread()) {
+ console.printToHistory(attributedText);
+ } else {
+ application.invokeLater(new Runnable() {
+ public void run() {
+ console.printToHistory(attributedText);
+ }
+ }, ModalityState.stateForComponent(console.getComponent()));
+ }
+ }
+
+ public static void printToConsole(@NotNull final JavaREPLLanguageConsole console,
+ @NotNull final String string,
+ @NotNull final ConsoleViewContentType mainType,
+ @Nullable ConsoleViewContentType additionalType) {
+ final TextAttributes mainAttributes = mainType.getAttributes();
+ final TextAttributes attributes;
+ if (additionalType == null) {
+ attributes = mainAttributes;
+ } else {
+ attributes = additionalType.getAttributes().clone();
+ attributes.setBackgroundColor(mainAttributes.getBackgroundColor());
+ }
+
+ Application application = ApplicationManager.getApplication();
+ if (application.isDispatchThread()) {
+ console.printToHistory(string, attributes);
+ } else {
+ application.invokeLater(new Runnable() {
+ public void run() {
+ console.printToHistory(string, attributes);
+ }
+ }, ModalityState.stateForComponent(console.getComponent()));
+ }
+ }
+
+ public void updateCodeCompletion() {
+ try {
+ ExpressionTemplate template = replClient.template(myEditorDocument.getText());
+ PsiFile contextFile = PsiFileFactory.getInstance(myProject).createFileFromText(randomIdentifier("Template") + ".java", JavaLanguage.INSTANCE, template.template());
+ PsiCodeFragment consoleFile = JavaCodeFragmentFactory.getInstance(myProject).createCodeBlockCodeFragment(myEditorDocument.getText(), contextFile.findElementAt(contextFile.getText().indexOf(template.token())), false);
+
+ myVirtualFile = (LightVirtualFile) consoleFile.getViewProvider().getVirtualFile();
+ myFile = ObjectUtils.assertNotNull(PsiManager.getInstance(myProject).findFile(myVirtualFile));
+ PsiDocumentManagerImpl.cachePsi(myEditorDocument, myFile);
+ } catch (Exception e) {
+ // Ignore completion if failed
+ }
+ }
+
+ private class MyLayout extends AbstractLayoutManager {
+ @Override
+ public Dimension preferredLayoutSize(final Container parent) {
+ return new Dimension(0, 0);
+ }
+
+ @Override
+ public void layoutContainer(final Container parent) {
+ final int componentCount = parent.getComponentCount();
+ if (componentCount == 0) return;
+ final EditorEx history = myHistoryViewer;
+ final EditorEx editor = componentCount == 2 ? myConsoleEditor : null;
+
+ if (editor == null) {
+ parent.getComponent(0).setBounds(parent.getBounds());
+ return;
+ }
+
+ final Dimension panelSize = parent.getSize();
+ if (panelSize.getHeight() <= 0) return;
+ final Dimension historySize = history.getContentSize();
+ final Dimension editorSize = editor.getContentSize();
+ final Dimension newEditorSize = new Dimension();
+
+ // deal with width
+ final int width = Math.max(editorSize.width, historySize.width);
+ newEditorSize.width = width + editor.getScrollPane().getHorizontalScrollBar().getHeight();
+ history.getSoftWrapModel().forceAdditionalColumnsUsage();
+ editor.getSettings().setAdditionalColumnsCount(2 + (width - editorSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, editor));
+ history.getSettings().setAdditionalColumnsCount(2 + (width - historySize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, history));
+
+ // deal with height
+ if (historySize.width == 0) historySize.height = 0;
+ final int minHistorySize = historySize.height > 0 ? 2 * history.getLineHeight() + (myShowSeparatorLine ? SEPARATOR_THICKNESS : 0) : 0;
+ final int minEditorSize = editor.isViewer() ? 0 : editor.getLineHeight();
+ final int editorPreferred = editor.isViewer() ? 0 : Math.max(minEditorSize, editorSize.height);
+ final int historyPreferred = Math.max(minHistorySize, historySize.height);
+ if (panelSize.height < minEditorSize) {
+ newEditorSize.height = panelSize.height;
+ } else if (panelSize.height < editorPreferred) {
+ newEditorSize.height = panelSize.height - minHistorySize;
+ } else if (panelSize.height < editorPreferred + historyPreferred) {
+ newEditorSize.height = editorPreferred;
+ } else {
+ newEditorSize.height = editorPreferred == 0 ? 0 : panelSize.height - historyPreferred;
+ }
+ final Dimension newHistorySize = new Dimension(width, panelSize.height - newEditorSize.height);
+
+ // apply
+ editor.getComponent().setBounds(0, newHistorySize.height, panelSize.width, newEditorSize.height);
+ myForceScrollToEnd.compareAndSet(false, shouldScrollHistoryToEnd());
+ history.getComponent().setBounds(0, 0, panelSize.width, newHistorySize.height);
+ }
+ }
+}
View
65 intellij-plugin/src/javarepl/plugin/JavaREPLLanguageConsoleView.java
@@ -0,0 +1,65 @@
+package javarepl.plugin;
+
+/*
+ * Copied from IntelliJ 12 sourcecode and heavily modified
+ *
+ * Copyright 2000-2010 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.
+ */
+
+import com.intellij.execution.impl.ConsoleViewImpl;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.util.Disposer;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * @author Gregory.Shrago
+ */
+public class JavaREPLLanguageConsoleView extends ConsoleViewImpl {
+ @NotNull
+ protected JavaREPLLanguageConsole myConsole;
+
+ public JavaREPLLanguageConsoleView(@NotNull final JavaREPLLanguageConsole console) {
+ super(console.getProject(), true);
+ myConsole = console;
+ Disposer.register(this, myConsole);
+ Disposer.register(getProject(), this);
+ }
+
+ @NotNull
+ public JavaREPLLanguageConsole getConsole() {
+ return myConsole;
+ }
+
+ @Override
+ protected EditorEx createRealEditor() {
+ return myConsole.getHistoryViewer();
+ }
+
+ @Override
+ protected void disposeEditor() {
+ }
+
+ @Override
+ protected JComponent createCenterComponent() {
+ return myConsole.getComponent();
+ }
+
+ @Override
+ public JComponent getPreferredFocusableComponent() {
+ return myConsole.getConsoleEditor().getContentComponent();
+ }
+}
View
BIN  lib/manual/xpp3-1.1.4-min.jar
Binary file not shown
View
BIN  lib/manual/xstream-1.4.3.jar
Binary file not shown
View
16 src/javarepl/Main.java
@@ -1,6 +1,10 @@
package javarepl;
-import com.googlecode.totallylazy.*;
+import com.googlecode.totallylazy.Function1;
+import com.googlecode.totallylazy.Option;
+import com.googlecode.totallylazy.Predicates;
+import com.googlecode.totallylazy.Sequence;
+import com.googlecode.totallylazy.predicates.LogicalPredicate;
import javarepl.completion.CodeCompleter;
import javarepl.completion.CompletionResult;
import javarepl.completion.SimpleConsoleCompleter;
@@ -97,12 +101,14 @@ public static void main(String... args) throws Exception {
private static ConsoleLogger systemStreamsLogger(String[] args) {
ConsoleLogger logger = new ConsoleLogger(outStream, errStream);
- Predicate<String> ignoredLogs = ignoreConsole(args)
- ? startsWith("POST /").or(startsWith("GET /")).or(startsWith("Listening on http://"))
+ LogicalPredicate<String> defaultIgnore = startsWith("POST /").or(startsWith("GET /"));
+
+ LogicalPredicate<String> ignoredLogs = ignoreConsole(args)
+ ? startsWith("Listening on http://")
: Predicates.<String>never();
- System.setOut(new ConsoleLoggerPrintStream(INFO, ignoredLogs, logger));
- System.setErr(new ConsoleLoggerPrintStream(ERROR, ignoredLogs, logger));
+ System.setOut(new ConsoleLoggerPrintStream(INFO, defaultIgnore.or(ignoredLogs), logger));
+ System.setErr(new ConsoleLoggerPrintStream(ERROR, defaultIgnore.or(ignoredLogs), logger));
return logger;
}
View
19 src/javarepl/client/ExpressionTemplate.java
@@ -0,0 +1,19 @@
+package javarepl.client;
+
+public final class ExpressionTemplate {
+ private final String template;
+ private final String token;
+
+ public ExpressionTemplate(String template, String token) {
+ this.template = template;
+ this.token = token;
+ }
+
+ public String template() {
+ return template;
+ }
+
+ public String token() {
+ return token;
+ }
+}
View
15 src/javarepl/console/rest/RestConsoleResource.java
@@ -7,11 +7,16 @@
import com.googlecode.utterlyidle.Response;
import com.googlecode.utterlyidle.Responses;
import com.googlecode.utterlyidle.annotations.*;
+import javarepl.Evaluator;
import javarepl.console.ConsoleLog;
import javarepl.console.ConsoleResult;
+import javarepl.expressions.Expression;
import static com.googlecode.funclate.Model.persistent.model;
+import static javarepl.Utils.randomIdentifier;
import static javarepl.console.ConsoleResult.emptyResult;
+import static javarepl.rendering.EvaluationClassRenderer.renderExpressionClass;
+import static javarepl.rendering.ExpressionTokenRenderer.EXPRESSION_TOKEN;
public class RestConsoleResource {
private final RestConsole console;
@@ -31,6 +36,16 @@ public Model execute(@FormParam("expression") String expr) {
}
@GET
+ @Path("template")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Model template(@QueryParam("expression") String expr) {
+ Evaluator evaluator = console.context().get(Evaluator.class);
+ Expression expression = evaluator.parseExpression(expr);
+ return model().add("template", renderExpressionClass(evaluator.context(), randomIdentifier("Evaluation"), expression))
+ .add("token", EXPRESSION_TOKEN);
+ }
+
+ @GET
@Path("")
public Response main() {
return Responses.seeOther("console.html");
View
2  src/javarepl/rendering/ExpressionTokenRenderer.java
@@ -8,7 +8,7 @@
import static javarepl.Utils.randomIdentifier;
public class ExpressionTokenRenderer {
- public static final String EXPRESSION_TOKEN = "%JAVAREPL_EXPR%";
+ public static final String EXPRESSION_TOKEN = "$JAVAREPL_EXPRESSION_TOKEN$";
@multimethod
public static String renderExpressionToken(Expression expression) {
Please sign in to comment.
Something went wrong with that request. Please try again.