Java tutorial
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.ObjectUtils; 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.JavaREPLClient; import javarepl.rendering.ExpressionTemplate; 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 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); } } }