crlf
authorunknown <Gregory.Shrago@.Labs.IntelliJ.Net>
Thu, 15 Oct 2009 14:40:07 +0000 (18:40 +0400)
committerunknown <Gregory.Shrago@.Labs.IntelliJ.Net>
Thu, 15 Oct 2009 14:40:07 +0000 (18:40 +0400)
platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java
platform/util/src/com/intellij/openapi/util/text/LineTokenizer.java

index 2d2056852f8018147b629d035a0c24467e0021f0..665873fb1979d4501c40bc33ed43bb7a5d407b38 100644 (file)
-/*\r
- * Copyright 2000-2009 JetBrains s.r.o.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.intellij.execution.impl;\r
-\r
-import com.intellij.codeInsight.navigation.IncrementalSearchHandler;\r
-import com.intellij.execution.ExecutionBundle;\r
-import com.intellij.execution.filters.*;\r
-import com.intellij.execution.process.ProcessHandler;\r
-import com.intellij.execution.ui.ConsoleView;\r
-import com.intellij.execution.ui.ConsoleViewContentType;\r
-import com.intellij.execution.ui.ObservableConsoleView;\r
-import com.intellij.ide.CommonActionsManager;\r
-import com.intellij.ide.DataAccessor;\r
-import com.intellij.ide.DataAccessors;\r
-import com.intellij.ide.OccurenceNavigator;\r
-import com.intellij.openapi.Disposable;\r
-import com.intellij.openapi.actionSystem.*;\r
-import com.intellij.openapi.application.ApplicationManager;\r
-import com.intellij.openapi.application.ModalityState;\r
-import com.intellij.openapi.command.CommandProcessor;\r
-import com.intellij.openapi.diagnostic.Logger;\r
-import com.intellij.openapi.diff.actions.DiffActions;\r
-import com.intellij.openapi.editor.*;\r
-import com.intellij.openapi.editor.actionSystem.*;\r
-import com.intellij.openapi.editor.colors.CodeInsightColors;\r
-import com.intellij.openapi.editor.colors.EditorColors;\r
-import com.intellij.openapi.editor.colors.EditorColorsManager;\r
-import com.intellij.openapi.editor.colors.EditorColorsScheme;\r
-import com.intellij.openapi.editor.event.*;\r
-import com.intellij.openapi.editor.ex.EditorEx;\r
-import com.intellij.openapi.editor.ex.MarkupModelEx;\r
-import com.intellij.openapi.editor.highlighter.EditorHighlighter;\r
-import com.intellij.openapi.editor.highlighter.HighlighterClient;\r
-import com.intellij.openapi.editor.highlighter.HighlighterIterator;\r
-import com.intellij.openapi.editor.markup.HighlighterLayer;\r
-import com.intellij.openapi.editor.markup.HighlighterTargetArea;\r
-import com.intellij.openapi.editor.markup.RangeHighlighter;\r
-import com.intellij.openapi.editor.markup.TextAttributes;\r
-import com.intellij.openapi.extensions.Extensions;\r
-import com.intellij.openapi.fileEditor.OpenFileDescriptor;\r
-import com.intellij.openapi.fileTypes.FileType;\r
-import com.intellij.openapi.ide.CopyPasteManager;\r
-import com.intellij.openapi.keymap.Keymap;\r
-import com.intellij.openapi.keymap.KeymapManager;\r
-import com.intellij.openapi.project.DumbAware;\r
-import com.intellij.openapi.project.Project;\r
-import com.intellij.openapi.util.Computable;\r
-import com.intellij.openapi.util.Condition;\r
-import com.intellij.openapi.util.Disposer;\r
-import com.intellij.openapi.util.Key;\r
-import com.intellij.openapi.util.text.LineTokenizer;\r
-import com.intellij.openapi.util.text.StringUtil;\r
-import com.intellij.pom.Navigatable;\r
-import com.intellij.psi.PsiDocumentManager;\r
-import com.intellij.psi.PsiFile;\r
-import com.intellij.psi.PsiFileFactory;\r
-import com.intellij.psi.tree.IElementType;\r
-import com.intellij.util.Alarm;\r
-import com.intellij.util.EditorPopupHandler;\r
-import com.intellij.util.LocalTimeCounter;\r
-import com.intellij.util.containers.HashMap;\r
-import org.jetbrains.annotations.NotNull;\r
-import org.jetbrains.annotations.TestOnly;\r
-\r
-import javax.swing.*;\r
-import java.awt.*;\r
-import java.awt.datatransfer.DataFlavor;\r
-import java.awt.datatransfer.Transferable;\r
-import java.awt.event.KeyEvent;\r
-import java.awt.event.KeyListener;\r
-import java.awt.event.MouseEvent;\r
-import java.awt.event.MouseMotionAdapter;\r
-import java.io.IOException;\r
-import java.util.*;\r
-import java.util.List;\r
-import java.util.concurrent.CopyOnWriteArraySet;\r
-\r
-public final class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableConsoleView, DataProvider, OccurenceNavigator {\r
-  private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.ConsoleViewImpl");\r
-\r
-  private static final int FLUSH_DELAY = 200; //TODO : make it an option\r
-\r
-  private static final Key<ConsoleViewImpl> CONSOLE_VIEW_IN_EDITOR_VIEW = Key.create("CONSOLE_VIEW_IN_EDITOR_VIEW");\r
-  static {\r
-    final EditorActionManager actionManager = EditorActionManager.getInstance();\r
-    final TypedAction typedAction = actionManager.getTypedAction();\r
-    typedAction.setupHandler(new MyTypedHandler(typedAction.getHandler()));\r
-  }\r
-\r
-  private final DisposedPsiManagerCheck myPsiDisposedCheck;\r
-  private ConsoleState myState = ConsoleState.NOT_STARTED;\r
-  private final int CYCLIC_BUFFER_SIZE = getCycleBufferSize();\r
-  private final boolean isViewer;\r
-  private Computable<ModalityState> myStateForUpdate;\r
-\r
-  private static int getCycleBufferSize() {\r
-    final String cycleBufferSizeProperty = System.getProperty("idea.cycle.buffer.size");\r
-    if (cycleBufferSizeProperty == null) return 1024 * 1024;\r
-    try {\r
-      return Integer.parseInt(cycleBufferSizeProperty) * 1024;\r
-    }\r
-    catch (NumberFormatException e) {\r
-      return 1024 * 1024;\r
-    }\r
-  }\r
-\r
-  private final boolean USE_CYCLIC_BUFFER = useCycleBuffer();\r
-\r
-  private static boolean useCycleBuffer() {\r
-    final String useCycleBufferProperty = System.getProperty("idea.cycle.buffer.size");\r
-    return useCycleBufferProperty == null || !"disabled".equalsIgnoreCase(useCycleBufferProperty);\r
-  }\r
-\r
-  private static final int HYPERLINK_LAYER = HighlighterLayer.SELECTION - 123;\r
-  private final Alarm mySpareTimeAlarm = new Alarm();\r
-\r
-  private final CopyOnWriteArraySet<ChangeListener> myListeners = new CopyOnWriteArraySet<ChangeListener>();\r
-  private final Set<ConsoleViewContentType> myDeferredTypes = new HashSet<ConsoleViewContentType>();\r
-  private final ArrayList<AnAction> customActions = new ArrayList<AnAction>();\r
-\r
-  @TestOnly\r
-  public Editor getEditor() {\r
-    return myEditor;\r
-  }\r
-\r
-  public void scrollToEnd() {\r
-    myEditor.getCaretModel().moveToOffset(myEditor.getDocument().getTextLength());\r
-  }\r
-\r
-  private static class TokenInfo{\r
-    private final ConsoleViewContentType contentType;\r
-    private int startOffset;\r
-    private int endOffset;\r
-    private final TextAttributes attributes;\r
-\r
-    private TokenInfo(final ConsoleViewContentType contentType, final int startOffset, final int endOffset) {\r
-      this.contentType = contentType;\r
-      this.startOffset = startOffset;\r
-      this.endOffset = endOffset;\r
-      attributes = contentType.getAttributes();\r
-    }\r
-  }\r
-\r
-  private final Project myProject;\r
-\r
-  private boolean myOutputPaused;\r
-\r
-  private Editor myEditor;\r
-\r
-  private final Object LOCK = new Object();\r
-\r
-  private int myContentSize;\r
-  private StringBuffer myDeferredOutput = new StringBuffer();\r
-  private StringBuffer myDeferredUserInput = new StringBuffer();\r
-\r
-  private ArrayList<TokenInfo> myTokens = new ArrayList<TokenInfo>();\r
-  private final Hyperlinks myHyperlinks = new Hyperlinks();\r
-\r
-  private String myHelpId;\r
-\r
-  private final Alarm myFlushAlarm = new Alarm();\r
-\r
-  private final Runnable myFlushDeferredRunnable = new Runnable() {\r
-    public void run() {\r
-      flushDeferredText();\r
-    }\r
-  };\r
-\r
-  private final CompositeFilter myMessageFilter;\r
-\r
-  private ArrayList<String> myHistory = new ArrayList<String>();\r
-  private int myHistorySize = 20;\r
-\r
-  private ArrayList<ConsoleInputListener> myConsoleInputListeners = new ArrayList<ConsoleInputListener>();\r
-\r
-  public void addConsoleUserInputLestener(ConsoleInputListener consoleInputListener) {\r
-    myConsoleInputListeners.add(consoleInputListener);\r
-  }\r
-\r
-  /**\r
-   * By default history works for one session. If\r
-   * you want to import previous session, set it up here.\r
-   * @param history where you can save history\r
-   */\r
-  public void importHistory(Collection<String> history) {\r
-    this.myHistory.clear();\r
-    this.myHistory.addAll(history);\r
-    while (this.myHistory.size() > myHistorySize) {\r
-      this.myHistory.remove(0);\r
-    }\r
-  }\r
-\r
-  public List<String> getHistory() {\r
-    return Collections.unmodifiableList(myHistory);\r
-  }\r
-\r
-  public void setHistorySize(int historySize) {\r
-    this.myHistorySize = historySize;\r
-  }\r
-\r
-  public int getHistorySize() {\r
-    return myHistorySize;\r
-  }\r
-\r
-  private FileType myFileType;\r
-\r
-  /**\r
-   * Use it for custom highlighting for user text.\r
-   * This will be highlighted as appropriate file to this file type.\r
-   * @param fileType according to which use highlighting\r
-   */\r
-  public void setFileType(FileType fileType) {\r
-    myFileType = fileType;\r
-  }\r
-\r
-  public ConsoleViewImpl(final Project project, boolean viewer) {\r
-    this(project, viewer, null);\r
-  }\r
-\r
-  public ConsoleViewImpl(final Project project, boolean viewer, FileType fileType) {\r
-    super(new BorderLayout());\r
-    isViewer = viewer;\r
-    myPsiDisposedCheck = new DisposedPsiManagerCheck(project);\r
-    myProject = project;\r
-    myFileType = fileType;\r
-\r
-    myMessageFilter = new CompositeFilter(project);\r
-    final ConsoleFilterProvider[] filterProviders = Extensions.getExtensions(ConsoleFilterProvider.FILTER_PROVIDERS);\r
-    for (ConsoleFilterProvider filterProvider : filterProviders) {\r
-      final Filter[] defaultFilters = filterProvider.getDefaultFilters(project);\r
-      for (Filter filter : defaultFilters) {\r
-        addMessageFilter(filter);\r
-      }\r
-    }\r
-\r
-    Disposer.register(project, this);\r
-  }\r
-\r
-  public void attachToProcess(final ProcessHandler processHandler){\r
-    myState = myState.attachTo(this, processHandler);\r
-  }\r
-\r
-  public void clear() {\r
-    assertIsDispatchThread();\r
-\r
-    final Document document;\r
-    synchronized(LOCK){\r
-      myContentSize = 0;\r
-      if (USE_CYCLIC_BUFFER) {\r
-        myDeferredOutput = new StringBuffer(Math.min(myDeferredOutput.length(), CYCLIC_BUFFER_SIZE));\r
-      }\r
-      else {\r
-        myDeferredOutput = new StringBuffer();\r
-      }\r
-      myDeferredTypes.clear();\r
-      myDeferredUserInput = new StringBuffer();\r
-      myHyperlinks.clear();\r
-      myTokens.clear();\r
-      if (myEditor == null) return;\r
-      myEditor.getMarkupModel().removeAllHighlighters();\r
-      document = myEditor.getDocument();\r
-    }\r
-    ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, myProject) {\r
-      public void run() {\r
-        CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {\r
-          public void run() {\r
-            document.deleteString(0, document.getTextLength());\r
-          }\r
-        }, null, DocCommandGroupId.noneGroupId(document));\r
-      }\r
-    });\r
-  }\r
-\r
-  public void scrollTo(final int offset) {\r
-    assertIsDispatchThread();\r
-    flushDeferredText();\r
-    if (myEditor == null) return;\r
-    int moveOffset = offset;\r
-    if (USE_CYCLIC_BUFFER && moveOffset >= myEditor.getDocument().getTextLength()) {\r
-      moveOffset = 0;\r
-    }\r
-    myEditor.getCaretModel().moveToOffset(moveOffset);\r
-    myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);\r
-  }\r
-\r
-  private static void assertIsDispatchThread() {\r
-    ApplicationManager.getApplication().assertIsDispatchThread();\r
-  }\r
-\r
-  public void setOutputPaused(final boolean value) {\r
-    myOutputPaused = value;\r
-    if (!value){\r
-      requestFlushImmediately();\r
-    }\r
-  }\r
-\r
-  public boolean isOutputPaused() {\r
-    return myOutputPaused;\r
-  }\r
-\r
-  public boolean hasDeferredOutput() {\r
-    synchronized(LOCK){\r
-      return myDeferredOutput.length() > 0;\r
-    }\r
-  }\r
-\r
-  public void performWhenNoDeferredOutput(final Runnable runnable) {\r
-    //Q: implement in another way without timer?\r
-    if (!hasDeferredOutput()){\r
-      runnable.run();\r
-    }\r
-    else{\r
-      mySpareTimeAlarm.addRequest(\r
-        new Runnable() {\r
-          public void run() {\r
-            performWhenNoDeferredOutput(runnable);\r
-          }\r
-        },\r
-        100\r
-      );\r
-    }\r
-  }\r
-\r
-  public JComponent getComponent() {\r
-    if (myEditor == null){\r
-      myEditor = createEditor();\r
-      requestFlushImmediately();\r
-      add(myEditor.getComponent(), BorderLayout.CENTER);\r
-\r
-      myEditor.getDocument().addDocumentListener(new DocumentAdapter() {\r
-        public void documentChanged(DocumentEvent e) {\r
-          if (e.getNewLength() == 0 && e.getOffset() == 0) {\r
-            // string has beeen removed from the beginning, move tokens down\r
-            synchronized (LOCK) {\r
-              int toRemoveLen = e.getOldLength();\r
-              int tIndex = findTokenInfoIndexByOffset(toRemoveLen);\r
-              ArrayList<TokenInfo> newTokens = new ArrayList<TokenInfo>(myTokens.subList(tIndex, myTokens.size()));\r
-              for (TokenInfo token : newTokens) {\r
-                token.startOffset -= toRemoveLen;\r
-                token.endOffset -= toRemoveLen;\r
-              }\r
-              if (!newTokens.isEmpty()) {\r
-                newTokens.get(0).startOffset = 0;\r
-              }\r
-              myContentSize -= Math.min(myContentSize, toRemoveLen);\r
-              myTokens = newTokens;\r
-            }\r
-          }\r
-        }\r
-      });\r
-    }\r
-    return this;\r
-  }\r
-\r
-  public void setModalityStateForUpdate(Computable<ModalityState> stateComputable) {\r
-    myStateForUpdate = stateComputable;\r
-  }\r
-\r
-\r
-\r
-  public void dispose(){\r
-    myState = myState.dispose();\r
-    if (myEditor != null){\r
-      myFlushAlarm.cancelAllRequests();\r
-      mySpareTimeAlarm.cancelAllRequests();\r
-      if (!myEditor.isDisposed()) {\r
-        EditorFactory.getInstance().releaseEditor(myEditor);\r
-      }\r
-      synchronized (LOCK) {\r
-        myDeferredOutput = new StringBuffer();\r
-      }\r
-      myEditor = null;\r
-    }\r
-  }\r
-\r
-  public void print(String s, final ConsoleViewContentType contentType) {\r
-    synchronized(LOCK){\r
-      myDeferredTypes.add(contentType);\r
-\r
-      s = StringUtil.convertLineSeparators(s);\r
-      myContentSize += s.length();\r
-      myDeferredOutput.append(s);\r
-      if (contentType == ConsoleViewContentType.USER_INPUT){\r
-        myDeferredUserInput.append(s);\r
-      }\r
-\r
-      boolean needNew = true;\r
-      if (!myTokens.isEmpty()){\r
-        final TokenInfo lastToken = myTokens.get(myTokens.size() - 1);\r
-        if (lastToken.contentType == contentType){\r
-          lastToken.endOffset = myContentSize; // optimization\r
-          needNew = false;\r
-        }\r
-      }\r
-      if (needNew){\r
-        myTokens.add(new TokenInfo(contentType, myContentSize - s.length(), myContentSize));\r
-      }\r
-\r
-      if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) {\r
-        if (contentType == ConsoleViewContentType.USER_INPUT) {\r
-          flushDeferredUserInput();\r
-        }\r
-      }\r
-      if (myFlushAlarm.getActiveRequestCount() == 0 && myEditor != null) {\r
-        final boolean shouldFlushNow = USE_CYCLIC_BUFFER && myDeferredOutput.length() > CYCLIC_BUFFER_SIZE;\r
-        myFlushAlarm.addRequest(myFlushDeferredRunnable, shouldFlushNow? 0 : FLUSH_DELAY, getStateForUpdate());\r
-      }\r
-    }\r
-  }\r
-\r
-  private ModalityState getStateForUpdate() {\r
-    return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(myEditor.getComponent());\r
-  }\r
-\r
-  private void requestFlushImmediately() {\r
-    if (myEditor != null) {\r
-      myFlushAlarm.addRequest(myFlushDeferredRunnable, 0, getStateForUpdate());\r
-    }\r
-  }\r
-\r
-  public int getContentSize() { return myContentSize; }\r
-\r
-  public boolean canPause() {\r
-    return true;\r
-  }\r
-\r
-  private void flushDeferredText() {\r
-    ApplicationManager.getApplication().assertIsDispatchThread();\r
-    if (myProject.isDisposed()) {\r
-      return;\r
-    }\r
-\r
-    final String text;\r
-    synchronized (LOCK) {\r
-      if (myOutputPaused) return;\r
-      if (myDeferredOutput.length() == 0) return;\r
-      if (myEditor == null) return;\r
-\r
-      text = myDeferredOutput.substring(0, myDeferredOutput.length());\r
-      if (USE_CYCLIC_BUFFER) {\r
-        myDeferredOutput = new StringBuffer(Math.min(myDeferredOutput.length(), CYCLIC_BUFFER_SIZE));\r
-      }\r
-      else {\r
-        myDeferredOutput.setLength(0);\r
-      }\r
-    }\r
-    final Document document = myEditor.getDocument();\r
-    final int oldLineCount = document.getLineCount();\r
-    final boolean isAtEndOfDocument = myEditor.getCaretModel().getOffset() == document.getTextLength();\r
-    boolean cycleUsed = USE_CYCLIC_BUFFER && document.getTextLength() + text.length() > CYCLIC_BUFFER_SIZE;\r
-    ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, myProject) {\r
-      public void run() {\r
-        CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {\r
-          public void run() {\r
-            document.insertString(document.getTextLength(), text);\r
-            synchronized (LOCK) {\r
-              fireChange();\r
-            }\r
-          }\r
-        }, null, DocCommandGroupId.noneGroupId(document));\r
-      }\r
-    });\r
-    myPsiDisposedCheck.performCheck();\r
-    final int newLineCount = document.getLineCount();\r
-    if (cycleUsed) {\r
-      final int lineCount = LineTokenizer.calcLineCount(text, true);\r
-      for (Iterator<RangeHighlighter> it = myHyperlinks.getRanges().keySet().iterator(); it.hasNext();) {\r
-        if (!it.next().isValid()) {\r
-          it.remove();\r
-        }\r
-      }\r
-      highlightHyperlinks(newLineCount >= lineCount + 1 ? newLineCount - lineCount - 1 : 0, newLineCount - 1);\r
-    } \r
-    else if (oldLineCount < newLineCount) {\r
-      highlightHyperlinks(oldLineCount - 1, newLineCount - 2);\r
-    }\r
-\r
-    if (isAtEndOfDocument) {\r
-      myEditor.getCaretModel().moveToOffset(myEditor.getDocument().getTextLength());\r
-      myEditor.getSelectionModel().removeSelection();\r
-      myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);\r
-    }\r
-  }\r
-\r
-  private void flushDeferredUserInput() {\r
-    if (myState.isRunning()){\r
-      final String text = myDeferredUserInput.substring(0, myDeferredUserInput.length());\r
-      final int index = Math.max(text.lastIndexOf('\n'), text.lastIndexOf('\r'));\r
-      if (index < 0) return;\r
-      try{\r
-        myState.sendUserInput(text.substring(0, index + 1));\r
-      }\r
-      catch(IOException e){\r
-        return;\r
-      }\r
-      myDeferredUserInput.setLength(0);\r
-      myDeferredUserInput.append(text.substring(index + 1));\r
-    }\r
-  }\r
-\r
-  public Object getData(final String dataId) {\r
-    if (DataConstants.NAVIGATABLE.equals(dataId)){\r
-      if (myEditor == null) {\r
-        return null;\r
-      }\r
-      final LogicalPosition pos = myEditor.getCaretModel().getLogicalPosition();\r
-      final HyperlinkInfo info = getHyperlinkInfoByLineAndCol(pos.line, pos.column);\r
-      final OpenFileDescriptor openFileDescriptor = info instanceof FileHyperlinkInfo ? ((FileHyperlinkInfo)info).getDescriptor() : null;\r
-      if (openFileDescriptor == null || !openFileDescriptor.getFile().isValid()) {\r
-        return null;\r
-      }\r
-      return openFileDescriptor;\r
-    }\r
-\r
-    if (DataConstants.EDITOR.equals(dataId)) {\r
-      return myEditor;\r
-    }\r
-    if (DataConstants.HELP_ID.equals(dataId)) {\r
-      return myHelpId;\r
-    }\r
-    return null;\r
-  }\r
-\r
-  public void setHelpId(final String helpId) {\r
-    myHelpId = helpId;\r
-  }\r
-\r
-  public void addMessageFilter(final Filter filter) {\r
-    myMessageFilter.addFilter(filter);\r
-  }\r
-\r
-  public void printHyperlink(final String hyperlinkText, final HyperlinkInfo info) {\r
-    if (myEditor == null) return;\r
-    print(hyperlinkText, ConsoleViewContentType.NORMAL_OUTPUT);\r
-    flushDeferredText();\r
-    final int textLength = myEditor.getDocument().getTextLength();\r
-    addHyperlink(textLength - hyperlinkText.length(), textLength, null, info, getHyperlinkAttributes());\r
-  }\r
-\r
-  private static TextAttributes getHyperlinkAttributes() {\r
-    return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES);\r
-  }\r
-\r
-  private static TextAttributes getFollowedHyperlinkAttributes() {\r
-    return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.FOLLOWED_HYPERLINK_ATTRIBUTES);\r
-  }\r
-  \r
-  private Editor createEditor() {\r
-    return ApplicationManager.getApplication().runReadAction(new Computable<Editor>() {\r
-      public Editor compute() {\r
-        return doCreateEditor();\r
-      }\r
-    });\r
-  }\r
-\r
-  private Editor doCreateEditor() {\r
-    final EditorFactory editorFactory = EditorFactory.getInstance();\r
-    final Document editorDocument = editorFactory.createDocument("");\r
-    editorDocument.addDocumentListener(new DocumentListener() {\r
-      public void beforeDocumentChange(DocumentEvent event) {\r
-      }\r
-\r
-      public void documentChanged(DocumentEvent event) {\r
-        if (myFileType != null) {\r
-          highlightUserTokens();\r
-        }\r
-      }\r
-    });\r
-\r
-    final int bufferSize = USE_CYCLIC_BUFFER ? CYCLIC_BUFFER_SIZE : 0;\r
-    editorDocument.setCyclicBufferSize(bufferSize);\r
-\r
-    final EditorEx editor = (EditorEx) editorFactory.createViewer(editorDocument,myProject);\r
-    final EditorHighlighter highlighter = new MyHighlighter();\r
-    editor.setHighlighter(highlighter);\r
-    editor.putUserData(CONSOLE_VIEW_IN_EDITOR_VIEW, this);\r
-\r
-    final EditorSettings editorSettings = editor.getSettings();\r
-    editorSettings.setLineMarkerAreaShown(false);\r
-    editorSettings.setLineNumbersShown(false);\r
-    editorSettings.setFoldingOutlineShown(false);\r
-    editorSettings.setAdditionalPageAtBottom(false);\r
-    editorSettings.setAdditionalColumnsCount(0);\r
-    editorSettings.setAdditionalLinesCount(0);\r
-\r
-    final EditorColorsScheme scheme = editor.getColorsScheme();\r
-    editor.setBackgroundColor(scheme.getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY));\r
-    scheme.setColor(EditorColors.CARET_ROW_COLOR, null);\r
-    scheme.setColor(EditorColors.RIGHT_MARGIN_COLOR, null);\r
-\r
-    editor.addEditorMouseListener(new EditorPopupHandler(){\r
-      public void invokePopup(final EditorMouseEvent event) {\r
-        final MouseEvent mouseEvent = event.getMouseEvent();\r
-        popupInvoked(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());\r
-      }\r
-    });\r
-\r
-    editor.addEditorMouseListener(\r
-      new EditorMouseAdapter(){\r
-        public void mouseReleased(final EditorMouseEvent e){\r
-          final MouseEvent mouseEvent = e.getMouseEvent();\r
-          if (!mouseEvent.isPopupTrigger()){\r
-            navigate(e);\r
-          }\r
-        }\r
-      }\r
-    );\r
-\r
-    editor.getContentComponent().addMouseMotionListener(\r
-      new MouseMotionAdapter(){\r
-        public void mouseMoved(final MouseEvent e){\r
-          final HyperlinkInfo info = getHyperlinkInfoByPoint(e.getPoint());\r
-          if (info != null){\r
-            editor.getContentComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));\r
-          }\r
-          else{\r
-            editor.getContentComponent().setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));\r
-          }\r
-        }\r
-      }\r
-    );\r
-\r
-    final ConsoleViewImpl consoleView = this;\r
-    editor.getContentComponent().addKeyListener(new KeyListener() {\r
-      private int historyPosition = myHistory.size();\r
-\r
-      public void keyTyped(KeyEvent e) {\r
-\r
-      }\r
-\r
-      public void keyPressed(KeyEvent e) {\r
-      }\r
-\r
-      public void keyReleased(KeyEvent e) {\r
-        if (e.isAltDown() && !e.isControlDown() && !e.isMetaDown() && !e.isShiftDown()) {\r
-          if (e.getKeyCode() == KeyEvent.VK_UP) {\r
-            historyPosition--;\r
-            if (historyPosition < 0) historyPosition = 0;\r
-            replaceString();\r
-            e.consume();\r
-          } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {\r
-            historyPosition++;\r
-            if (historyPosition > myHistory.size()) historyPosition = myHistory.size();\r
-            replaceString();\r
-            e.consume();\r
-          }\r
-        } else {\r
-          historyPosition = myHistory.size();\r
-        }\r
-      }\r
-\r
-      private void replaceString() {\r
-        final String str;\r
-\r
-        if (myHistory.size() == historyPosition) str = "";\r
-        else str = myHistory.get(historyPosition);\r
-        synchronized (LOCK) {\r
-          if (myTokens.isEmpty()) return;\r
-          final TokenInfo info = myTokens.get(myTokens.size() - 1);\r
-          if (info.contentType != ConsoleViewContentType.USER_INPUT) {\r
-            consoleView.insertUserText(str, 0);\r
-          } else {\r
-            consoleView.replaceUserText(str, info.startOffset, info.endOffset);\r
-          }\r
-        }\r
-      }\r
-    });\r
-\r
-    setEditorUpActions(editor);\r
-\r
-    return editor;\r
-  }\r
-\r
-  private void highlightUserTokens() {\r
-    if (myTokens.isEmpty()) return;\r
-    final TokenInfo token = myTokens.get(myTokens.size() - 1);\r
-    if (token.contentType == ConsoleViewContentType.USER_INPUT) {\r
-      String text = myEditor.getDocument().getText().substring(token.startOffset, token.endOffset);\r
-      PsiFile file = PsiFileFactory.getInstance(myProject).\r
-        createFileFromText("dummy", myFileType, text, LocalTimeCounter.currentTime(), true);\r
-      Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);\r
-      assert document != null;\r
-      Editor editor = EditorFactory.getInstance().createEditor(document, myProject, myFileType, false);\r
-      try {\r
-        RangeHighlighter[] allHighlighters = myEditor.getMarkupModel().getAllHighlighters();\r
-        for (RangeHighlighter highlighter : allHighlighters) {\r
-          if (highlighter.getStartOffset() >= token.startOffset) {\r
-            myEditor.getMarkupModel().removeHighlighter(highlighter);\r
-          }\r
-        }\r
-        HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(0);\r
-        while (!iterator.atEnd()) {\r
-          myEditor.getMarkupModel().addRangeHighlighter(iterator.getStart() + token.startOffset, iterator.getEnd() + token.startOffset, HighlighterLayer.SYNTAX,\r
-                                                        iterator.getTextAttributes(),\r
-                                                        HighlighterTargetArea.EXACT_RANGE);\r
-          iterator.advance();\r
-        }\r
-      }\r
-      finally {\r
-        EditorFactory.getInstance().releaseEditor(editor);\r
-      }\r
-    }\r
-  }\r
-\r
-  private static void setEditorUpActions(final Editor editor) {\r
-    new EnterHandler().registerCustomShortcutSet(CommonShortcuts.ENTER, editor.getContentComponent());\r
-    registerActionHandler(editor, IdeActions.ACTION_EDITOR_PASTE, new PasteHandler());\r
-    registerActionHandler(editor, IdeActions.ACTION_EDITOR_BACKSPACE, new BackSpaceHandler());\r
-    registerActionHandler(editor, IdeActions.ACTION_EDITOR_DELETE, new DeleteHandler());\r
-  }\r
-\r
-  private static void registerActionHandler(final Editor editor, final String actionId, final AnAction action) {\r
-    final Keymap keymap=KeymapManager.getInstance().getActiveKeymap();\r
-    final Shortcut[] shortcuts = keymap.getShortcuts(actionId);\r
-    action.registerCustomShortcutSet(new CustomShortcutSet(shortcuts), editor.getContentComponent());\r
-  }\r
-\r
-  private void popupInvoked(final Component component, final int x, final int y){\r
-    final DefaultActionGroup group = new DefaultActionGroup();\r
-    group.add(new ClearAllAction());\r
-    group.add(new CopyAction());\r
-    group.addSeparator();\r
-    final ActionManager actionManager = ActionManager.getInstance();\r
-    group.add(actionManager.getAction(DiffActions.COMPARE_WITH_CLIPBOARD));\r
-    final ActionPopupMenu menu = actionManager.createActionPopupMenu(ActionPlaces.UNKNOWN, group);\r
-    menu.getComponent().show(component, x, y);\r
-  }\r
-\r
-  private void navigate(final EditorMouseEvent event){\r
-    if (event.getMouseEvent().isPopupTrigger()) return;\r
-    final Point p = event.getMouseEvent().getPoint();\r
-    final HyperlinkInfo info = getHyperlinkInfoByPoint(p);\r
-    if (info != null){\r
-      info.navigate(myProject);\r
-      linkFollowed(info);\r
-    }\r
-  }\r
-\r
-  private static final Key<TextAttributes> OLD_HYPERLINK_TEXT_ATTRIBUTES = Key.create("OLD_HYPERLINK_TEXT_ATTRIBUTES");\r
-  private void linkFollowed(final HyperlinkInfo info) {\r
-    MarkupModelEx markupModel = (MarkupModelEx)myEditor.getMarkupModel();\r
-    for (Map.Entry<RangeHighlighter,HyperlinkInfo> entry : myHyperlinks.getRanges().entrySet()) {\r
-      RangeHighlighter range = entry.getKey();\r
-      TextAttributes oldAttr = range.getUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES);\r
-      if (oldAttr != null) {\r
-        markupModel.setRangeHighlighterAttributes(range, oldAttr);\r
-        range.putUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES, null);\r
-      }\r
-      if (entry.getValue() == info) {\r
-        TextAttributes oldAttributes = range.getTextAttributes();\r
-        range.putUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES, oldAttributes);\r
-        TextAttributes attributes = getFollowedHyperlinkAttributes().clone();\r
-        assert oldAttributes != null;\r
-        attributes.setFontType(oldAttributes.getFontType());\r
-        attributes.setEffectType(oldAttributes.getEffectType());\r
-        attributes.setEffectColor(oldAttributes.getEffectColor());\r
-        attributes.setForegroundColor(oldAttributes.getForegroundColor());\r
-        markupModel.setRangeHighlighterAttributes(range, attributes);\r
-      }\r
-    }\r
-    //refresh highlighter text attributes\r
-    RangeHighlighter dummy = markupModel.addRangeHighlighter(0, 0, HYPERLINK_LAYER, getHyperlinkAttributes(), HighlighterTargetArea.EXACT_RANGE);\r
-    markupModel.removeHighlighter(dummy);\r
-  }\r
-\r
-  private HyperlinkInfo getHyperlinkInfoByPoint(final Point p){\r
-    if (myEditor == null) return null;\r
-    final LogicalPosition pos = myEditor.xyToLogicalPosition(new Point(p.x, p.y));\r
-    return getHyperlinkInfoByLineAndCol(pos.line, pos.column);\r
-  }\r
-\r
-  private HyperlinkInfo getHyperlinkInfoByLineAndCol(final int line, final int col) {\r
-    final int offset = myEditor.logicalPositionToOffset(new LogicalPosition(line, col));\r
-    return myHyperlinks.getHyperlinkAt(offset);\r
-  }\r
-\r
-  private void highlightHyperlinks(final int line1, final int line2){\r
-    if (myMessageFilter != null){\r
-      ApplicationManager.getApplication().assertIsDispatchThread();\r
-      PsiDocumentManager.getInstance(myProject).commitAllDocuments();\r
-      final Document document = myEditor.getDocument();\r
-      final CharSequence chars = document.getCharsSequence();\r
-      final TextAttributes hyperlinkAttributes = getHyperlinkAttributes();\r
-\r
-      for(int line = line1; line <= line2; line++) {\r
-        if (line < 0) continue;\r
-        final int startOffset = document.getLineStartOffset(line);\r
-        int endOffset = document.getLineEndOffset(line);\r
-        if (endOffset < document.getTextLength()){\r
-          endOffset++; // add '\n'\r
-        }\r
-        final String text = chars.subSequence(startOffset, endOffset).toString();\r
-        final Filter.Result result = myMessageFilter.applyFilter(text, endOffset);\r
-        if (result != null){\r
-          final int highlightStartOffset = result.highlightStartOffset;\r
-          final int highlightEndOffset = result.highlightEndOffset;\r
-          final HyperlinkInfo hyperlinkInfo = result.hyperlinkInfo;\r
-          addHyperlink(highlightStartOffset, highlightEndOffset, result.highlightAttributes, hyperlinkInfo, hyperlinkAttributes);\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  private void addHyperlink(final int highlightStartOffset,\r
-                            final int highlightEndOffset,\r
-                            final TextAttributes highlightAttributes,\r
-                            final HyperlinkInfo hyperlinkInfo,\r
-                            final TextAttributes hyperlinkAttributes) {\r
-    TextAttributes textAttributes = highlightAttributes != null ? highlightAttributes : hyperlinkAttributes;\r
-    final RangeHighlighter highlighter = myEditor.getMarkupModel().addRangeHighlighter(highlightStartOffset,\r
-                                                                                       highlightEndOffset,\r
-                                                                                       HYPERLINK_LAYER,\r
-                                                                                       textAttributes,\r
-                                                                                       HighlighterTargetArea.EXACT_RANGE);\r
-    myHyperlinks.add(highlighter, hyperlinkInfo);\r
-  }\r
-\r
-  private class ClearAllAction extends AnAction{\r
-    private ClearAllAction(){\r
-      super(ExecutionBundle.message("clear.all.from.console.action.name"));\r
-    }\r
-\r
-    public void actionPerformed(final AnActionEvent e){\r
-      clear();\r
-    }\r
-  }\r
-\r
-  private class CopyAction extends AnAction{\r
-    private CopyAction(){\r
-      super(myEditor != null && myEditor.getSelectionModel().hasSelection() ? ExecutionBundle.message("copy.selected.content.action.name") : ExecutionBundle.message("copy.content.action.name"));\r
-    }\r
-\r
-    public void actionPerformed(final AnActionEvent e){\r
-      if (myEditor == null) return;\r
-      if (myEditor.getSelectionModel().hasSelection()){\r
-        myEditor.getSelectionModel().copySelectionToClipboard();\r
-      }\r
-      else{\r
-        myEditor.getSelectionModel().setSelection(0, myEditor.getDocument().getTextLength());\r
-        myEditor.getSelectionModel().copySelectionToClipboard();\r
-        myEditor.getSelectionModel().removeSelection();\r
-      }\r
-    }\r
-  }\r
-\r
-  private class MyHighlighter extends DocumentAdapter implements EditorHighlighter {\r
-    private boolean myHasEditor;\r
-\r
-    public HighlighterIterator createIterator(final int startOffset) {\r
-      final int startIndex = findTokenInfoIndexByOffset(startOffset);\r
-\r
-      return new HighlighterIterator(){\r
-        private int myIndex = startIndex;\r
-\r
-        public TextAttributes getTextAttributes() {\r
-          if (myFileType != null && getTokenInfo().contentType == ConsoleViewContentType.USER_INPUT) {\r
-            return ConsoleViewContentType.NORMAL_OUTPUT.getAttributes();\r
-          }\r
-          return getTokenInfo() == null ? null : getTokenInfo().attributes;\r
-        }\r
-\r
-        public int getStart() {\r
-          return getTokenInfo() == null ? 0 : getTokenInfo().startOffset;\r
-        }\r
-\r
-        public int getEnd() {\r
-          return getTokenInfo() == null ? 0 : getTokenInfo().endOffset;\r
-        }\r
-\r
-        public IElementType getTokenType() {\r
-          return null;\r
-        }\r
-\r
-        public void advance() {\r
-          myIndex++;\r
-        }\r
-\r
-        public void retreat() {\r
-          myIndex--;\r
-        }\r
-\r
-        public boolean atEnd() {\r
-          return myIndex < 0 || myIndex >= myTokens.size();\r
-        }\r
-\r
-        private TokenInfo getTokenInfo() {\r
-          return myTokens.get(myIndex);\r
-        }\r
-      };\r
-    }\r
-\r
-    public void setText(final CharSequence text) {\r
-    }\r
-\r
-    public void setEditor(final HighlighterClient editor) {\r
-      LOG.assertTrue(!myHasEditor, "Highlighters cannot be reused with different editors");\r
-      myHasEditor = true;\r
-    }\r
-\r
-    public void setColorScheme(EditorColorsScheme scheme) {\r
-    }\r
-  }\r
-\r
-  private int findTokenInfoIndexByOffset(final int offset) {\r
-    int low = 0;\r
-    int high = myTokens.size() - 1;\r
-\r
-    while(low <= high){\r
-      final int mid = (low + high) / 2;\r
-      final TokenInfo midVal = myTokens.get(mid);\r
-      if (offset < midVal.startOffset){\r
-        high = mid - 1;\r
-      }\r
-      else if (offset >= midVal.endOffset){\r
-        low = mid + 1;\r
-      }\r
-      else{\r
-        return mid;\r
-      }\r
-    }\r
-    return myTokens.size();\r
-  }\r
-\r
-  private static class MyTypedHandler implements TypedActionHandler {\r
-    private final TypedActionHandler myOriginalHandler;\r
-\r
-    private MyTypedHandler(final TypedActionHandler originalAction) {\r
-      myOriginalHandler = originalAction;\r
-    }\r
-\r
-    public void execute(@NotNull final Editor editor, final char charTyped, @NotNull final DataContext dataContext) {\r
-      final ConsoleViewImpl consoleView = editor.getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);\r
-      if (consoleView == null || !consoleView.myState.isRunning() || consoleView.isViewer){\r
-        myOriginalHandler.execute(editor, charTyped, dataContext);\r
-      }\r
-      else{\r
-        final String s = String.valueOf(charTyped);\r
-        SelectionModel selectionModel = editor.getSelectionModel();\r
-        if (selectionModel.hasSelection()) {\r
-          consoleView.replaceUserText(s, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());\r
-        } else {\r
-          consoleView.insertUserText(s, editor.getCaretModel().getOffset());\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  private static final DataAccessor<ConsoleViewImpl> CONSOLE = new DataAccessor<ConsoleViewImpl>() {\r
-    public ConsoleViewImpl getImpl(final DataContext dataContext) throws NoDataException {\r
-      return DataAccessors.EDITOR.getNotNull(dataContext).getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);\r
-    }\r
-  };\r
-\r
-  private static final Condition<ConsoleViewImpl> CONSOLE_IS_RUNNING = new Condition<ConsoleViewImpl>() {\r
-    public boolean value(final ConsoleViewImpl consoleView) {\r
-      return consoleView.myState.isRunning();\r
-    }\r
-  };\r
-\r
-  private static final DataAccessor<ConsoleViewImpl> RUNNINT_CONSOLE =DataAccessor.createConditionalAccessor(CONSOLE, CONSOLE_IS_RUNNING);\r
-\r
-  private abstract static class ConsoleAction extends AnAction implements DumbAware {\r
-    public void actionPerformed(final AnActionEvent e) {\r
-      final DataContext context = e.getDataContext();\r
-      final ConsoleViewImpl console = RUNNINT_CONSOLE.from(context);\r
-      execute(console, context);\r
-    }\r
-\r
-    protected abstract void execute(ConsoleViewImpl console, final DataContext context);\r
-\r
-    public void update(final AnActionEvent e) {\r
-      final ConsoleViewImpl console = RUNNINT_CONSOLE.from(e.getDataContext());\r
-      e.getPresentation().setEnabled(console != null);\r
-    }\r
-  }\r
-\r
-  private static class EnterHandler extends ConsoleAction {\r
-    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {\r
-      synchronized (consoleView.LOCK) {\r
-        String str = consoleView.myDeferredUserInput.toString();\r
-        if (StringUtil.isNotEmpty(str)) {\r
-          consoleView.myHistory.remove(str);\r
-          consoleView.myHistory.add(str);\r
-          if (consoleView.myHistory.size() > consoleView.myHistorySize) consoleView.myHistory.remove(0);\r
-        }\r
-        for (ConsoleInputListener listener : consoleView.myConsoleInputListeners) {\r
-          listener.textEntered(str);\r
-        }\r
-      }\r
-      consoleView.print("\n", ConsoleViewContentType.USER_INPUT);\r
-      consoleView.flushDeferredText();\r
-      final Editor editor = consoleView.myEditor;\r
-      editor.getCaretModel().moveToOffset(editor.getDocument().getTextLength());\r
-      editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);\r
-    }\r
-  }\r
-\r
-  private static class PasteHandler extends ConsoleAction {\r
-    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {\r
-      final Transferable content = CopyPasteManager.getInstance().getContents();\r
-      if (content == null) return;\r
-      String s = null;\r
-      try {\r
-        s = (String)content.getTransferData(DataFlavor.stringFlavor);\r
-      }\r
-      catch(Exception e) {\r
-        consoleView.myEditor.getComponent().getToolkit().beep();\r
-      }\r
-      if (s == null) return;\r
-      Editor editor = consoleView.myEditor;\r
-      SelectionModel selectionModel = editor.getSelectionModel();\r
-      if (selectionModel.hasSelection()) {\r
-        consoleView.replaceUserText(s, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());\r
-      } else {\r
-        consoleView.insertUserText(s, editor.getCaretModel().getOffset());\r
-      }\r
-    }\r
-  }\r
-\r
-  private static class BackSpaceHandler extends ConsoleAction {\r
-    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {\r
-      final Editor editor = consoleView.myEditor;\r
-\r
-      if (IncrementalSearchHandler.isHintVisible(editor)) {\r
-        getDefaultActionHandler().execute(editor, context);\r
-        return;\r
-      }\r
-\r
-      final Document document = editor.getDocument();\r
-      final int length = document.getTextLength();\r
-      if (length == 0) {\r
-        return;\r
-      }\r
-\r
-      SelectionModel selectionModel = editor.getSelectionModel();\r
-      if (selectionModel.hasSelection()) {\r
-        consoleView.deleteUserText(selectionModel.getSelectionStart(),\r
-                                   selectionModel.getSelectionEnd() - selectionModel.getSelectionStart());\r
-      } else if (editor.getCaretModel().getOffset() > 0) {\r
-        consoleView.deleteUserText(editor.getCaretModel().getOffset() - 1, 1);\r
-      }\r
-    }\r
-\r
-    private static EditorActionHandler getDefaultActionHandler() {\r
-      return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE);\r
-    }\r
-  }\r
-\r
-  private static class DeleteHandler extends ConsoleAction {\r
-    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {\r
-      final Editor editor = consoleView.myEditor;\r
-\r
-      if (IncrementalSearchHandler.isHintVisible(editor)) {\r
-        getDefaultActionHandler().execute(editor, context);\r
-        return;\r
-      }\r
-\r
-      final Document document = editor.getDocument();\r
-      final int length = document.getTextLength();\r
-      if (length == 0) {\r
-        return;\r
-      }\r
-\r
-      SelectionModel selectionModel = editor.getSelectionModel();\r
-      if (selectionModel.hasSelection()) {\r
-        consoleView.deleteUserText(selectionModel.getSelectionStart(),\r
-                                   selectionModel.getSelectionEnd() - selectionModel.getSelectionStart());\r
-      } else {\r
-        consoleView.deleteUserText(editor.getCaretModel().getOffset(), 1);\r
-      }\r
-    }\r
-\r
-    private static EditorActionHandler getDefaultActionHandler() {\r
-      return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE);\r
-    }\r
-  }\r
-\r
-  private static class Hyperlinks {\r
-    private static final int NO_INDEX = Integer.MIN_VALUE;\r
-    private final Map<RangeHighlighter,HyperlinkInfo> myHighlighterToMessageInfoMap = new HashMap<RangeHighlighter, HyperlinkInfo>();\r
-    private int myLastIndex = NO_INDEX;\r
-\r
-    public void clear() {\r
-      myHighlighterToMessageInfoMap.clear();\r
-      myLastIndex = NO_INDEX;\r
-    }\r
-\r
-    public HyperlinkInfo getHyperlinkAt(final int offset) {\r
-      for (final RangeHighlighter highlighter : myHighlighterToMessageInfoMap.keySet()) {\r
-        if (highlighter.isValid() && containsOffset(offset, highlighter)) {\r
-          return myHighlighterToMessageInfoMap.get(highlighter);\r
-        }\r
-      }\r
-      return null;\r
-    }\r
-\r
-    private static boolean containsOffset(final int offset, final RangeHighlighter highlighter) {\r
-      return highlighter.getStartOffset() <= offset && offset <= highlighter.getEndOffset();\r
-    }\r
-\r
-    public void add(final RangeHighlighter highlighter, final HyperlinkInfo hyperlinkInfo) {\r
-      myHighlighterToMessageInfoMap.put(highlighter, hyperlinkInfo);\r
-      if (myLastIndex != NO_INDEX && containsOffset(myLastIndex, highlighter)) myLastIndex = NO_INDEX;\r
-    }\r
-\r
-    private Map<RangeHighlighter,HyperlinkInfo> getRanges() {\r
-      return myHighlighterToMessageInfoMap;\r
-    }\r
-  }\r
-\r
-  public JComponent getPreferredFocusableComponent() {\r
-    //ensure editor created\r
-    getComponent();\r
-    return myEditor.getContentComponent();\r
-  }\r
-\r
-\r
-  // navigate up/down in stack trace\r
-  public boolean hasNextOccurence() {\r
-    return next(1, false) != null;\r
-  }\r
-\r
-  public boolean hasPreviousOccurence() {\r
-    return next(-1, false) != null;\r
-  }\r
-\r
-  public OccurenceInfo goNextOccurence() {\r
-    return next(1, true);\r
-  }\r
-\r
-  private OccurenceInfo next(final int delta, boolean doMove) {\r
-    List<RangeHighlighter> ranges = new ArrayList<RangeHighlighter>(myHyperlinks.getRanges().keySet());\r
-    Collections.sort(ranges, new Comparator<RangeHighlighter>() {\r
-      public int compare(final RangeHighlighter o1, final RangeHighlighter o2) {\r
-        return o1.getStartOffset() - o2.getStartOffset();\r
-      }\r
-    });\r
-    int i;\r
-    for (i = 0; i<ranges.size(); i++) {\r
-      RangeHighlighter range = ranges.get(i);\r
-      if (range.getUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES) != null) {\r
-        break;\r
-      }\r
-    }\r
-    int newIndex = ranges.isEmpty() ? -1 : i == ranges.size() ? 0 : (i + delta + ranges.size()) % ranges.size();\r
-    RangeHighlighter next = newIndex < ranges.size() && newIndex >= 0 ? ranges.get(newIndex) : null;\r
-    if (next == null) return null;\r
-    if (doMove) {\r
-      scrollTo(next.getStartOffset());\r
-    }\r
-    final HyperlinkInfo hyperlinkInfo = myHyperlinks.getRanges().get(next);\r
-    return new OccurenceInfo(new Navigatable() {\r
-      public void navigate(final boolean requestFocus) {\r
-        hyperlinkInfo.navigate(myProject);\r
-        linkFollowed(hyperlinkInfo);\r
-      }\r
-\r
-      public boolean canNavigate() {\r
-        return true;\r
-      }\r
-\r
-      public boolean canNavigateToSource() {\r
-        return true;\r
-      }\r
-    }, i, ranges.size());\r
-  }\r
-\r
-  public OccurenceInfo goPreviousOccurence() {\r
-    return next(-1, true);\r
-  }\r
-\r
-  public String getNextOccurenceActionName() {\r
-    return ExecutionBundle.message("down.the.stack.trace");\r
-  }\r
-\r
-  public String getPreviousOccurenceActionName() {\r
-    return ExecutionBundle.message("up.the.stack.trace");\r
-  }\r
-\r
-  public void addCustomConsoleAction(@NotNull AnAction action) {\r
-    customActions.add(action);\r
-  }\r
-\r
-  @NotNull\r
-  public AnAction[] createConsoleActions() {\r
-    //Initializing prev and next occurrences actions\r
-    CommonActionsManager actionsManager = CommonActionsManager.getInstance();\r
-    AnAction prevAction = actionsManager.createPrevOccurenceAction(this);\r
-    prevAction.getTemplatePresentation().setText(getPreviousOccurenceActionName());\r
-    AnAction nextAction = actionsManager.createNextOccurenceAction(this);\r
-    nextAction.getTemplatePresentation().setText(getNextOccurenceActionName());\r
-    //Initializing custom actions\r
-    AnAction[] consoleActions = new AnAction[2 + customActions.size()];\r
-    consoleActions[0] = prevAction;\r
-    consoleActions[1] = nextAction;\r
-    for (int i = 0; i < customActions.size(); ++i) {\r
-      consoleActions[i + 2] = customActions.get(i);\r
-    }\r
-    return consoleActions;\r
-  }\r
-\r
-  public void setEditorEnabled(boolean enabled) {\r
-    myEditor.getContentComponent().setEnabled(enabled);\r
-  }\r
-\r
-  private void fireChange() {\r
-    if (myDeferredTypes.isEmpty()) return;\r
-    Collection<ConsoleViewContentType> types = Collections.unmodifiableCollection(myDeferredTypes);\r
-\r
-    for (ChangeListener each : myListeners) {\r
-      each.contentAdded(types);\r
-    }\r
-\r
-    myDeferredTypes.clear();\r
-  }\r
-\r
-  public void addChangeListener(final ChangeListener listener, final Disposable parent) {\r
-    myListeners.add(listener);\r
-    Disposer.register(parent, new Disposable() {\r
-      public void dispose() {\r
-        myListeners.remove(listener);\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * insert text to document\r
-   * @param s inserted text\r
-   * @param offset relativly to all document text\r
-   */\r
-  private void insertUserText(final String s, int offset) {\r
-    final ConsoleViewImpl consoleView = this;\r
-    final Editor editor = consoleView.myEditor;\r
-    final Document document = editor.getDocument();\r
-    final int startOffset;\r
-\r
-    synchronized (consoleView.LOCK) {\r
-      if (consoleView.myTokens.isEmpty()) return;\r
-      final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);\r
-      if (info.contentType != ConsoleViewContentType.USER_INPUT && !s.contains("\n")) {\r
-        consoleView.print(s, ConsoleViewContentType.USER_INPUT);\r
-        consoleView.flushDeferredText();\r
-        editor.getCaretModel().moveToOffset(document.getTextLength());\r
-        editor.getSelectionModel().removeSelection();\r
-        return;\r
-      } else if (info.contentType != ConsoleViewContentType.USER_INPUT) {\r
-        insertUserText("temp", offset);\r
-        final TokenInfo newInfo = consoleView.myTokens.get(consoleView.myTokens.size() - 1);\r
-        replaceUserText(s, newInfo.startOffset, newInfo.endOffset);\r
-        return;\r
-      }\r
-      int charCountToAdd;\r
-\r
-\r
-      if (offset > info.endOffset) {\r
-        startOffset = info.endOffset;\r
-      }\r
-      else if (offset < info.startOffset) {\r
-        startOffset = info.startOffset;\r
-      } else {\r
-        startOffset = offset;\r
-      }\r
-      charCountToAdd = s.length();\r
-\r
-      if (consoleView.myDeferredUserInput.length() < info.endOffset - info.startOffset) return; //user was quick\r
-\r
-      consoleView.myDeferredUserInput.insert(startOffset - info.startOffset, s);\r
-\r
-      info.endOffset += charCountToAdd;\r
-      consoleView.myContentSize += charCountToAdd;\r
-    }\r
-\r
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {\r
-      public void run() {\r
-        document.insertString(startOffset, s);\r
-        editor.getCaretModel().moveToOffset(startOffset + s.length());\r
-        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * replace text\r
-   * @param s text for replace\r
-   * @param start relativly to all document text\r
-   * @param end relativly to all document text\r
-   */\r
-  private void replaceUserText(final String s, int start, int end) {\r
-    if (start == end) {\r
-      insertUserText(s, start);\r
-      return;\r
-    }\r
-    final ConsoleViewImpl consoleView = this;\r
-    final Editor editor = consoleView.myEditor;\r
-    final Document document = editor.getDocument();\r
-    final int startOffset;\r
-    final int endOffset;\r
-\r
-    synchronized (consoleView.LOCK) {\r
-      if (consoleView.myTokens.isEmpty()) return;\r
-      final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);\r
-      if (info.contentType != ConsoleViewContentType.USER_INPUT) {\r
-        consoleView.print(s, ConsoleViewContentType.USER_INPUT);\r
-        consoleView.flushDeferredText();\r
-        editor.getCaretModel().moveToOffset(document.getTextLength());\r
-        editor.getSelectionModel().removeSelection();\r
-        return;\r
-      }\r
-      if (consoleView.myDeferredUserInput.length() == 0) return;\r
-      int charCountToReplace;\r
-\r
-      startOffset = getStartOffset(start, info);\r
-      endOffset = getEndOffset(end, info);\r
-\r
-      if (startOffset == -1 ||\r
-          endOffset == -1 ||\r
-          endOffset <= startOffset) {\r
-        editor.getSelectionModel().removeSelection();\r
-        editor.getCaretModel().moveToOffset(start);\r
-        return;\r
-      }\r
-      charCountToReplace = s.length() - endOffset + startOffset;\r
-\r
-      if (consoleView.myDeferredUserInput.length() < info.endOffset - info.startOffset) return; //user was quick\r
-\r
-      consoleView.myDeferredUserInput.replace(startOffset - info.startOffset, endOffset - info.startOffset, s);\r
-\r
-      info.endOffset += charCountToReplace;\r
-      if (info.startOffset == info.endOffset) {\r
-        consoleView.myTokens.remove(consoleView.myTokens.size() - 1);\r
-      }\r
-      consoleView.myContentSize += charCountToReplace;\r
-    }\r
-\r
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {\r
-      public void run() {\r
-        document.replaceString(startOffset, endOffset, s);\r
-        editor.getCaretModel().moveToOffset(startOffset + s.length());\r
-        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);\r
-        editor.getSelectionModel().removeSelection();\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * delete text\r
-   * @param offset relativly to all document text\r
-   * @param length lenght of deleted text\r
-   */\r
-  private void deleteUserText(int offset, int length) {\r
-    ConsoleViewImpl consoleView = this;\r
-    final Editor editor = consoleView.myEditor;\r
-    final Document document = editor.getDocument();\r
-    final int startOffset;\r
-    final int endOffset;\r
-\r
-    synchronized (consoleView.LOCK) {\r
-      if (consoleView.myTokens.isEmpty()) return;\r
-      final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);\r
-      if (info.contentType != ConsoleViewContentType.USER_INPUT) return;\r
-      if (consoleView.myDeferredUserInput.length() == 0) return;\r
-      int charCountToDelete;\r
-\r
-      startOffset = getStartOffset(offset, info);\r
-      endOffset = getEndOffset(offset + length, info);\r
-      if (startOffset == -1 ||\r
-          endOffset == -1 ||\r
-          endOffset <= startOffset) {\r
-        editor.getSelectionModel().removeSelection();\r
-        editor.getCaretModel().moveToOffset(offset);\r
-        return;\r
-      }\r
-\r
-      consoleView.myDeferredUserInput.delete(startOffset - info.startOffset, endOffset - info.startOffset);\r
-      charCountToDelete = endOffset - startOffset;\r
-\r
-      info.endOffset -= charCountToDelete;\r
-      if (info.startOffset == info.endOffset) {\r
-        consoleView.myTokens.remove(consoleView.myTokens.size() - 1);\r
-      }\r
-      consoleView.myContentSize -= charCountToDelete;\r
-    }\r
-\r
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {\r
-      public void run() {\r
-        document.deleteString(startOffset, endOffset);\r
-        editor.getCaretModel().moveToOffset(startOffset);\r
-        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);\r
-        editor.getSelectionModel().removeSelection();\r
-      }\r
-    });\r
-  }\r
-\r
-  //util methods for add, replace, delete methods\r
-  private int getStartOffset(int offset, TokenInfo info) {\r
-    int startOffset;\r
-    if (offset >= info.startOffset && offset < info.endOffset) {\r
-      startOffset = offset;\r
-    } else if (offset < info.startOffset) {\r
-      startOffset = info.startOffset;\r
-    } else {\r
-      startOffset = -1;\r
-    }\r
-    return startOffset;\r
-  }\r
-\r
-  private int getEndOffset(int offset, TokenInfo info) {\r
-    int endOffset;\r
-    if (offset > info.endOffset) {\r
-      endOffset = info.endOffset;\r
-    } else if (offset <= info.startOffset) {\r
-      endOffset = -1;\r
-    } else {\r
-      endOffset = offset;\r
-    }\r
-    return endOffset;\r
-  }\r
-}\r
-\r
+/*
+ * Copyright 2000-2009 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 com.intellij.execution.impl;
+
+import com.intellij.codeInsight.navigation.IncrementalSearchHandler;
+import com.intellij.execution.ExecutionBundle;
+import com.intellij.execution.filters.*;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.ui.ConsoleView;
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.execution.ui.ObservableConsoleView;
+import com.intellij.ide.CommonActionsManager;
+import com.intellij.ide.DataAccessor;
+import com.intellij.ide.DataAccessors;
+import com.intellij.ide.OccurenceNavigator;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.diff.actions.DiffActions;
+import com.intellij.openapi.editor.*;
+import com.intellij.openapi.editor.actionSystem.*;
+import com.intellij.openapi.editor.colors.CodeInsightColors;
+import com.intellij.openapi.editor.colors.EditorColors;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.event.*;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.ex.MarkupModelEx;
+import com.intellij.openapi.editor.highlighter.EditorHighlighter;
+import com.intellij.openapi.editor.highlighter.HighlighterClient;
+import com.intellij.openapi.editor.highlighter.HighlighterIterator;
+import com.intellij.openapi.editor.markup.HighlighterLayer;
+import com.intellij.openapi.editor.markup.HighlighterTargetArea;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.keymap.Keymap;
+import com.intellij.openapi.keymap.KeymapManager;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.text.LineTokenizer;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.pom.Navigatable;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileFactory;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.util.Alarm;
+import com.intellij.util.EditorPopupHandler;
+import com.intellij.util.LocalTimeCounter;
+import com.intellij.util.containers.HashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.TestOnly;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.io.IOException;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public final class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableConsoleView, DataProvider, OccurenceNavigator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.ConsoleViewImpl");
+
+  private static final int FLUSH_DELAY = 200; //TODO : make it an option
+
+  private static final Key<ConsoleViewImpl> CONSOLE_VIEW_IN_EDITOR_VIEW = Key.create("CONSOLE_VIEW_IN_EDITOR_VIEW");
+  static {
+    final EditorActionManager actionManager = EditorActionManager.getInstance();
+    final TypedAction typedAction = actionManager.getTypedAction();
+    typedAction.setupHandler(new MyTypedHandler(typedAction.getHandler()));
+  }
+
+  private final DisposedPsiManagerCheck myPsiDisposedCheck;
+  private ConsoleState myState = ConsoleState.NOT_STARTED;
+  private final int CYCLIC_BUFFER_SIZE = getCycleBufferSize();
+  private final boolean isViewer;
+  private Computable<ModalityState> myStateForUpdate;
+
+  private static int getCycleBufferSize() {
+    final String cycleBufferSizeProperty = System.getProperty("idea.cycle.buffer.size");
+    if (cycleBufferSizeProperty == null) return 1024 * 1024;
+    try {
+      return Integer.parseInt(cycleBufferSizeProperty) * 1024;
+    }
+    catch (NumberFormatException e) {
+      return 1024 * 1024;
+    }
+  }
+
+  private final boolean USE_CYCLIC_BUFFER = useCycleBuffer();
+
+  private static boolean useCycleBuffer() {
+    final String useCycleBufferProperty = System.getProperty("idea.cycle.buffer.size");
+    return useCycleBufferProperty == null || !"disabled".equalsIgnoreCase(useCycleBufferProperty);
+  }
+
+  private static final int HYPERLINK_LAYER = HighlighterLayer.SELECTION - 123;
+  private final Alarm mySpareTimeAlarm = new Alarm();
+
+  private final CopyOnWriteArraySet<ChangeListener> myListeners = new CopyOnWriteArraySet<ChangeListener>();
+  private final Set<ConsoleViewContentType> myDeferredTypes = new HashSet<ConsoleViewContentType>();
+  private final ArrayList<AnAction> customActions = new ArrayList<AnAction>();
+
+  @TestOnly
+  public Editor getEditor() {
+    return myEditor;
+  }
+
+  public void scrollToEnd() {
+    myEditor.getCaretModel().moveToOffset(myEditor.getDocument().getTextLength());
+  }
+
+  private static class TokenInfo{
+    private final ConsoleViewContentType contentType;
+    private int startOffset;
+    private int endOffset;
+    private final TextAttributes attributes;
+
+    private TokenInfo(final ConsoleViewContentType contentType, final int startOffset, final int endOffset) {
+      this.contentType = contentType;
+      this.startOffset = startOffset;
+      this.endOffset = endOffset;
+      attributes = contentType.getAttributes();
+    }
+  }
+
+  private final Project myProject;
+
+  private boolean myOutputPaused;
+
+  private Editor myEditor;
+
+  private final Object LOCK = new Object();
+
+  private int myContentSize;
+  private StringBuffer myDeferredOutput = new StringBuffer();
+  private StringBuffer myDeferredUserInput = new StringBuffer();
+
+  private ArrayList<TokenInfo> myTokens = new ArrayList<TokenInfo>();
+  private final Hyperlinks myHyperlinks = new Hyperlinks();
+
+  private String myHelpId;
+
+  private final Alarm myFlushAlarm = new Alarm();
+
+  private final Runnable myFlushDeferredRunnable = new Runnable() {
+    public void run() {
+      flushDeferredText();
+    }
+  };
+
+  private final CompositeFilter myMessageFilter;
+
+  private ArrayList<String> myHistory = new ArrayList<String>();
+  private int myHistorySize = 20;
+
+  private ArrayList<ConsoleInputListener> myConsoleInputListeners = new ArrayList<ConsoleInputListener>();
+
+  public void addConsoleUserInputLestener(ConsoleInputListener consoleInputListener) {
+    myConsoleInputListeners.add(consoleInputListener);
+  }
+
+  /**
+   * By default history works for one session. If
+   * you want to import previous session, set it up here.
+   * @param history where you can save history
+   */
+  public void importHistory(Collection<String> history) {
+    this.myHistory.clear();
+    this.myHistory.addAll(history);
+    while (this.myHistory.size() > myHistorySize) {
+      this.myHistory.remove(0);
+    }
+  }
+
+  public List<String> getHistory() {
+    return Collections.unmodifiableList(myHistory);
+  }
+
+  public void setHistorySize(int historySize) {
+    this.myHistorySize = historySize;
+  }
+
+  public int getHistorySize() {
+    return myHistorySize;
+  }
+
+  private FileType myFileType;
+
+  /**
+   * Use it for custom highlighting for user text.
+   * This will be highlighted as appropriate file to this file type.
+   * @param fileType according to which use highlighting
+   */
+  public void setFileType(FileType fileType) {
+    myFileType = fileType;
+  }
+
+  public ConsoleViewImpl(final Project project, boolean viewer) {
+    this(project, viewer, null);
+  }
+
+  public ConsoleViewImpl(final Project project, boolean viewer, FileType fileType) {
+    super(new BorderLayout());
+    isViewer = viewer;
+    myPsiDisposedCheck = new DisposedPsiManagerCheck(project);
+    myProject = project;
+    myFileType = fileType;
+
+    myMessageFilter = new CompositeFilter(project);
+    final ConsoleFilterProvider[] filterProviders = Extensions.getExtensions(ConsoleFilterProvider.FILTER_PROVIDERS);
+    for (ConsoleFilterProvider filterProvider : filterProviders) {
+      final Filter[] defaultFilters = filterProvider.getDefaultFilters(project);
+      for (Filter filter : defaultFilters) {
+        addMessageFilter(filter);
+      }
+    }
+
+    Disposer.register(project, this);
+  }
+
+  public void attachToProcess(final ProcessHandler processHandler){
+    myState = myState.attachTo(this, processHandler);
+  }
+
+  public void clear() {
+    assertIsDispatchThread();
+
+    final Document document;
+    synchronized(LOCK){
+      myContentSize = 0;
+      if (USE_CYCLIC_BUFFER) {
+        myDeferredOutput = new StringBuffer(Math.min(myDeferredOutput.length(), CYCLIC_BUFFER_SIZE));
+      }
+      else {
+        myDeferredOutput = new StringBuffer();
+      }
+      myDeferredTypes.clear();
+      myDeferredUserInput = new StringBuffer();
+      myHyperlinks.clear();
+      myTokens.clear();
+      if (myEditor == null) return;
+      myEditor.getMarkupModel().removeAllHighlighters();
+      document = myEditor.getDocument();
+    }
+    ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, myProject) {
+      public void run() {
+        CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
+          public void run() {
+            document.deleteString(0, document.getTextLength());
+          }
+        }, null, DocCommandGroupId.noneGroupId(document));
+      }
+    });
+  }
+
+  public void scrollTo(final int offset) {
+    assertIsDispatchThread();
+    flushDeferredText();
+    if (myEditor == null) return;
+    int moveOffset = offset;
+    if (USE_CYCLIC_BUFFER && moveOffset >= myEditor.getDocument().getTextLength()) {
+      moveOffset = 0;
+    }
+    myEditor.getCaretModel().moveToOffset(moveOffset);
+    myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
+  }
+
+  private static void assertIsDispatchThread() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+  }
+
+  public void setOutputPaused(final boolean value) {
+    myOutputPaused = value;
+    if (!value){
+      requestFlushImmediately();
+    }
+  }
+
+  public boolean isOutputPaused() {
+    return myOutputPaused;
+  }
+
+  public boolean hasDeferredOutput() {
+    synchronized(LOCK){
+      return myDeferredOutput.length() > 0;
+    }
+  }
+
+  public void performWhenNoDeferredOutput(final Runnable runnable) {
+    //Q: implement in another way without timer?
+    if (!hasDeferredOutput()){
+      runnable.run();
+    }
+    else{
+      mySpareTimeAlarm.addRequest(
+        new Runnable() {
+          public void run() {
+            performWhenNoDeferredOutput(runnable);
+          }
+        },
+        100
+      );
+    }
+  }
+
+  public JComponent getComponent() {
+    if (myEditor == null){
+      myEditor = createEditor();
+      requestFlushImmediately();
+      add(myEditor.getComponent(), BorderLayout.CENTER);
+
+      myEditor.getDocument().addDocumentListener(new DocumentAdapter() {
+        public void documentChanged(DocumentEvent e) {
+          if (e.getNewLength() == 0 && e.getOffset() == 0) {
+            // string has beeen removed from the beginning, move tokens down
+            synchronized (LOCK) {
+              int toRemoveLen = e.getOldLength();
+              int tIndex = findTokenInfoIndexByOffset(toRemoveLen);
+              ArrayList<TokenInfo> newTokens = new ArrayList<TokenInfo>(myTokens.subList(tIndex, myTokens.size()));
+              for (TokenInfo token : newTokens) {
+                token.startOffset -= toRemoveLen;
+                token.endOffset -= toRemoveLen;
+              }
+              if (!newTokens.isEmpty()) {
+                newTokens.get(0).startOffset = 0;
+              }
+              myContentSize -= Math.min(myContentSize, toRemoveLen);
+              myTokens = newTokens;
+            }
+          }
+        }
+      });
+    }
+    return this;
+  }
+
+  public void setModalityStateForUpdate(Computable<ModalityState> stateComputable) {
+    myStateForUpdate = stateComputable;
+  }
+
+
+
+  public void dispose(){
+    myState = myState.dispose();
+    if (myEditor != null){
+      myFlushAlarm.cancelAllRequests();
+      mySpareTimeAlarm.cancelAllRequests();
+      if (!myEditor.isDisposed()) {
+        EditorFactory.getInstance().releaseEditor(myEditor);
+      }
+      synchronized (LOCK) {
+        myDeferredOutput = new StringBuffer();
+      }
+      myEditor = null;
+    }
+  }
+
+  public void print(String s, final ConsoleViewContentType contentType) {
+    synchronized(LOCK){
+      myDeferredTypes.add(contentType);
+
+      s = StringUtil.convertLineSeparators(s);
+      myContentSize += s.length();
+      myDeferredOutput.append(s);
+      if (contentType == ConsoleViewContentType.USER_INPUT){
+        myDeferredUserInput.append(s);
+      }
+
+      boolean needNew = true;
+      if (!myTokens.isEmpty()){
+        final TokenInfo lastToken = myTokens.get(myTokens.size() - 1);
+        if (lastToken.contentType == contentType){
+          lastToken.endOffset = myContentSize; // optimization
+          needNew = false;
+        }
+      }
+      if (needNew){
+        myTokens.add(new TokenInfo(contentType, myContentSize - s.length(), myContentSize));
+      }
+
+      if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) {
+        if (contentType == ConsoleViewContentType.USER_INPUT) {
+          flushDeferredUserInput();
+        }
+      }
+      if (myFlushAlarm.getActiveRequestCount() == 0 && myEditor != null) {
+        final boolean shouldFlushNow = USE_CYCLIC_BUFFER && myDeferredOutput.length() > CYCLIC_BUFFER_SIZE;
+        myFlushAlarm.addRequest(myFlushDeferredRunnable, shouldFlushNow? 0 : FLUSH_DELAY, getStateForUpdate());
+      }
+    }
+  }
+
+  private ModalityState getStateForUpdate() {
+    return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(myEditor.getComponent());
+  }
+
+  private void requestFlushImmediately() {
+    if (myEditor != null) {
+      myFlushAlarm.addRequest(myFlushDeferredRunnable, 0, getStateForUpdate());
+    }
+  }
+
+  public int getContentSize() { return myContentSize; }
+
+  public boolean canPause() {
+    return true;
+  }
+
+  private void flushDeferredText() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    if (myProject.isDisposed()) {
+      return;
+    }
+
+    final String text;
+    synchronized (LOCK) {
+      if (myOutputPaused) return;
+      if (myDeferredOutput.length() == 0) return;
+      if (myEditor == null) return;
+
+      text = myDeferredOutput.substring(0, myDeferredOutput.length());
+      if (USE_CYCLIC_BUFFER) {
+        myDeferredOutput = new StringBuffer(Math.min(myDeferredOutput.length(), CYCLIC_BUFFER_SIZE));
+      }
+      else {
+        myDeferredOutput.setLength(0);
+      }
+    }
+    final Document document = myEditor.getDocument();
+    final int oldLineCount = document.getLineCount();
+    final boolean isAtEndOfDocument = myEditor.getCaretModel().getOffset() == document.getTextLength();
+    boolean cycleUsed = USE_CYCLIC_BUFFER && document.getTextLength() + text.length() > CYCLIC_BUFFER_SIZE;
+    ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, myProject) {
+      public void run() {
+        CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
+          public void run() {
+            document.insertString(document.getTextLength(), text);
+            synchronized (LOCK) {
+              fireChange();
+            }
+          }
+        }, null, DocCommandGroupId.noneGroupId(document));
+      }
+    });
+    myPsiDisposedCheck.performCheck();
+    final int newLineCount = document.getLineCount();
+    if (cycleUsed) {
+      final int lineCount = LineTokenizer.calcLineCount(text, true);
+      for (Iterator<RangeHighlighter> it = myHyperlinks.getRanges().keySet().iterator(); it.hasNext();) {
+        if (!it.next().isValid()) {
+          it.remove();
+        }
+      }
+      highlightHyperlinks(newLineCount >= lineCount + 1 ? newLineCount - lineCount - 1 : 0, newLineCount - 1);
+    } 
+    else if (oldLineCount < newLineCount) {
+      highlightHyperlinks(oldLineCount - 1, newLineCount - 2);
+    }
+
+    if (isAtEndOfDocument) {
+      myEditor.getCaretModel().moveToOffset(myEditor.getDocument().getTextLength());
+      myEditor.getSelectionModel().removeSelection();
+      myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+    }
+  }
+
+  private void flushDeferredUserInput() {
+    if (myState.isRunning()){
+      final String text = myDeferredUserInput.substring(0, myDeferredUserInput.length());
+      final int index = Math.max(text.lastIndexOf('\n'), text.lastIndexOf('\r'));
+      if (index < 0) return;
+      try{
+        myState.sendUserInput(text.substring(0, index + 1));
+      }
+      catch(IOException e){
+        return;
+      }
+      myDeferredUserInput.setLength(0);
+      myDeferredUserInput.append(text.substring(index + 1));
+    }
+  }
+
+  public Object getData(final String dataId) {
+    if (DataConstants.NAVIGATABLE.equals(dataId)){
+      if (myEditor == null) {
+        return null;
+      }
+      final LogicalPosition pos = myEditor.getCaretModel().getLogicalPosition();
+      final HyperlinkInfo info = getHyperlinkInfoByLineAndCol(pos.line, pos.column);
+      final OpenFileDescriptor openFileDescriptor = info instanceof FileHyperlinkInfo ? ((FileHyperlinkInfo)info).getDescriptor() : null;
+      if (openFileDescriptor == null || !openFileDescriptor.getFile().isValid()) {
+        return null;
+      }
+      return openFileDescriptor;
+    }
+
+    if (DataConstants.EDITOR.equals(dataId)) {
+      return myEditor;
+    }
+    if (DataConstants.HELP_ID.equals(dataId)) {
+      return myHelpId;
+    }
+    return null;
+  }
+
+  public void setHelpId(final String helpId) {
+    myHelpId = helpId;
+  }
+
+  public void addMessageFilter(final Filter filter) {
+    myMessageFilter.addFilter(filter);
+  }
+
+  public void printHyperlink(final String hyperlinkText, final HyperlinkInfo info) {
+    if (myEditor == null) return;
+    print(hyperlinkText, ConsoleViewContentType.NORMAL_OUTPUT);
+    flushDeferredText();
+    final int textLength = myEditor.getDocument().getTextLength();
+    addHyperlink(textLength - hyperlinkText.length(), textLength, null, info, getHyperlinkAttributes());
+  }
+
+  private static TextAttributes getHyperlinkAttributes() {
+    return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES);
+  }
+
+  private static TextAttributes getFollowedHyperlinkAttributes() {
+    return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.FOLLOWED_HYPERLINK_ATTRIBUTES);
+  }
+  
+  private Editor createEditor() {
+    return ApplicationManager.getApplication().runReadAction(new Computable<Editor>() {
+      public Editor compute() {
+        return doCreateEditor();
+      }
+    });
+  }
+
+  private Editor doCreateEditor() {
+    final EditorFactory editorFactory = EditorFactory.getInstance();
+    final Document editorDocument = editorFactory.createDocument("");
+    editorDocument.addDocumentListener(new DocumentListener() {
+      public void beforeDocumentChange(DocumentEvent event) {
+      }
+
+      public void documentChanged(DocumentEvent event) {
+        if (myFileType != null) {
+          highlightUserTokens();
+        }
+      }
+    });
+
+    final int bufferSize = USE_CYCLIC_BUFFER ? CYCLIC_BUFFER_SIZE : 0;
+    editorDocument.setCyclicBufferSize(bufferSize);
+
+    final EditorEx editor = (EditorEx) editorFactory.createViewer(editorDocument,myProject);
+    final EditorHighlighter highlighter = new MyHighlighter();
+    editor.setHighlighter(highlighter);
+    editor.putUserData(CONSOLE_VIEW_IN_EDITOR_VIEW, this);
+
+    final EditorSettings editorSettings = editor.getSettings();
+    editorSettings.setLineMarkerAreaShown(false);
+    editorSettings.setLineNumbersShown(false);
+    editorSettings.setFoldingOutlineShown(false);
+    editorSettings.setAdditionalPageAtBottom(false);
+    editorSettings.setAdditionalColumnsCount(0);
+    editorSettings.setAdditionalLinesCount(0);
+
+    final EditorColorsScheme scheme = editor.getColorsScheme();
+    editor.setBackgroundColor(scheme.getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY));
+    scheme.setColor(EditorColors.CARET_ROW_COLOR, null);
+    scheme.setColor(EditorColors.RIGHT_MARGIN_COLOR, null);
+
+    editor.addEditorMouseListener(new EditorPopupHandler(){
+      public void invokePopup(final EditorMouseEvent event) {
+        final MouseEvent mouseEvent = event.getMouseEvent();
+        popupInvoked(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
+      }
+    });
+
+    editor.addEditorMouseListener(
+      new EditorMouseAdapter(){
+        public void mouseReleased(final EditorMouseEvent e){
+          final MouseEvent mouseEvent = e.getMouseEvent();
+          if (!mouseEvent.isPopupTrigger()){
+            navigate(e);
+          }
+        }
+      }
+    );
+
+    editor.getContentComponent().addMouseMotionListener(
+      new MouseMotionAdapter(){
+        public void mouseMoved(final MouseEvent e){
+          final HyperlinkInfo info = getHyperlinkInfoByPoint(e.getPoint());
+          if (info != null){
+            editor.getContentComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+          }
+          else{
+            editor.getContentComponent().setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+          }
+        }
+      }
+    );
+
+    final ConsoleViewImpl consoleView = this;
+    editor.getContentComponent().addKeyListener(new KeyListener() {
+      private int historyPosition = myHistory.size();
+
+      public void keyTyped(KeyEvent e) {
+
+      }
+
+      public void keyPressed(KeyEvent e) {
+      }
+
+      public void keyReleased(KeyEvent e) {
+        if (e.isAltDown() && !e.isControlDown() && !e.isMetaDown() && !e.isShiftDown()) {
+          if (e.getKeyCode() == KeyEvent.VK_UP) {
+            historyPosition--;
+            if (historyPosition < 0) historyPosition = 0;
+            replaceString();
+            e.consume();
+          } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
+            historyPosition++;
+            if (historyPosition > myHistory.size()) historyPosition = myHistory.size();
+            replaceString();
+            e.consume();
+          }
+        } else {
+          historyPosition = myHistory.size();
+        }
+      }
+
+      private void replaceString() {
+        final String str;
+
+        if (myHistory.size() == historyPosition) str = "";
+        else str = myHistory.get(historyPosition);
+        synchronized (LOCK) {
+          if (myTokens.isEmpty()) return;
+          final TokenInfo info = myTokens.get(myTokens.size() - 1);
+          if (info.contentType != ConsoleViewContentType.USER_INPUT) {
+            consoleView.insertUserText(str, 0);
+          } else {
+            consoleView.replaceUserText(str, info.startOffset, info.endOffset);
+          }
+        }
+      }
+    });
+
+    setEditorUpActions(editor);
+
+    return editor;
+  }
+
+  private void highlightUserTokens() {
+    if (myTokens.isEmpty()) return;
+    final TokenInfo token = myTokens.get(myTokens.size() - 1);
+    if (token.contentType == ConsoleViewContentType.USER_INPUT) {
+      String text = myEditor.getDocument().getText().substring(token.startOffset, token.endOffset);
+      PsiFile file = PsiFileFactory.getInstance(myProject).
+        createFileFromText("dummy", myFileType, text, LocalTimeCounter.currentTime(), true);
+      Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
+      assert document != null;
+      Editor editor = EditorFactory.getInstance().createEditor(document, myProject, myFileType, false);
+      try {
+        RangeHighlighter[] allHighlighters = myEditor.getMarkupModel().getAllHighlighters();
+        for (RangeHighlighter highlighter : allHighlighters) {
+          if (highlighter.getStartOffset() >= token.startOffset) {
+            myEditor.getMarkupModel().removeHighlighter(highlighter);
+          }
+        }
+        HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(0);
+        while (!iterator.atEnd()) {
+          myEditor.getMarkupModel().addRangeHighlighter(iterator.getStart() + token.startOffset, iterator.getEnd() + token.startOffset, HighlighterLayer.SYNTAX,
+                                                        iterator.getTextAttributes(),
+                                                        HighlighterTargetArea.EXACT_RANGE);
+          iterator.advance();
+        }
+      }
+      finally {
+        EditorFactory.getInstance().releaseEditor(editor);
+      }
+    }
+  }
+
+  private static void setEditorUpActions(final Editor editor) {
+    new EnterHandler().registerCustomShortcutSet(CommonShortcuts.ENTER, editor.getContentComponent());
+    registerActionHandler(editor, IdeActions.ACTION_EDITOR_PASTE, new PasteHandler());
+    registerActionHandler(editor, IdeActions.ACTION_EDITOR_BACKSPACE, new BackSpaceHandler());
+    registerActionHandler(editor, IdeActions.ACTION_EDITOR_DELETE, new DeleteHandler());
+  }
+
+  private static void registerActionHandler(final Editor editor, final String actionId, final AnAction action) {
+    final Keymap keymap=KeymapManager.getInstance().getActiveKeymap();
+    final Shortcut[] shortcuts = keymap.getShortcuts(actionId);
+    action.registerCustomShortcutSet(new CustomShortcutSet(shortcuts), editor.getContentComponent());
+  }
+
+  private void popupInvoked(final Component component, final int x, final int y){
+    final DefaultActionGroup group = new DefaultActionGroup();
+    group.add(new ClearAllAction());
+    group.add(new CopyAction());
+    group.addSeparator();
+    final ActionManager actionManager = ActionManager.getInstance();
+    group.add(actionManager.getAction(DiffActions.COMPARE_WITH_CLIPBOARD));
+    final ActionPopupMenu menu = actionManager.createActionPopupMenu(ActionPlaces.UNKNOWN, group);
+    menu.getComponent().show(component, x, y);
+  }
+
+  private void navigate(final EditorMouseEvent event){
+    if (event.getMouseEvent().isPopupTrigger()) return;
+    final Point p = event.getMouseEvent().getPoint();
+    final HyperlinkInfo info = getHyperlinkInfoByPoint(p);
+    if (info != null){
+      info.navigate(myProject);
+      linkFollowed(info);
+    }
+  }
+
+  private static final Key<TextAttributes> OLD_HYPERLINK_TEXT_ATTRIBUTES = Key.create("OLD_HYPERLINK_TEXT_ATTRIBUTES");
+  private void linkFollowed(final HyperlinkInfo info) {
+    MarkupModelEx markupModel = (MarkupModelEx)myEditor.getMarkupModel();
+    for (Map.Entry<RangeHighlighter,HyperlinkInfo> entry : myHyperlinks.getRanges().entrySet()) {
+      RangeHighlighter range = entry.getKey();
+      TextAttributes oldAttr = range.getUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES);
+      if (oldAttr != null) {
+        markupModel.setRangeHighlighterAttributes(range, oldAttr);
+        range.putUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES, null);
+      }
+      if (entry.getValue() == info) {
+        TextAttributes oldAttributes = range.getTextAttributes();
+        range.putUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES, oldAttributes);
+        TextAttributes attributes = getFollowedHyperlinkAttributes().clone();
+        assert oldAttributes != null;
+        attributes.setFontType(oldAttributes.getFontType());
+        attributes.setEffectType(oldAttributes.getEffectType());
+        attributes.setEffectColor(oldAttributes.getEffectColor());
+        attributes.setForegroundColor(oldAttributes.getForegroundColor());
+        markupModel.setRangeHighlighterAttributes(range, attributes);
+      }
+    }
+    //refresh highlighter text attributes
+    RangeHighlighter dummy = markupModel.addRangeHighlighter(0, 0, HYPERLINK_LAYER, getHyperlinkAttributes(), HighlighterTargetArea.EXACT_RANGE);
+    markupModel.removeHighlighter(dummy);
+  }
+
+  private HyperlinkInfo getHyperlinkInfoByPoint(final Point p){
+    if (myEditor == null) return null;
+    final LogicalPosition pos = myEditor.xyToLogicalPosition(new Point(p.x, p.y));
+    return getHyperlinkInfoByLineAndCol(pos.line, pos.column);
+  }
+
+  private HyperlinkInfo getHyperlinkInfoByLineAndCol(final int line, final int col) {
+    final int offset = myEditor.logicalPositionToOffset(new LogicalPosition(line, col));
+    return myHyperlinks.getHyperlinkAt(offset);
+  }
+
+  private void highlightHyperlinks(final int line1, final int line2){
+    if (myMessageFilter != null){
+      ApplicationManager.getApplication().assertIsDispatchThread();
+      PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+      final Document document = myEditor.getDocument();
+      final CharSequence chars = document.getCharsSequence();
+      final TextAttributes hyperlinkAttributes = getHyperlinkAttributes();
+
+      for(int line = line1; line <= line2; line++) {
+        if (line < 0) continue;
+        final int startOffset = document.getLineStartOffset(line);
+        int endOffset = document.getLineEndOffset(line);
+        if (endOffset < document.getTextLength()){
+          endOffset++; // add '\n'
+        }
+        final String text = chars.subSequence(startOffset, endOffset).toString();
+        final Filter.Result result = myMessageFilter.applyFilter(text, endOffset);
+        if (result != null){
+          final int highlightStartOffset = result.highlightStartOffset;
+          final int highlightEndOffset = result.highlightEndOffset;
+          final HyperlinkInfo hyperlinkInfo = result.hyperlinkInfo;
+          addHyperlink(highlightStartOffset, highlightEndOffset, result.highlightAttributes, hyperlinkInfo, hyperlinkAttributes);
+        }
+      }
+    }
+  }
+
+  private void addHyperlink(final int highlightStartOffset,
+                            final int highlightEndOffset,
+                            final TextAttributes highlightAttributes,
+                            final HyperlinkInfo hyperlinkInfo,
+                            final TextAttributes hyperlinkAttributes) {
+    TextAttributes textAttributes = highlightAttributes != null ? highlightAttributes : hyperlinkAttributes;
+    final RangeHighlighter highlighter = myEditor.getMarkupModel().addRangeHighlighter(highlightStartOffset,
+                                                                                       highlightEndOffset,
+                                                                                       HYPERLINK_LAYER,
+                                                                                       textAttributes,
+                                                                                       HighlighterTargetArea.EXACT_RANGE);
+    myHyperlinks.add(highlighter, hyperlinkInfo);
+  }
+
+  private class ClearAllAction extends AnAction{
+    private ClearAllAction(){
+      super(ExecutionBundle.message("clear.all.from.console.action.name"));
+    }
+
+    public void actionPerformed(final AnActionEvent e){
+      clear();
+    }
+  }
+
+  private class CopyAction extends AnAction{
+    private CopyAction(){
+      super(myEditor != null && myEditor.getSelectionModel().hasSelection() ? ExecutionBundle.message("copy.selected.content.action.name") : ExecutionBundle.message("copy.content.action.name"));
+    }
+
+    public void actionPerformed(final AnActionEvent e){
+      if (myEditor == null) return;
+      if (myEditor.getSelectionModel().hasSelection()){
+        myEditor.getSelectionModel().copySelectionToClipboard();
+      }
+      else{
+        myEditor.getSelectionModel().setSelection(0, myEditor.getDocument().getTextLength());
+        myEditor.getSelectionModel().copySelectionToClipboard();
+        myEditor.getSelectionModel().removeSelection();
+      }
+    }
+  }
+
+  private class MyHighlighter extends DocumentAdapter implements EditorHighlighter {
+    private boolean myHasEditor;
+
+    public HighlighterIterator createIterator(final int startOffset) {
+      final int startIndex = findTokenInfoIndexByOffset(startOffset);
+
+      return new HighlighterIterator(){
+        private int myIndex = startIndex;
+
+        public TextAttributes getTextAttributes() {
+          if (myFileType != null && getTokenInfo().contentType == ConsoleViewContentType.USER_INPUT) {
+            return ConsoleViewContentType.NORMAL_OUTPUT.getAttributes();
+          }
+          return getTokenInfo() == null ? null : getTokenInfo().attributes;
+        }
+
+        public int getStart() {
+          return getTokenInfo() == null ? 0 : getTokenInfo().startOffset;
+        }
+
+        public int getEnd() {
+          return getTokenInfo() == null ? 0 : getTokenInfo().endOffset;
+        }
+
+        public IElementType getTokenType() {
+          return null;
+        }
+
+        public void advance() {
+          myIndex++;
+        }
+
+        public void retreat() {
+          myIndex--;
+        }
+
+        public boolean atEnd() {
+          return myIndex < 0 || myIndex >= myTokens.size();
+        }
+
+        private TokenInfo getTokenInfo() {
+          return myTokens.get(myIndex);
+        }
+      };
+    }
+
+    public void setText(final CharSequence text) {
+    }
+
+    public void setEditor(final HighlighterClient editor) {
+      LOG.assertTrue(!myHasEditor, "Highlighters cannot be reused with different editors");
+      myHasEditor = true;
+    }
+
+    public void setColorScheme(EditorColorsScheme scheme) {
+    }
+  }
+
+  private int findTokenInfoIndexByOffset(final int offset) {
+    int low = 0;
+    int high = myTokens.size() - 1;
+
+    while(low <= high){
+      final int mid = (low + high) / 2;
+      final TokenInfo midVal = myTokens.get(mid);
+      if (offset < midVal.startOffset){
+        high = mid - 1;
+      }
+      else if (offset >= midVal.endOffset){
+        low = mid + 1;
+      }
+      else{
+        return mid;
+      }
+    }
+    return myTokens.size();
+  }
+
+  private static class MyTypedHandler implements TypedActionHandler {
+    private final TypedActionHandler myOriginalHandler;
+
+    private MyTypedHandler(final TypedActionHandler originalAction) {
+      myOriginalHandler = originalAction;
+    }
+
+    public void execute(@NotNull final Editor editor, final char charTyped, @NotNull final DataContext dataContext) {
+      final ConsoleViewImpl consoleView = editor.getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);
+      if (consoleView == null || !consoleView.myState.isRunning() || consoleView.isViewer){
+        myOriginalHandler.execute(editor, charTyped, dataContext);
+      }
+      else{
+        final String s = String.valueOf(charTyped);
+        SelectionModel selectionModel = editor.getSelectionModel();
+        if (selectionModel.hasSelection()) {
+          consoleView.replaceUserText(s, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
+        } else {
+          consoleView.insertUserText(s, editor.getCaretModel().getOffset());
+        }
+      }
+    }
+  }
+
+  private static final DataAccessor<ConsoleViewImpl> CONSOLE = new DataAccessor<ConsoleViewImpl>() {
+    public ConsoleViewImpl getImpl(final DataContext dataContext) throws NoDataException {
+      return DataAccessors.EDITOR.getNotNull(dataContext).getUserData(CONSOLE_VIEW_IN_EDITOR_VIEW);
+    }
+  };
+
+  private static final Condition<ConsoleViewImpl> CONSOLE_IS_RUNNING = new Condition<ConsoleViewImpl>() {
+    public boolean value(final ConsoleViewImpl consoleView) {
+      return consoleView.myState.isRunning();
+    }
+  };
+
+  private static final DataAccessor<ConsoleViewImpl> RUNNINT_CONSOLE =DataAccessor.createConditionalAccessor(CONSOLE, CONSOLE_IS_RUNNING);
+
+  private abstract static class ConsoleAction extends AnAction implements DumbAware {
+    public void actionPerformed(final AnActionEvent e) {
+      final DataContext context = e.getDataContext();
+      final ConsoleViewImpl console = RUNNINT_CONSOLE.from(context);
+      execute(console, context);
+    }
+
+    protected abstract void execute(ConsoleViewImpl console, final DataContext context);
+
+    public void update(final AnActionEvent e) {
+      final ConsoleViewImpl console = RUNNINT_CONSOLE.from(e.getDataContext());
+      e.getPresentation().setEnabled(console != null);
+    }
+  }
+
+  private static class EnterHandler extends ConsoleAction {
+    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {
+      synchronized (consoleView.LOCK) {
+        String str = consoleView.myDeferredUserInput.toString();
+        if (StringUtil.isNotEmpty(str)) {
+          consoleView.myHistory.remove(str);
+          consoleView.myHistory.add(str);
+          if (consoleView.myHistory.size() > consoleView.myHistorySize) consoleView.myHistory.remove(0);
+        }
+        for (ConsoleInputListener listener : consoleView.myConsoleInputListeners) {
+          listener.textEntered(str);
+        }
+      }
+      consoleView.print("\n", ConsoleViewContentType.USER_INPUT);
+      consoleView.flushDeferredText();
+      final Editor editor = consoleView.myEditor;
+      editor.getCaretModel().moveToOffset(editor.getDocument().getTextLength());
+      editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+    }
+  }
+
+  private static class PasteHandler extends ConsoleAction {
+    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {
+      final Transferable content = CopyPasteManager.getInstance().getContents();
+      if (content == null) return;
+      String s = null;
+      try {
+        s = (String)content.getTransferData(DataFlavor.stringFlavor);
+      }
+      catch(Exception e) {
+        consoleView.myEditor.getComponent().getToolkit().beep();
+      }
+      if (s == null) return;
+      Editor editor = consoleView.myEditor;
+      SelectionModel selectionModel = editor.getSelectionModel();
+      if (selectionModel.hasSelection()) {
+        consoleView.replaceUserText(s, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
+      } else {
+        consoleView.insertUserText(s, editor.getCaretModel().getOffset());
+      }
+    }
+  }
+
+  private static class BackSpaceHandler extends ConsoleAction {
+    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {
+      final Editor editor = consoleView.myEditor;
+
+      if (IncrementalSearchHandler.isHintVisible(editor)) {
+        getDefaultActionHandler().execute(editor, context);
+        return;
+      }
+
+      final Document document = editor.getDocument();
+      final int length = document.getTextLength();
+      if (length == 0) {
+        return;
+      }
+
+      SelectionModel selectionModel = editor.getSelectionModel();
+      if (selectionModel.hasSelection()) {
+        consoleView.deleteUserText(selectionModel.getSelectionStart(),
+                                   selectionModel.getSelectionEnd() - selectionModel.getSelectionStart());
+      } else if (editor.getCaretModel().getOffset() > 0) {
+        consoleView.deleteUserText(editor.getCaretModel().getOffset() - 1, 1);
+      }
+    }
+
+    private static EditorActionHandler getDefaultActionHandler() {
+      return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE);
+    }
+  }
+
+  private static class DeleteHandler extends ConsoleAction {
+    public void execute(final ConsoleViewImpl consoleView, final DataContext context) {
+      final Editor editor = consoleView.myEditor;
+
+      if (IncrementalSearchHandler.isHintVisible(editor)) {
+        getDefaultActionHandler().execute(editor, context);
+        return;
+      }
+
+      final Document document = editor.getDocument();
+      final int length = document.getTextLength();
+      if (length == 0) {
+        return;
+      }
+
+      SelectionModel selectionModel = editor.getSelectionModel();
+      if (selectionModel.hasSelection()) {
+        consoleView.deleteUserText(selectionModel.getSelectionStart(),
+                                   selectionModel.getSelectionEnd() - selectionModel.getSelectionStart());
+      } else {
+        consoleView.deleteUserText(editor.getCaretModel().getOffset(), 1);
+      }
+    }
+
+    private static EditorActionHandler getDefaultActionHandler() {
+      return EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE);
+    }
+  }
+
+  private static class Hyperlinks {
+    private static final int NO_INDEX = Integer.MIN_VALUE;
+    private final Map<RangeHighlighter,HyperlinkInfo> myHighlighterToMessageInfoMap = new HashMap<RangeHighlighter, HyperlinkInfo>();
+    private int myLastIndex = NO_INDEX;
+
+    public void clear() {
+      myHighlighterToMessageInfoMap.clear();
+      myLastIndex = NO_INDEX;
+    }
+
+    public HyperlinkInfo getHyperlinkAt(final int offset) {
+      for (final RangeHighlighter highlighter : myHighlighterToMessageInfoMap.keySet()) {
+        if (highlighter.isValid() && containsOffset(offset, highlighter)) {
+          return myHighlighterToMessageInfoMap.get(highlighter);
+        }
+      }
+      return null;
+    }
+
+    private static boolean containsOffset(final int offset, final RangeHighlighter highlighter) {
+      return highlighter.getStartOffset() <= offset && offset <= highlighter.getEndOffset();
+    }
+
+    public void add(final RangeHighlighter highlighter, final HyperlinkInfo hyperlinkInfo) {
+      myHighlighterToMessageInfoMap.put(highlighter, hyperlinkInfo);
+      if (myLastIndex != NO_INDEX && containsOffset(myLastIndex, highlighter)) myLastIndex = NO_INDEX;
+    }
+
+    private Map<RangeHighlighter,HyperlinkInfo> getRanges() {
+      return myHighlighterToMessageInfoMap;
+    }
+  }
+
+  public JComponent getPreferredFocusableComponent() {
+    //ensure editor created
+    getComponent();
+    return myEditor.getContentComponent();
+  }
+
+
+  // navigate up/down in stack trace
+  public boolean hasNextOccurence() {
+    return next(1, false) != null;
+  }
+
+  public boolean hasPreviousOccurence() {
+    return next(-1, false) != null;
+  }
+
+  public OccurenceInfo goNextOccurence() {
+    return next(1, true);
+  }
+
+  private OccurenceInfo next(final int delta, boolean doMove) {
+    List<RangeHighlighter> ranges = new ArrayList<RangeHighlighter>(myHyperlinks.getRanges().keySet());
+    Collections.sort(ranges, new Comparator<RangeHighlighter>() {
+      public int compare(final RangeHighlighter o1, final RangeHighlighter o2) {
+        return o1.getStartOffset() - o2.getStartOffset();
+      }
+    });
+    int i;
+    for (i = 0; i<ranges.size(); i++) {
+      RangeHighlighter range = ranges.get(i);
+      if (range.getUserData(OLD_HYPERLINK_TEXT_ATTRIBUTES) != null) {
+        break;
+      }
+    }
+    int newIndex = ranges.isEmpty() ? -1 : i == ranges.size() ? 0 : (i + delta + ranges.size()) % ranges.size();
+    RangeHighlighter next = newIndex < ranges.size() && newIndex >= 0 ? ranges.get(newIndex) : null;
+    if (next == null) return null;
+    if (doMove) {
+      scrollTo(next.getStartOffset());
+    }
+    final HyperlinkInfo hyperlinkInfo = myHyperlinks.getRanges().get(next);
+    return new OccurenceInfo(new Navigatable() {
+      public void navigate(final boolean requestFocus) {
+        hyperlinkInfo.navigate(myProject);
+        linkFollowed(hyperlinkInfo);
+      }
+
+      public boolean canNavigate() {
+        return true;
+      }
+
+      public boolean canNavigateToSource() {
+        return true;
+      }
+    }, i, ranges.size());
+  }
+
+  public OccurenceInfo goPreviousOccurence() {
+    return next(-1, true);
+  }
+
+  public String getNextOccurenceActionName() {
+    return ExecutionBundle.message("down.the.stack.trace");
+  }
+
+  public String getPreviousOccurenceActionName() {
+    return ExecutionBundle.message("up.the.stack.trace");
+  }
+
+  public void addCustomConsoleAction(@NotNull AnAction action) {
+    customActions.add(action);
+  }
+
+  @NotNull
+  public AnAction[] createConsoleActions() {
+    //Initializing prev and next occurrences actions
+    CommonActionsManager actionsManager = CommonActionsManager.getInstance();
+    AnAction prevAction = actionsManager.createPrevOccurenceAction(this);
+    prevAction.getTemplatePresentation().setText(getPreviousOccurenceActionName());
+    AnAction nextAction = actionsManager.createNextOccurenceAction(this);
+    nextAction.getTemplatePresentation().setText(getNextOccurenceActionName());
+    //Initializing custom actions
+    AnAction[] consoleActions = new AnAction[2 + customActions.size()];
+    consoleActions[0] = prevAction;
+    consoleActions[1] = nextAction;
+    for (int i = 0; i < customActions.size(); ++i) {
+      consoleActions[i + 2] = customActions.get(i);
+    }
+    return consoleActions;
+  }
+
+  public void setEditorEnabled(boolean enabled) {
+    myEditor.getContentComponent().setEnabled(enabled);
+  }
+
+  private void fireChange() {
+    if (myDeferredTypes.isEmpty()) return;
+    Collection<ConsoleViewContentType> types = Collections.unmodifiableCollection(myDeferredTypes);
+
+    for (ChangeListener each : myListeners) {
+      each.contentAdded(types);
+    }
+
+    myDeferredTypes.clear();
+  }
+
+  public void addChangeListener(final ChangeListener listener, final Disposable parent) {
+    myListeners.add(listener);
+    Disposer.register(parent, new Disposable() {
+      public void dispose() {
+        myListeners.remove(listener);
+      }
+    });
+  }
+
+  /**
+   * insert text to document
+   * @param s inserted text
+   * @param offset relativly to all document text
+   */
+  private void insertUserText(final String s, int offset) {
+    final ConsoleViewImpl consoleView = this;
+    final Editor editor = consoleView.myEditor;
+    final Document document = editor.getDocument();
+    final int startOffset;
+
+    synchronized (consoleView.LOCK) {
+      if (consoleView.myTokens.isEmpty()) return;
+      final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);
+      if (info.contentType != ConsoleViewContentType.USER_INPUT && !s.contains("\n")) {
+        consoleView.print(s, ConsoleViewContentType.USER_INPUT);
+        consoleView.flushDeferredText();
+        editor.getCaretModel().moveToOffset(document.getTextLength());
+        editor.getSelectionModel().removeSelection();
+        return;
+      } else if (info.contentType != ConsoleViewContentType.USER_INPUT) {
+        insertUserText("temp", offset);
+        final TokenInfo newInfo = consoleView.myTokens.get(consoleView.myTokens.size() - 1);
+        replaceUserText(s, newInfo.startOffset, newInfo.endOffset);
+        return;
+      }
+      int charCountToAdd;
+
+
+      if (offset > info.endOffset) {
+        startOffset = info.endOffset;
+      }
+      else if (offset < info.startOffset) {
+        startOffset = info.startOffset;
+      } else {
+        startOffset = offset;
+      }
+      charCountToAdd = s.length();
+
+      if (consoleView.myDeferredUserInput.length() < info.endOffset - info.startOffset) return; //user was quick
+
+      consoleView.myDeferredUserInput.insert(startOffset - info.startOffset, s);
+
+      info.endOffset += charCountToAdd;
+      consoleView.myContentSize += charCountToAdd;
+    }
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        document.insertString(startOffset, s);
+        editor.getCaretModel().moveToOffset(startOffset + s.length());
+        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+      }
+    });
+  }
+
+  /**
+   * replace text
+   * @param s text for replace
+   * @param start relativly to all document text
+   * @param end relativly to all document text
+   */
+  private void replaceUserText(final String s, int start, int end) {
+    if (start == end) {
+      insertUserText(s, start);
+      return;
+    }
+    final ConsoleViewImpl consoleView = this;
+    final Editor editor = consoleView.myEditor;
+    final Document document = editor.getDocument();
+    final int startOffset;
+    final int endOffset;
+
+    synchronized (consoleView.LOCK) {
+      if (consoleView.myTokens.isEmpty()) return;
+      final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);
+      if (info.contentType != ConsoleViewContentType.USER_INPUT) {
+        consoleView.print(s, ConsoleViewContentType.USER_INPUT);
+        consoleView.flushDeferredText();
+        editor.getCaretModel().moveToOffset(document.getTextLength());
+        editor.getSelectionModel().removeSelection();
+        return;
+      }
+      if (consoleView.myDeferredUserInput.length() == 0) return;
+      int charCountToReplace;
+
+      startOffset = getStartOffset(start, info);
+      endOffset = getEndOffset(end, info);
+
+      if (startOffset == -1 ||
+          endOffset == -1 ||
+          endOffset <= startOffset) {
+        editor.getSelectionModel().removeSelection();
+        editor.getCaretModel().moveToOffset(start);
+        return;
+      }
+      charCountToReplace = s.length() - endOffset + startOffset;
+
+      if (consoleView.myDeferredUserInput.length() < info.endOffset - info.startOffset) return; //user was quick
+
+      consoleView.myDeferredUserInput.replace(startOffset - info.startOffset, endOffset - info.startOffset, s);
+
+      info.endOffset += charCountToReplace;
+      if (info.startOffset == info.endOffset) {
+        consoleView.myTokens.remove(consoleView.myTokens.size() - 1);
+      }
+      consoleView.myContentSize += charCountToReplace;
+    }
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        document.replaceString(startOffset, endOffset, s);
+        editor.getCaretModel().moveToOffset(startOffset + s.length());
+        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+        editor.getSelectionModel().removeSelection();
+      }
+    });
+  }
+
+  /**
+   * delete text
+   * @param offset relativly to all document text
+   * @param length lenght of deleted text
+   */
+  private void deleteUserText(int offset, int length) {
+    ConsoleViewImpl consoleView = this;
+    final Editor editor = consoleView.myEditor;
+    final Document document = editor.getDocument();
+    final int startOffset;
+    final int endOffset;
+
+    synchronized (consoleView.LOCK) {
+      if (consoleView.myTokens.isEmpty()) return;
+      final TokenInfo info = consoleView.myTokens.get(consoleView.myTokens.size() - 1);
+      if (info.contentType != ConsoleViewContentType.USER_INPUT) return;
+      if (consoleView.myDeferredUserInput.length() == 0) return;
+      int charCountToDelete;
+
+      startOffset = getStartOffset(offset, info);
+      endOffset = getEndOffset(offset + length, info);
+      if (startOffset == -1 ||
+          endOffset == -1 ||
+          endOffset <= startOffset) {
+        editor.getSelectionModel().removeSelection();
+        editor.getCaretModel().moveToOffset(offset);
+        return;
+      }
+
+      consoleView.myDeferredUserInput.delete(startOffset - info.startOffset, endOffset - info.startOffset);
+      charCountToDelete = endOffset - startOffset;
+
+      info.endOffset -= charCountToDelete;
+      if (info.startOffset == info.endOffset) {
+        consoleView.myTokens.remove(consoleView.myTokens.size() - 1);
+      }
+      consoleView.myContentSize -= charCountToDelete;
+    }
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        document.deleteString(startOffset, endOffset);
+        editor.getCaretModel().moveToOffset(startOffset);
+        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+        editor.getSelectionModel().removeSelection();
+      }
+    });
+  }
+
+  //util methods for add, replace, delete methods
+  private int getStartOffset(int offset, TokenInfo info) {
+    int startOffset;
+    if (offset >= info.startOffset && offset < info.endOffset) {
+      startOffset = offset;
+    } else if (offset < info.startOffset) {
+      startOffset = info.startOffset;
+    } else {
+      startOffset = -1;
+    }
+    return startOffset;
+  }
+
+  private int getEndOffset(int offset, TokenInfo info) {
+    int endOffset;
+    if (offset > info.endOffset) {
+      endOffset = info.endOffset;
+    } else if (offset <= info.startOffset) {
+      endOffset = -1;
+    } else {
+      endOffset = offset;
+    }
+    return endOffset;
+  }
+}
+
index 9064bb70c356d76ea1cbfd96ddc52df211cb049e..8948242bd840d948f9e16a770694148acacebec4 100644 (file)
-/*\r
- * Copyright 2000-2009 JetBrains s.r.o.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package com.intellij.openapi.util.text;\r
-\r
-import com.intellij.util.ArrayUtil;\r
-import com.intellij.util.text.CharArrayCharSequence;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-/**\r
- *\r
- */\r
-public class LineTokenizer {\r
-  private int myOffset = 0;\r
-  private int myLength = 0;\r
-  private int myLineSeparatorLength = 0;\r
-  private boolean atEnd = false;\r
-  private CharSequence myText;\r
-\r
-  public static String[] tokenize(CharSequence chars, boolean includeSeparators) {\r
-    return tokenize(chars, includeSeparators, true);\r
-  }\r
-\r
-  private static String[] tokenize(final CharSequence chars, final boolean includeSeparators, final boolean skipLastEmptyLine) {\r
-    if (chars == null || chars.length() == 0){\r
-      return ArrayUtil.EMPTY_STRING_ARRAY;\r
-    }\r
-\r
-    LineTokenizer tokenizer = new LineTokenizer(chars);\r
-    List<String> lines = new ArrayList<String>();\r
-    while(!tokenizer.atEnd()){\r
-      int offset = tokenizer.getOffset();\r
-      String line;\r
-      if (includeSeparators){\r
-        line = chars.subSequence(offset, offset + tokenizer.getLength() + tokenizer.getLineSeparatorLength()).toString();\r
-      }\r
-      else{\r
-        line = chars.subSequence(offset, offset + tokenizer.getLength()).toString();\r
-      }\r
-      lines.add(line);\r
-      tokenizer.advance();\r
-    }\r
-\r
-    if (!skipLastEmptyLine && stringEdnsWithSeparator(tokenizer)) lines.add("");\r
-\r
-    return lines.toArray(new String[lines.size()]);\r
-  }\r
-\r
-  public static int calcLineCount(final CharSequence chars, final boolean skipLastEmptyLine) {\r
-    int lineCount = 0;\r
-    if (chars != null && chars.length() != 0) {\r
-      final LineTokenizer tokenizer = new LineTokenizer(chars);\r
-      while (!tokenizer.atEnd()) {\r
-        lineCount += 1;\r
-        tokenizer.advance();\r
-      }\r
-      if (!skipLastEmptyLine && stringEdnsWithSeparator(tokenizer)) {\r
-        lineCount += 1;\r
-      }\r
-    }\r
-    return lineCount;\r
-  }\r
-\r
-  public static String[] tokenize(char[] chars, boolean includeSeparators) {\r
-    return tokenize(chars, includeSeparators, true);\r
-  }\r
-\r
-  public static String[] tokenize(char[] chars, boolean includeSeparators, boolean skipLastEmptyLine) {\r
-    return tokenize(chars, 0, chars.length, includeSeparators, skipLastEmptyLine);\r
-  }\r
-\r
-  public static String[] tokenize(char[] chars, int startOffset, int endOffset, boolean includeSeparators,\r
-                                  boolean skipLastEmptyLine) {\r
-    return tokenize(new CharArrayCharSequence(chars, startOffset, endOffset), includeSeparators, skipLastEmptyLine);\r
-  }\r
-\r
-  private static boolean stringEdnsWithSeparator(LineTokenizer tokenizer) {\r
-    return tokenizer.getLineSeparatorLength() > 0;\r
-  }\r
-\r
-  public static String[] tokenize(char[] chars, int startOffset, int endOffset, boolean includeSeparators) {\r
-    return tokenize(chars, startOffset, endOffset, includeSeparators, true);\r
-  }\r
-\r
-  public LineTokenizer(CharSequence text) {\r
-    myText = text;\r
-    myOffset = 0;\r
-    advance();\r
-  }\r
-\r
-  public LineTokenizer(char[] text, int startOffset, int endOffset) {\r
-    this(new CharArrayCharSequence(text, startOffset, endOffset));\r
-  }\r
-\r
-  public final boolean atEnd() {\r
-    return atEnd;\r
-  }\r
-\r
-  public final int getOffset() {\r
-    return myOffset;\r
-  }\r
-\r
-  public final int getLength() {\r
-    return myLength;\r
-  }\r
-\r
-  public final int getLineSeparatorLength() {\r
-    return myLineSeparatorLength;\r
-  }\r
-\r
-  public void advance() {\r
-    int i = myOffset + myLength + myLineSeparatorLength;\r
-    final int textLength = myText.length();\r
-    if (i >= textLength){\r
-      atEnd = true;\r
-      return;\r
-    }\r
-    while(i < textLength){\r
-      char c = myText.charAt(i);\r
-      if (c == '\r' || c == '\n') break;\r
-      i++;\r
-    }\r
-\r
-    myOffset = myOffset + myLength + myLineSeparatorLength;\r
-    myLength = i - myOffset;\r
-\r
-    myLineSeparatorLength = 0;\r
-    if (i == textLength) return;\r
-\r
-    char first = myText.charAt(i);\r
-    if (first == '\r' || first == '\n') {\r
-      myLineSeparatorLength = 1;\r
-    }\r
-\r
-    i++;\r
-    if (i == textLength) return;\r
-\r
-    char second = myText.charAt(i);\r
-    if (first == '\r' && second == '\n') {\r
-      myLineSeparatorLength = 2;\r
-    }\r
-  }\r
-}\r
+/*
+ * Copyright 2000-2009 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 com.intellij.openapi.util.text;
+
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.text.CharArrayCharSequence;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class LineTokenizer {
+  private int myOffset = 0;
+  private int myLength = 0;
+  private int myLineSeparatorLength = 0;
+  private boolean atEnd = false;
+  private CharSequence myText;
+
+  public static String[] tokenize(CharSequence chars, boolean includeSeparators) {
+    return tokenize(chars, includeSeparators, true);
+  }
+
+  private static String[] tokenize(final CharSequence chars, final boolean includeSeparators, final boolean skipLastEmptyLine) {
+    if (chars == null || chars.length() == 0){
+      return ArrayUtil.EMPTY_STRING_ARRAY;
+    }
+
+    LineTokenizer tokenizer = new LineTokenizer(chars);
+    List<String> lines = new ArrayList<String>();
+    while(!tokenizer.atEnd()){
+      int offset = tokenizer.getOffset();
+      String line;
+      if (includeSeparators){
+        line = chars.subSequence(offset, offset + tokenizer.getLength() + tokenizer.getLineSeparatorLength()).toString();
+      }
+      else{
+        line = chars.subSequence(offset, offset + tokenizer.getLength()).toString();
+      }
+      lines.add(line);
+      tokenizer.advance();
+    }
+
+    if (!skipLastEmptyLine && stringEdnsWithSeparator(tokenizer)) lines.add("");
+
+    return lines.toArray(new String[lines.size()]);
+  }
+
+  public static int calcLineCount(final CharSequence chars, final boolean skipLastEmptyLine) {
+    int lineCount = 0;
+    if (chars != null && chars.length() != 0) {
+      final LineTokenizer tokenizer = new LineTokenizer(chars);
+      while (!tokenizer.atEnd()) {
+        lineCount += 1;
+        tokenizer.advance();
+      }
+      if (!skipLastEmptyLine && stringEdnsWithSeparator(tokenizer)) {
+        lineCount += 1;
+      }
+    }
+    return lineCount;
+  }
+
+  public static String[] tokenize(char[] chars, boolean includeSeparators) {
+    return tokenize(chars, includeSeparators, true);
+  }
+
+  public static String[] tokenize(char[] chars, boolean includeSeparators, boolean skipLastEmptyLine) {
+    return tokenize(chars, 0, chars.length, includeSeparators, skipLastEmptyLine);
+  }
+
+  public static String[] tokenize(char[] chars, int startOffset, int endOffset, boolean includeSeparators,
+                                  boolean skipLastEmptyLine) {
+    return tokenize(new CharArrayCharSequence(chars, startOffset, endOffset), includeSeparators, skipLastEmptyLine);
+  }
+
+  private static boolean stringEdnsWithSeparator(LineTokenizer tokenizer) {
+    return tokenizer.getLineSeparatorLength() > 0;
+  }
+
+  public static String[] tokenize(char[] chars, int startOffset, int endOffset, boolean includeSeparators) {
+    return tokenize(chars, startOffset, endOffset, includeSeparators, true);
+  }
+
+  public LineTokenizer(CharSequence text) {
+    myText = text;
+    myOffset = 0;
+    advance();
+  }
+
+  public LineTokenizer(char[] text, int startOffset, int endOffset) {
+    this(new CharArrayCharSequence(text, startOffset, endOffset));
+  }
+
+  public final boolean atEnd() {
+    return atEnd;
+  }
+
+  public final int getOffset() {
+    return myOffset;
+  }
+
+  public final int getLength() {
+    return myLength;
+  }
+
+  public final int getLineSeparatorLength() {
+    return myLineSeparatorLength;
+  }
+
+  public void advance() {
+    int i = myOffset + myLength + myLineSeparatorLength;
+    final int textLength = myText.length();
+    if (i >= textLength){
+      atEnd = true;
+      return;
+    }
+    while(i < textLength){
+      char c = myText.charAt(i);
+      if (c == '\r' || c == '\n') break;
+      i++;
+    }
+
+    myOffset = myOffset + myLength + myLineSeparatorLength;
+    myLength = i - myOffset;
+
+    myLineSeparatorLength = 0;
+    if (i == textLength) return;
+
+    char first = myText.charAt(i);
+    if (first == '\r' || first == '\n') {
+      myLineSeparatorLength = 1;
+    }
+
+    i++;
+    if (i == textLength) return;
+
+    char second = myText.charAt(i);
+    if (first == '\r' && second == '\n') {
+      myLineSeparatorLength = 2;
+    }
+  }
+}