@Override
    public void layoutContainer(final Container parent) {
      final int componentCount = parent.getComponentCount();
      if (componentCount == 0) return;
      final EditorEx history = myHistoryViewer;
      final EditorEx editor = componentCount == 2 ? myConsoleEditor : null;

      if (editor == null) {
        parent.getComponent(0).setBounds(parent.getBounds());
        return;
      }

      final Dimension panelSize = parent.getSize();
      if (panelSize.getHeight() <= 0) return;
      final Dimension historySize = history.getContentSize();
      final Dimension editorSize = editor.getContentSize();
      final Dimension newEditorSize = new Dimension();

      // deal with width
      final int width = Math.max(editorSize.width, historySize.width);
      newEditorSize.width = width + editor.getScrollPane().getHorizontalScrollBar().getHeight();
      history.getSoftWrapModel().forceAdditionalColumnsUsage();
      editor
          .getSettings()
          .setAdditionalColumnsCount(
              2 + (width - editorSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, editor));
      history
          .getSettings()
          .setAdditionalColumnsCount(
              2 + (width - historySize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, history));

      // deal with height
      if (historySize.width == 0) historySize.height = 0;
      final int minHistorySize =
          historySize.height > 0
              ? 2 * history.getLineHeight() + (myShowSeparatorLine ? SEPARATOR_THICKNESS : 0)
              : 0;
      final int minEditorSize = editor.isViewer() ? 0 : editor.getLineHeight();
      final int editorPreferred =
          editor.isViewer() ? 0 : Math.max(minEditorSize, editorSize.height);
      final int historyPreferred = Math.max(minHistorySize, historySize.height);
      if (panelSize.height < minEditorSize) {
        newEditorSize.height = panelSize.height;
      } else if (panelSize.height < editorPreferred) {
        newEditorSize.height = panelSize.height - minHistorySize;
      } else if (panelSize.height < editorPreferred + historyPreferred) {
        newEditorSize.height = editorPreferred;
      } else {
        newEditorSize.height = editorPreferred == 0 ? 0 : panelSize.height - historyPreferred;
      }
      final Dimension newHistorySize =
          new Dimension(width, panelSize.height - newEditorSize.height);

      // apply
      editor
          .getComponent()
          .setBounds(0, newHistorySize.height, panelSize.width, newEditorSize.height);
      myForceScrollToEnd.compareAndSet(false, shouldScrollHistoryToEnd());
      history.getComponent().setBounds(0, 0, panelSize.width, newHistorySize.height);
    }
  private int calcOffset(int col, int lineNumber, int lineStartOffset) {
    if (myDocumentWindow.getTextLength() == 0) return 0;

    int end = myDocumentWindow.getLineEndOffset(lineNumber);

    CharSequence text = myDocumentWindow.getCharsSequence();
    return EditorUtil.calcOffset(
        this, text, lineStartOffset, end, col, EditorUtil.getTabSize(myDelegate), null);
  }
  private int calcLogicalColumnNumber(int offsetInLine, int lineNumber, int lineStartOffset) {
    if (myDocumentWindow.getTextLength() == 0) return 0;

    if (offsetInLine == 0) return 0;
    int end = myDocumentWindow.getLineEndOffset(lineNumber);
    if (offsetInLine > end - lineStartOffset) offsetInLine = end - lineStartOffset;

    CharSequence text = myDocumentWindow.getCharsSequence();
    return EditorUtil.calcColumnNumber(
        this,
        text,
        lineStartOffset,
        lineStartOffset + offsetInLine,
        EditorUtil.getTabSize(myDelegate));
  }
  public void testSoftWrapsRecalculationInASpecificCase() throws Exception {
    configureFromFileText(
        getTestName(false) + ".java",
        "<selection>class Foo {\n"
            + "\t@Override\n"
            + "\tpublic boolean equals(Object other) {\n"
            + "\t\treturn this == other;\n"
            + "\t}\n"
            + "}</selection>");
    CodeFoldingManager.getInstance(ourProject).buildInitialFoldings(myEditor);
    configureSoftWraps(32);

    // verify initial state
    assertEquals(4, EditorUtil.getTabSize(myEditor));
    assertEquals(
        "[FoldRegion +(59:64), placeholder=' { ', FoldRegion +(85:88), placeholder=' }']",
        myEditor.getFoldingModel().toString());
    verifySoftWrapPositions(52, 85);

    Document document = myEditor.getDocument();
    for (int i = document.getLineCount() - 1; i >= 0; i--) {
      document.insertString(document.getLineStartOffset(i), "//");
    }

    verifySoftWrapPositions(58, 93);
  }
  /**
   * Validates that content of the editor as well as caret and selection matches one specified in
   * data file that should be formed with the same format as one used in configureByFile
   *
   * @param message - this check specific message. Added to text, caret position, selection
   *     checking. May be null
   * @param filePath - relative path from %IDEA_INSTALLATION_HOME%/testData/
   * @param ignoreTrailingSpaces - whether trailing spaces in editor in data file should be stripped
   *     prior to comparing.
   */
  protected void checkResultByFile(
      @Nullable String message,
      @TestDataFile @NotNull String filePath,
      final boolean ignoreTrailingSpaces) {
    bringRealEditorBack();

    getProject().getComponent(PostprocessReformattingAspect.class).doPostponedFormatting();
    if (ignoreTrailingSpaces) {
      final Editor editor = myEditor;
      TrailingSpacesStripper.stripIfNotCurrentLine(editor.getDocument(), false);
      EditorUtil.fillVirtualSpaceUntilCaret(editor);
    }

    PsiDocumentManager.getInstance(getProject()).commitAllDocuments();

    String fullPath = getTestDataPath() + filePath;

    File ioFile = new File(fullPath);

    assertTrue(getMessage("Cannot find file " + fullPath, message), ioFile.exists());
    String fileText = null;
    try {
      fileText = FileUtil.loadFile(ioFile, CharsetToolkit.UTF8_CHARSET);
    } catch (IOException e) {
      LOG.error(e);
    }
    checkResultByText(
        message,
        StringUtil.convertLineSeparators(fileText),
        ignoreTrailingSpaces,
        getTestDataPath() + "/" + filePath);
  }
  public void testSoftWrapToHardWrapConversion() throws IOException {
    String text =
        "this is line 1\n"
            + "this is line 2\n"
            + "this is line 3\n"
            + "this is line 4\n"
            + "this is line 5";

    init(71, text, 10);
    VisualPosition changePosition = new VisualPosition(1, 0);
    myEditor.getCaretModel().moveToVisualPosition(changePosition);

    int logicalLinesBefore = myEditor.offsetToLogicalPosition(text.length()).line;
    int offsetBefore = myEditor.getCaretModel().getOffset();

    LogicalPosition logicalPositionBefore = myEditor.visualToLogicalPosition(changePosition);
    assertEquals(1, EditorUtil.getSoftWrapCountAfterLineStart(myEditor, logicalPositionBefore));
    assertTrue(logicalPositionBefore.column > 0);

    SoftWrap softWrap = getSoftWrapModel().getSoftWrap(offsetBefore);
    assertNotNull(softWrap);

    type('a');

    LogicalPosition logicalPositionAfter = myEditor.visualToLogicalPosition(changePosition);
    assertEquals(new LogicalPosition(1, 0, 0, 0, 0, 0, 0), logicalPositionAfter);
    assertEquals(
        offsetBefore + softWrap.getText().length() + 1, myEditor.getCaretModel().getOffset());
    assertEquals(logicalLinesBefore + 1, myEditor.offsetToLogicalPosition(text.length()).line);
  }
  /**
   * Called on editor settings change. Current model is expected to drop all cached information
   * about the settings if any.
   */
  public void reinitSettings() {
    boolean softWrapsUsedBefore = myUseSoftWraps;
    myUseSoftWraps = areSoftWrapsEnabledInEditor();

    int tabWidthBefore = myTabWidth;
    myTabWidth = EditorUtil.getTabSize(myEditor);

    boolean fontsChanged = false;
    if (!myFontPreferences.equals(myEditor.getColorsScheme().getFontPreferences())
        && myEditorTextRepresentationHelper instanceof DefaultEditorTextRepresentationHelper) {
      fontsChanged = true;
      myEditor.getColorsScheme().getFontPreferences().copyTo(myFontPreferences);
      ((DefaultEditorTextRepresentationHelper) myEditorTextRepresentationHelper)
          .clearSymbolWidthCache();
      myPainter.reinit();
    }

    if ((myUseSoftWraps ^ softWrapsUsedBefore)
        || (tabWidthBefore >= 0 && myTabWidth != tabWidthBefore)
        || fontsChanged) {
      myApplianceManager.reset();
      myDeferredFoldRegions.clear();
      myStorage.removeAll();
      myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
    }
  }
 public static void setEditorVisibleSize(Editor editor, int widthInChars, int heightInChars) {
   Dimension size =
       new Dimension(
           widthInChars * EditorUtil.getSpaceWidth(Font.PLAIN, editor),
           heightInChars * editor.getLineHeight());
   ((EditorEx) editor).getScrollPane().getViewport().setExtentSize(size);
 }
  @Nullable
  Font getFontAbleToDisplay(LookupElementPresentation p) {
    String sampleString = p.getItemText() + p.getTailText() + p.getTypeText();

    // assume a single font can display all lookup item chars
    Set<Font> fonts = ContainerUtil.newHashSet();
    for (int i = 0; i < sampleString.length(); i++) {
      fonts.add(
          EditorUtil.fontForChar(sampleString.charAt(i), Font.PLAIN, myLookup.getEditor())
              .getFont());
    }

    eachFont:
    for (Font font : fonts) {
      if (font.equals(myNormalFont)) continue;

      for (int i = 0; i < sampleString.length(); i++) {
        if (!font.canDisplay(sampleString.charAt(i))) {
          continue eachFont;
        }
      }
      return font;
    }
    return null;
  }
Exemple #10
0
    void execute(BrowseMode browseMode) {
      myBrowseMode = browseMode;

      Document document = myEditor.getDocument();
      final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
      if (file == null) return;
      PsiDocumentManager.getInstance(myProject).commitAllDocuments();

      if (EditorUtil.inVirtualSpace(myEditor, myPosition)) {
        return;
      }

      final int offset = myEditor.logicalPositionToOffset(myPosition);

      int selStart = myEditor.getSelectionModel().getSelectionStart();
      int selEnd = myEditor.getSelectionModel().getSelectionEnd();

      if (offset >= selStart && offset < selEnd) return;

      ProgressIndicatorUtils.scheduleWithWriteActionPriority(
          myProgress,
          new ReadTask() {
            @Override
            public void computeInReadAction(@NotNull ProgressIndicator indicator) {
              doExecute(file, offset);
            }

            @Override
            public void onCanceled(@NotNull ProgressIndicator indicator) {}
          });
    }
  private boolean isInsideSoftWrap(@NotNull VisualPosition visual, boolean countBeforeSoftWrap) {
    if (!isSoftWrappingEnabled()) {
      return false;
    }
    SoftWrapModel model = myEditor.getSoftWrapModel();
    if (!model.isSoftWrappingEnabled()) {
      return false;
    }
    LogicalPosition logical = myEditor.visualToLogicalPosition(visual);
    int offset = myEditor.logicalPositionToOffset(logical);
    if (offset <= 0) {
      // Never expect to be here, just a defensive programming.
      return false;
    }

    SoftWrap softWrap = model.getSoftWrap(offset);
    if (softWrap == null) {
      return false;
    }

    // We consider visual positions that point after the last symbol before soft wrap and the first
    // symbol after soft wrap to not
    // belong to soft wrap-introduced virtual space.
    VisualPosition visualAfterSoftWrap = myEditor.offsetToVisualPosition(offset);
    if (visualAfterSoftWrap.line == visual.line && visualAfterSoftWrap.column <= visual.column) {
      return false;
    }

    if (myEditor.myUseNewRendering) {
      VisualPosition beforeSoftWrap = myEditor.offsetToVisualPosition(offset, true, true);
      return visual.line > beforeSoftWrap.line
          || visual.column > beforeSoftWrap.column
          || visual.column == beforeSoftWrap.column && countBeforeSoftWrap;
    } else {
      VisualPosition visualBeforeSoftWrap = myEditor.offsetToVisualPosition(offset - 1);
      int x = 0;
      LogicalPosition logLineStart =
          myEditor.visualToLogicalPosition(new VisualPosition(visualBeforeSoftWrap.line, 0));
      if (logLineStart.softWrapLinesOnCurrentLogicalLine > 0) {
        int offsetLineStart = myEditor.logicalPositionToOffset(logLineStart);
        softWrap = model.getSoftWrap(offsetLineStart);
        if (softWrap != null) {
          x = softWrap.getIndentInPixels();
        }
      }
      int width =
          EditorUtil.textWidthInColumns(
              myEditor, myEditor.getDocument().getCharsSequence(), offset - 1, offset, x);
      int softWrapStartColumn = visualBeforeSoftWrap.column + width;
      if (visual.line > visualBeforeSoftWrap.line) {
        return true;
      }
      return countBeforeSoftWrap
          ? visual.column >= softWrapStartColumn
          : visual.column > softWrapStartColumn;
    }
  }
  /**
   * @return 1-based column index where tabs are treated as single characters. External tools don't
   *     know about IDEA's tab size.
   */
  protected static String getColumnNumber(Editor editor, LogicalPosition pos) {
    if (EditorUtil.inVirtualSpace(editor, pos)) {
      return String.valueOf(pos.column + 1);
    }

    int offset = editor.logicalPositionToOffset(pos);
    int lineStart =
        editor.getDocument().getLineStartOffset(editor.getDocument().getLineNumber(offset));
    return String.valueOf(offset - lineStart + 1);
  }
 private int wrapPositionForTabbedTextWithoutOptimization(
     @NotNull Editor editor,
     @NotNull CharSequence text,
     int spaceSize,
     int startLineOffset,
     int endLineOffset,
     int targetRangeEndOffset) {
   int width = 0;
   int x = 0;
   int newX;
   int symbolWidth;
   int result = Integer.MAX_VALUE;
   boolean wrapLine = false;
   for (int i = startLineOffset; i < Math.min(endLineOffset, targetRangeEndOffset); i++) {
     char c = text.charAt(i);
     switch (c) {
       case '\t':
         newX = EditorUtil.nextTabStop(x, editor);
         int diffInPixels = newX - x;
         symbolWidth = diffInPixels / spaceSize;
         if (diffInPixels % spaceSize > 0) {
           symbolWidth++;
         }
         break;
       default:
         newX = x + EditorUtil.charWidth(c, Font.PLAIN, editor);
         symbolWidth = 1;
     }
     if (width + symbolWidth + FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS
             >= mySettings.RIGHT_MARGIN
         && (Math.min(endLineOffset, targetRangeEndOffset) - i)
             >= FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS) {
       result = i - 1;
     }
     if (width + symbolWidth >= mySettings.RIGHT_MARGIN) {
       wrapLine = true;
       break;
     }
     x = newX;
     width += symbolWidth;
   }
   return wrapLine ? result : -1;
 }
  @NotNull
  public static <T extends PsiElement> JBPopup getPsiElementPopup(
      @NotNull T[] elements,
      @NotNull final PsiElementListCellRenderer<T> renderer,
      @Nullable final String title,
      @NotNull final PsiElementProcessor<T> processor,
      @Nullable final T selection) {
    final JList list =
        new JBListWithHintProvider(elements) {
          @Nullable
          @Override
          protected PsiElement getPsiElementForHint(Object selectedValue) {
            return (PsiElement) selectedValue;
          }
        };
    list.setCellRenderer(renderer);

    list.setFont(EditorUtil.getEditorFont());

    if (selection != null) {
      list.setSelectedValue(selection, true);
    }

    final Runnable runnable =
        () -> {
          int[] ids = list.getSelectedIndices();
          if (ids == null || ids.length == 0) return;
          for (Object element : list.getSelectedValues()) {
            if (element != null) {
              processor.execute((T) element);
            }
          }
        };

    PopupChooserBuilder builder = new PopupChooserBuilder(list);
    if (title != null) {
      builder.setTitle(title);
    }
    renderer.installSpeedSearch(builder, true);

    JBPopup popup = builder.setItemChoosenCallback(runnable).createPopup();

    builder.getScrollPane().setBorder(null);
    builder.getScrollPane().setViewportBorder(null);

    return popup;
  }
  public void moveCaretRelatively(
      int columnShift,
      int lineShift,
      boolean withSelection,
      boolean blockSelection,
      boolean scrollToCaret) {
    assertIsDispatchThread();
    SelectionModel selectionModel = myEditor.getSelectionModel();
    int selectionStart = selectionModel.getLeadSelectionOffset();
    LogicalPosition blockSelectionStart =
        selectionModel.hasBlockSelection() ? selectionModel.getBlockStart() : getLogicalPosition();
    EditorSettings editorSettings = myEditor.getSettings();
    VisualPosition visualCaret = getVisualPosition();

    int desiredX = myDesiredX;
    if (columnShift == 0) {
      if (myDesiredX < 0) {
        desiredX = myEditor.visualPositionToXY(visualCaret).x;
      }
    } else {
      myDesiredX = desiredX = -1;
    }

    int newLineNumber = visualCaret.line + lineShift;
    int newColumnNumber = visualCaret.column + columnShift;
    if (desiredX >= 0 && !ApplicationManager.getApplication().isUnitTestMode()) {
      newColumnNumber =
          myEditor.xyToVisualPosition(
                  new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight()))
              .column;
    }

    Document document = myEditor.getDocument();
    if (!editorSettings.isVirtualSpace()
        && columnShift == 0
        && getLogicalPosition().softWrapLinesOnCurrentLogicalLine <= 0) {
      newColumnNumber = myEditor.getLastColumnNumber();
    } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == 1) {
      int lastLine = document.getLineCount() - 1;
      if (lastLine < 0) lastLine = 0;
      if (EditorModificationUtil.calcAfterLineEnd(myEditor) >= 0
          && newLineNumber
              < myEditor.logicalToVisualPosition(new LogicalPosition(lastLine, 0)).line) {
        newColumnNumber = 0;
        newLineNumber++;
      }
    } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == -1) {
      if (newColumnNumber < 0 && newLineNumber > 0) {
        newLineNumber--;
        newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber);
      }
    }

    if (newColumnNumber < 0) newColumnNumber = 0;

    // There is a possible case that caret is located at the first line and user presses 'Shift+Up'.
    // We want to select all text
    // from the document start to the current caret position then. So, we have a dedicated flag for
    // tracking that.
    boolean selectToDocumentStart = false;
    if (newLineNumber < 0) {
      selectToDocumentStart = true;
      newLineNumber = 0;

      // We want to move caret to the first column if it's already located at the first line and
      // 'Up' is pressed.
      newColumnNumber = 0;
      desiredX = -1;
    }

    VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber);
    int lastColumnNumber = newColumnNumber;
    if (!editorSettings.isCaretInsideTabs() && !myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
      LogicalPosition log =
          myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber));
      int offset = myEditor.logicalPositionToOffset(log);
      if (offset >= document.getTextLength()) {
        int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength()).column;
        // We want to move caret to the last column if if it's located at the last line and 'Down'
        // is pressed.
        newColumnNumber = lastColumnNumber = Math.max(lastOffsetColumn, newColumnNumber);
        desiredX = -1;
      }
      CharSequence text = document.getCharsSequence();
      if (offset >= 0 && offset < document.getTextLength()) {
        if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) {
          if (columnShift <= 0) {
            newColumnNumber = myEditor.offsetToVisualPosition(offset).column;
          } else {
            SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1);
            // There is a possible case that tabulation symbol is the last document symbol
            // represented on a visual line before
            // soft wrap. We can't just use column from 'offset + 1' because it would point on a
            // next visual line.
            if (softWrap == null) {
              newColumnNumber = myEditor.offsetToVisualPosition(offset + 1).column;
            } else {
              newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber);
            }
          }
        }
      }
    }

    pos = new VisualPosition(newLineNumber, newColumnNumber);
    if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
      LogicalPosition logical = myEditor.visualToLogicalPosition(pos);
      int softWrapOffset = myEditor.logicalPositionToOffset(logical);
      if (columnShift >= 0) {
        moveToOffset(softWrapOffset);
      } else {
        int line = myEditor.offsetToVisualLine(softWrapOffset - 1);
        moveToVisualPosition(
            new VisualPosition(line, EditorUtil.getLastVisualLineColumnNumber(myEditor, line)));
      }
    } else {
      moveToVisualPosition(pos);
      if (!editorSettings.isVirtualSpace() && columnShift == 0) {
        myEditor.setLastColumnNumber(lastColumnNumber);
      }
    }

    if (withSelection) {
      if (blockSelection) {
        selectionModel.setBlockSelection(blockSelectionStart, getLogicalPosition());
      } else {
        if (selectToDocumentStart) {
          selectionModel.setSelection(selectionStart, 0);
        } else if (pos.line >= myEditor.getVisibleLineCount()) {
          if (selectionStart < document.getTextLength()) {
            selectionModel.setSelection(selectionStart, document.getTextLength());
          }
        } else {
          selectionModel.setSelection(selectionStart, getVisualPosition(), getOffset());
        }
      }
    } else {
      selectionModel.removeSelection();
    }

    if (scrollToCaret) {
      myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
    }

    if (desiredX >= 0) {
      myDesiredX = desiredX;
    }

    EditorActionUtil.selectNonexpandableFold(myEditor);
  }
  public void doWrapLongLinesIfNecessary(
      @NotNull final Editor editor,
      @NotNull final Project project,
      @NotNull Document document,
      int startOffset,
      int endOffset) {
    // Normalization.
    int startOffsetToUse = Math.min(document.getTextLength(), Math.max(0, startOffset));
    int endOffsetToUse = Math.min(document.getTextLength(), Math.max(0, endOffset));

    LineWrapPositionStrategy strategy = LanguageLineWrapPositionStrategy.INSTANCE.forEditor(editor);
    CharSequence text = document.getCharsSequence();
    int startLine = document.getLineNumber(startOffsetToUse);
    int endLine = document.getLineNumber(Math.max(0, endOffsetToUse - 1));
    int maxLine = Math.min(document.getLineCount(), endLine + 1);
    int tabSize = EditorUtil.getTabSize(editor);
    if (tabSize <= 0) {
      tabSize = 1;
    }
    int spaceSize = EditorUtil.getSpaceWidth(Font.PLAIN, editor);
    int[] shifts = new int[2];
    // shifts[0] - lines shift.
    // shift[1] - offset shift.

    for (int line = startLine; line < maxLine; line++) {
      int startLineOffset = document.getLineStartOffset(line);
      int endLineOffset = document.getLineEndOffset(line);
      final int preferredWrapPosition =
          calculatePreferredWrapPosition(
              editor, text, tabSize, spaceSize, startLineOffset, endLineOffset, endOffsetToUse);

      if (preferredWrapPosition < 0 || preferredWrapPosition >= endLineOffset) {
        continue;
      }
      if (preferredWrapPosition >= endOffsetToUse) {
        return;
      }

      // We know that current line exceeds right margin if control flow reaches this place, so, wrap
      // it.
      int wrapOffset =
          strategy.calculateWrapPosition(
              document,
              editor.getProject(),
              Math.max(startLineOffset, startOffsetToUse),
              Math.min(endLineOffset, endOffsetToUse),
              preferredWrapPosition,
              false,
              false);
      if (wrapOffset < 0 // No appropriate wrap position is found.
          // No point in splitting line when its left part contains only white spaces, example:
          //    line start -> |                   | <- right margin
          //                  |   aaaaaaaaaaaaaaaa|aaaaaaaaaaaaaaaaaaaa() <- don't want to wrap this
          // line even if it exceeds right margin
          || CharArrayUtil.shiftBackward(text, startLineOffset, wrapOffset - 1, " \t")
              < startLineOffset) {
        continue;
      }

      // Move caret to the target position and emulate pressing <enter>.
      editor.getCaretModel().moveToOffset(wrapOffset);
      emulateEnter(editor, project, shifts);

      // We know that number of lines is just increased, hence, update the data accordingly.
      maxLine += shifts[0];
      endOffsetToUse += shifts[1];
    }
  }
  @Override
  public void invoke(
      @NotNull Project project,
      @NotNull Editor editor,
      @NotNull Caret caret,
      @NotNull PsiFile file) {
    if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
    myProject = project;
    myEditor = editor;
    myCaret = caret;
    myFile = file;

    myDocument = editor.getDocument();

    if (!FileDocumentManager.getInstance().requestWriting(myDocument, project)) {
      return;
    }
    FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.block");
    final Commenter commenter = findCommenter(myFile, myEditor, caret);
    if (commenter == null) return;

    final String prefix;
    final String suffix;

    if (commenter instanceof SelfManagingCommenter) {
      final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter) commenter;
      mySelfManagedCommenterData =
          selfManagingCommenter.createBlockCommentingState(
              caret.getSelectionStart(), caret.getSelectionEnd(), myDocument, myFile);

      if (mySelfManagedCommenterData == null) {
        mySelfManagedCommenterData = SelfManagingCommenter.EMPTY_STATE;
      }

      prefix =
          selfManagingCommenter.getBlockCommentPrefix(
              caret.getSelectionStart(), myDocument, mySelfManagedCommenterData);
      suffix =
          selfManagingCommenter.getBlockCommentSuffix(
              caret.getSelectionEnd(), myDocument, mySelfManagedCommenterData);
    } else {
      prefix = commenter.getBlockCommentPrefix();
      suffix = commenter.getBlockCommentSuffix();
    }

    if (prefix == null || suffix == null) return;

    TextRange commentedRange = findCommentedRange(commenter);
    if (commentedRange != null) {
      final int commentStart = commentedRange.getStartOffset();
      final int commentEnd = commentedRange.getEndOffset();
      int selectionStart = commentStart;
      int selectionEnd = commentEnd;
      if (myCaret.hasSelection()) {
        selectionStart = myCaret.getSelectionStart();
        selectionEnd = myCaret.getSelectionEnd();
      }
      if ((commentStart < selectionStart || commentStart >= selectionEnd)
          && (commentEnd <= selectionStart || commentEnd > selectionEnd)) {
        commentRange(selectionStart, selectionEnd, prefix, suffix, commenter);
      } else {
        uncommentRange(commentedRange, trim(prefix), trim(suffix), commenter);
      }
    } else {
      if (myCaret.hasSelection()) {
        int selectionStart = myCaret.getSelectionStart();
        int selectionEnd = myCaret.getSelectionEnd();
        if (commenter instanceof IndentedCommenter) {
          final Boolean value = ((IndentedCommenter) commenter).forceIndentedLineComment();
          if (value != null && value == Boolean.TRUE) {
            selectionStart =
                myDocument.getLineStartOffset(myDocument.getLineNumber(selectionStart));
            selectionEnd = myDocument.getLineEndOffset(myDocument.getLineNumber(selectionEnd));
          }
        }
        commentRange(selectionStart, selectionEnd, prefix, suffix, commenter);
      } else {
        EditorUtil.fillVirtualSpaceUntilCaret(editor);
        int caretOffset = myCaret.getOffset();
        if (commenter instanceof IndentedCommenter) {
          final Boolean value = ((IndentedCommenter) commenter).forceIndentedLineComment();
          if (value != null && value == Boolean.TRUE) {
            final int lineNumber = myDocument.getLineNumber(caretOffset);
            final int start = myDocument.getLineStartOffset(lineNumber);
            final int end = myDocument.getLineEndOffset(lineNumber);
            commentRange(start, end, prefix, suffix, commenter);
            return;
          }
        }
        myDocument.insertString(caretOffset, prefix + suffix);
        myCaret.moveToOffset(caretOffset + prefix.length());
      }
    }
  }
  private void show(
      @NotNull final Project project,
      @NotNull Editor editor,
      @NotNull PsiFile file,
      @NotNull final GotoData gotoData) {
    final PsiElement[] targets = gotoData.targets;
    final List<AdditionalAction> additionalActions = gotoData.additionalActions;

    if (targets.length == 0 && additionalActions.isEmpty()) {
      HintManager.getInstance().showErrorHint(editor, getNotFoundMessage(project, editor, file));
      return;
    }

    if (targets.length == 1 && additionalActions.isEmpty()) {
      Navigatable descriptor =
          targets[0] instanceof Navigatable
              ? (Navigatable) targets[0]
              : EditSourceUtil.getDescriptor(targets[0]);
      if (descriptor != null && descriptor.canNavigate()) {
        navigateToElement(descriptor);
      }
      return;
    }

    for (PsiElement eachTarget : targets) {
      gotoData.renderers.put(eachTarget, createRenderer(gotoData, eachTarget));
    }

    final String name = ((PsiNamedElement) gotoData.source).getName();
    boolean finished = gotoData.listUpdaterTask == null || gotoData.listUpdaterTask.isFinished();
    final String title = getChooserTitle(gotoData.source, name, targets.length, finished);

    if (shouldSortTargets()) {
      Arrays.sort(targets, createComparator(gotoData.renderers, gotoData));
    }

    List<Object> allElements = new ArrayList<Object>(targets.length + additionalActions.size());
    Collections.addAll(allElements, targets);
    allElements.addAll(additionalActions);

    final JBListWithHintProvider list =
        new JBListWithHintProvider(new CollectionListModel<Object>(allElements)) {
          @Override
          protected PsiElement getPsiElementForHint(final Object selectedValue) {
            return selectedValue instanceof PsiElement ? (PsiElement) selectedValue : null;
          }
        };

    list.setFont(EditorUtil.getEditorFont());

    list.setCellRenderer(
        new DefaultListCellRenderer() {
          @Override
          public Component getListCellRendererComponent(
              JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            if (value == null)
              return super.getListCellRendererComponent(
                  list, value, index, isSelected, cellHasFocus);
            if (value instanceof AdditionalAction) {
              return myActionElementRenderer.getListCellRendererComponent(
                  list, value, index, isSelected, cellHasFocus);
            }
            PsiElementListCellRenderer renderer = getRenderer(value, gotoData.renderers, gotoData);
            return renderer.getListCellRendererComponent(
                list, value, index, isSelected, cellHasFocus);
          }
        });

    final Runnable runnable =
        () -> {
          int[] ids = list.getSelectedIndices();
          if (ids == null || ids.length == 0) return;
          Object[] selectedElements = list.getSelectedValues();
          for (Object element : selectedElements) {
            if (element instanceof AdditionalAction) {
              ((AdditionalAction) element).execute();
            } else {
              Navigatable nav =
                  element instanceof Navigatable
                      ? (Navigatable) element
                      : EditSourceUtil.getDescriptor((PsiElement) element);
              try {
                if (nav != null && nav.canNavigate()) {
                  navigateToElement(nav);
                }
              } catch (IndexNotReadyException e) {
                DumbService.getInstance(project)
                    .showDumbModeNotification("Navigation is not available while indexing");
              }
            }
          }
        };

    final PopupChooserBuilder builder = new PopupChooserBuilder(list);
    builder.setFilteringEnabled(
        o -> {
          if (o instanceof AdditionalAction) {
            return ((AdditionalAction) o).getText();
          }
          return getRenderer(o, gotoData.renderers, gotoData).getElementText((PsiElement) o);
        });

    final Ref<UsageView> usageView = new Ref<UsageView>();
    final JBPopup popup =
        builder
            .setTitle(title)
            .setItemChoosenCallback(runnable)
            .setMovable(true)
            .setCancelCallback(
                () -> {
                  HintUpdateSupply.hideHint(list);
                  final ListBackgroundUpdaterTask task = gotoData.listUpdaterTask;
                  if (task != null) {
                    task.cancelTask();
                  }
                  return true;
                })
            .setCouldPin(
                popup1 -> {
                  usageView.set(
                      FindUtil.showInUsageView(
                          gotoData.source,
                          gotoData.targets,
                          getFindUsagesTitle(gotoData.source, name, gotoData.targets.length),
                          project));
                  popup1.cancel();
                  return false;
                })
            .setAdText(getAdText(gotoData.source, targets.length))
            .createPopup();

    builder.getScrollPane().setBorder(null);
    builder.getScrollPane().setViewportBorder(null);

    if (gotoData.listUpdaterTask != null) {
      gotoData.listUpdaterTask.init((AbstractPopup) popup, list, usageView);
      ProgressManager.getInstance().run(gotoData.listUpdaterTask);
    }
    popup.showInBestPositionFor(editor);
  }
  public void moveToVisualPosition(@NotNull VisualPosition pos) {
    assertIsDispatchThread();
    validateCallContext();
    myDesiredX = -1;
    int column = pos.column;
    int line = pos.line;

    if (column < 0) column = 0;

    if (line < 0) line = 0;

    int lastLine = myEditor.getVisibleLineCount() - 1;
    if (lastLine <= 0) {
      lastLine = 0;
    }

    if (line > lastLine) {
      line = lastLine;
    }

    EditorSettings editorSettings = myEditor.getSettings();

    if (!editorSettings.isVirtualSpace() && line <= lastLine) {
      int lineEndColumn = EditorUtil.getLastVisualLineColumnNumber(myEditor, line);
      if (column > lineEndColumn) {
        column = lineEndColumn;
      }

      if (column < 0 && line > 0) {
        line--;
        column = EditorUtil.getLastVisualLineColumnNumber(myEditor, line);
      }
    }

    myVisibleCaret = new VisualPosition(line, column);

    VerticalInfo oldInfo = myCaretInfo;
    LogicalPosition oldPosition = myLogicalCaret;

    setCurrentLogicalCaret(myEditor.visualToLogicalPosition(myVisibleCaret));
    myOffset = myEditor.logicalPositionToOffset(myLogicalCaret);
    LOG.assertTrue(myOffset >= 0 && myOffset <= myEditor.getDocument().getTextLength());

    myVisualLineStart =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0)));
    myVisualLineEnd =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line + 1, 0)));

    ((FoldingModelImpl) myEditor.getFoldingModel()).flushCaretPosition();

    myEditor.setLastColumnNumber(myVisibleCaret.column);
    myEditor.updateCaretCursor();
    requestRepaint(oldInfo);

    if (oldPosition.column != myLogicalCaret.column || oldPosition.line != myLogicalCaret.line) {
      CaretEvent event = new CaretEvent(myEditor, oldPosition, myLogicalCaret);

      for (CaretListener listener : myCaretListeners) {
        listener.caretPositionChanged(event);
      }
    }
  }
  @Override
  public void apply() {
    initComponent();
    UISettings settings = UISettings.getInstance();
    int _fontSize = getIntValue(myComponent.myFontSizeCombo, settings.FONT_SIZE);
    int _presentationFontSize =
        getIntValue(myComponent.myPresentationModeFontSize, settings.PRESENTATION_MODE_FONT_SIZE);
    boolean shouldUpdateUI = false;
    String _fontFace = (String) myComponent.myFontCombo.getSelectedItem();
    LafManager lafManager = LafManager.getInstance();
    if (_fontSize != settings.FONT_SIZE || !settings.FONT_FACE.equals(_fontFace)) {
      settings.FONT_SIZE = _fontSize;
      settings.FONT_FACE = _fontFace;
      shouldUpdateUI = true;
    }

    if (_presentationFontSize != settings.PRESENTATION_MODE_FONT_SIZE) {
      settings.PRESENTATION_MODE_FONT_SIZE = _presentationFontSize;
      shouldUpdateUI = true;
    }

    if (!myComponent.myAntialiasingInIDE.getSelectedItem().equals(settings.IDE_AA_TYPE)) {
      settings.IDE_AA_TYPE = (AntialiasingType) myComponent.myAntialiasingInIDE.getSelectedItem();
      shouldUpdateUI = true;
    }

    if (!myComponent.myAntialiasingInEditor.getSelectedItem().equals(settings.EDITOR_AA_TYPE)) {
      settings.EDITOR_AA_TYPE =
          (AntialiasingType) myComponent.myAntialiasingInEditor.getSelectedItem();
      shouldUpdateUI = true;
    }

    settings.ANIMATE_WINDOWS = myComponent.myAnimateWindowsCheckBox.isSelected();
    boolean update =
        settings.SHOW_TOOL_WINDOW_NUMBERS != myComponent.myWindowShortcutsCheckBox.isSelected();
    settings.SHOW_TOOL_WINDOW_NUMBERS = myComponent.myWindowShortcutsCheckBox.isSelected();
    update |= settings.HIDE_TOOL_STRIPES != !myComponent.myShowToolStripesCheckBox.isSelected();
    settings.HIDE_TOOL_STRIPES = !myComponent.myShowToolStripesCheckBox.isSelected();
    update |= settings.SHOW_ICONS_IN_MENUS != myComponent.myCbDisplayIconsInMenu.isSelected();
    settings.SHOW_ICONS_IN_MENUS = myComponent.myCbDisplayIconsInMenu.isSelected();
    update |=
        settings.SHOW_MEMORY_INDICATOR != myComponent.myShowMemoryIndicatorCheckBox.isSelected();
    settings.SHOW_MEMORY_INDICATOR = myComponent.myShowMemoryIndicatorCheckBox.isSelected();
    update |= settings.ALLOW_MERGE_BUTTONS != myComponent.myAllowMergeButtons.isSelected();
    settings.ALLOW_MERGE_BUTTONS = myComponent.myAllowMergeButtons.isSelected();
    update |= settings.CYCLE_SCROLLING != myComponent.myCycleScrollingCheckBox.isSelected();
    settings.CYCLE_SCROLLING = myComponent.myCycleScrollingCheckBox.isSelected();
    if (settings.OVERRIDE_NONIDEA_LAF_FONTS != myComponent.myOverrideLAFFonts.isSelected()) {
      shouldUpdateUI = true;
    }
    settings.OVERRIDE_NONIDEA_LAF_FONTS = myComponent.myOverrideLAFFonts.isSelected();
    settings.MOVE_MOUSE_ON_DEFAULT_BUTTON =
        myComponent.myMoveMouseOnDefaultButtonCheckBox.isSelected();
    settings.HIDE_NAVIGATION_ON_FOCUS_LOSS =
        myComponent.myHideNavigationPopupsCheckBox.isSelected();
    settings.DND_WITH_PRESSED_ALT_ONLY = myComponent.myAltDNDCheckBox.isSelected();

    update |= settings.DISABLE_MNEMONICS != myComponent.myDisableMnemonics.isSelected();
    settings.DISABLE_MNEMONICS = myComponent.myDisableMnemonics.isSelected();

    update |= settings.USE_SMALL_LABELS_ON_TABS != myComponent.myUseSmallLabelsOnTabs.isSelected();
    settings.USE_SMALL_LABELS_ON_TABS = myComponent.myUseSmallLabelsOnTabs.isSelected();

    update |= settings.WIDESCREEN_SUPPORT != myComponent.myWidescreenLayoutCheckBox.isSelected();
    settings.WIDESCREEN_SUPPORT = myComponent.myWidescreenLayoutCheckBox.isSelected();

    update |= settings.LEFT_HORIZONTAL_SPLIT != myComponent.myLeftLayoutCheckBox.isSelected();
    settings.LEFT_HORIZONTAL_SPLIT = myComponent.myLeftLayoutCheckBox.isSelected();

    update |= settings.RIGHT_HORIZONTAL_SPLIT != myComponent.myRightLayoutCheckBox.isSelected();
    settings.RIGHT_HORIZONTAL_SPLIT = myComponent.myRightLayoutCheckBox.isSelected();

    update |=
        settings.NAVIGATE_TO_PREVIEW
            != (myComponent.myNavigateToPreviewCheckBox.isVisible()
                && myComponent.myNavigateToPreviewCheckBox.isSelected());
    settings.NAVIGATE_TO_PREVIEW = myComponent.myNavigateToPreviewCheckBox.isSelected();

    ColorBlindness blindness = myComponent.myColorBlindnessPanel.getColorBlindness();
    boolean updateEditorScheme = false;
    if (settings.COLOR_BLINDNESS != blindness) {
      settings.COLOR_BLINDNESS = blindness;
      update = true;
      ComponentsPackage.getStateStore(ApplicationManager.getApplication())
          .reloadState(DefaultColorSchemesManager.class);
      updateEditorScheme = true;
    }

    update |=
        settings.DISABLE_MNEMONICS_IN_CONTROLS
            != myComponent.myDisableMnemonicInControlsCheckBox.isSelected();
    settings.DISABLE_MNEMONICS_IN_CONTROLS =
        myComponent.myDisableMnemonicInControlsCheckBox.isSelected();

    update |=
        settings.SHOW_ICONS_IN_QUICK_NAVIGATION
            != myComponent.myHideIconsInQuickNavigation.isSelected();
    settings.SHOW_ICONS_IN_QUICK_NAVIGATION = myComponent.myHideIconsInQuickNavigation.isSelected();

    if (!Comparing.equal(
        myComponent.myLafComboBox.getSelectedItem(), lafManager.getCurrentLookAndFeel())) {
      final UIManager.LookAndFeelInfo lafInfo =
          (UIManager.LookAndFeelInfo) myComponent.myLafComboBox.getSelectedItem();
      if (lafManager.checkLookAndFeel(lafInfo)) {
        update = shouldUpdateUI = true;
        final boolean wasDarcula = UIUtil.isUnderDarcula();
        lafManager.setCurrentLookAndFeel(lafInfo);
        //noinspection SSBasedInspection
        SwingUtilities.invokeLater(
            new Runnable() {
              @Override
              public void run() {
                if (UIUtil.isUnderDarcula()) {
                  DarculaInstaller.install();
                } else if (wasDarcula) {
                  DarculaInstaller.uninstall();
                }
              }
            });
      }
    }

    if (shouldUpdateUI) {
      lafManager.updateUI();
    }

    if (WindowManagerEx.getInstanceEx().isAlphaModeSupported()) {
      int delay = -1;
      try {
        delay = Integer.parseInt(myComponent.myAlphaModeDelayTextField.getText());
      } catch (NumberFormatException ignored) {
      }
      float ratio = myComponent.myAlphaModeRatioSlider.getValue() / 100f;
      if (myComponent.myEnableAlphaModeCheckBox.isSelected() != settings.ENABLE_ALPHA_MODE
          || delay != -1 && delay != settings.ALPHA_MODE_DELAY
          || ratio != settings.ALPHA_MODE_RATIO) {
        update = true;
        settings.ENABLE_ALPHA_MODE = myComponent.myEnableAlphaModeCheckBox.isSelected();
        settings.ALPHA_MODE_DELAY = delay;
        settings.ALPHA_MODE_RATIO = ratio;
      }
    }
    int tooltipDelay = Math.min(myComponent.myInitialTooltipDelaySlider.getValue(), 5000);
    if (tooltipDelay != Registry.intValue("ide.tooltip.initialDelay")) {
      update = true;
      Registry.get("ide.tooltip.initialDelay").setValue(tooltipDelay);
    }

    if (update) {
      settings.fireUISettingsChanged();
    }
    myComponent.updateCombo();

    EditorUtil.reinitSettings();

    if (updateEditorScheme) {
      EditorColorsManagerImpl.schemeChangedOrSwitched();
    }
  }
  private void moveToLogicalPosition(LogicalPosition pos, boolean locateBeforeSoftWrap) {
    assertIsDispatchThread();
    myDesiredX = -1;
    validateCallContext();
    int column = pos.column;
    int line = pos.line;
    int softWrapLinesBefore = pos.softWrapLinesBeforeCurrentLogicalLine;
    int softWrapLinesCurrent = pos.softWrapLinesOnCurrentLogicalLine;
    int softWrapColumns = pos.softWrapColumnDiff;

    Document doc = myEditor.getDocument();

    if (column < 0) {
      column = 0;
      softWrapColumns = 0;
    }
    if (line < 0) {
      line = 0;
      softWrapLinesBefore = 0;
      softWrapLinesCurrent = 0;
    }

    int lineCount = doc.getLineCount();
    if (lineCount == 0) {
      line = 0;
    } else if (line > lineCount - 1) {
      line = lineCount - 1;
      softWrapLinesBefore = 0;
      softWrapLinesCurrent = 0;
    }

    EditorSettings editorSettings = myEditor.getSettings();

    if (!editorSettings.isVirtualSpace()
        && line < lineCount
        && !myEditor.getSelectionModel().hasBlockSelection()) {
      int lineEndOffset = doc.getLineEndOffset(line);
      int lineEndColumnNumber = myEditor.offsetToLogicalPosition(lineEndOffset).column;
      if (column > lineEndColumnNumber) {
        column = lineEndColumnNumber;
        if (softWrapColumns != 0) {
          softWrapColumns -= column - lineEndColumnNumber;
        }
      }
    }

    ((FoldingModelImpl) myEditor.getFoldingModel()).flushCaretPosition();

    VerticalInfo oldInfo = myCaretInfo;
    LogicalPosition oldCaretPosition = myLogicalCaret;

    LogicalPosition logicalPositionToUse;
    if (pos.visualPositionAware) {
      logicalPositionToUse =
          new LogicalPosition(
              line,
              column,
              softWrapLinesBefore,
              softWrapLinesCurrent,
              softWrapColumns,
              pos.foldedLines,
              pos.foldingColumnDiff);
    } else {
      logicalPositionToUse = new LogicalPosition(line, column);
    }
    setCurrentLogicalCaret(logicalPositionToUse);

    final int offset = myEditor.logicalPositionToOffset(myLogicalCaret);

    FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(offset);

    if (collapsedAt != null && offset > collapsedAt.getStartOffset()) {
      Runnable runnable =
          new Runnable() {
            public void run() {
              FoldRegion[] allCollapsedAt =
                  ((FoldingModelImpl) myEditor.getFoldingModel()).fetchCollapsedAt(offset);
              for (FoldRegion foldRange : allCollapsedAt) {
                foldRange.setExpanded(true);
              }
            }
          };

      myEditor.getFoldingModel().runBatchFoldingOperation(runnable);
    }

    myEditor.setLastColumnNumber(myLogicalCaret.column);
    myVisibleCaret = myEditor.logicalToVisualPosition(myLogicalCaret);

    myOffset = myEditor.logicalPositionToOffset(myLogicalCaret);
    LOG.assertTrue(myOffset >= 0 && myOffset <= myEditor.getDocument().getTextLength());

    myVisualLineStart =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0)));
    myVisualLineEnd =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line + 1, 0)));

    myEditor.updateCaretCursor();
    requestRepaint(oldInfo);

    if (locateBeforeSoftWrap && SoftWrapHelper.isCaretAfterSoftWrap(myEditor)) {
      int lineToUse = myVisibleCaret.line - 1;
      if (lineToUse >= 0) {
        moveToVisualPosition(
            new VisualPosition(
                lineToUse, EditorUtil.getLastVisualLineColumnNumber(myEditor, lineToUse)));
        return;
      }
    }

    if (!oldCaretPosition.toVisualPosition().equals(myLogicalCaret.toVisualPosition())) {
      CaretEvent event = new CaretEvent(myEditor, oldCaretPosition, myLogicalCaret);
      for (CaretListener listener : myCaretListeners) {
        listener.caretPositionChanged(event);
      }
    }
  }
  public boolean processMessageLine(Callback callback) {
    if (super.processMessageLine(callback)) {
      return true;
    }
    final String line = callback.getCurrentLine();
    if (line == null) {
      return false;
    }
    if (JavacResourcesReader.MSG_PATTERNS_START.equals(line)) {
      myParserActions.clear();
      while (true) {
        final String patternLine = callback.getNextLine();
        if (JavacResourcesReader.MSG_PATTERNS_END.equals(patternLine)) {
          break;
        }
        addJavacPattern(patternLine);
      }
      return true;
    }

    int colonIndex1 = line.indexOf(':');
    if (colonIndex1 == 1) { // drive letter
      colonIndex1 = line.indexOf(':', colonIndex1 + 1);
    }

    if (colonIndex1 >= 0) { // looks like found something like file path
      @NonNls String part1 = line.substring(0, colonIndex1).trim();
      if (part1.equalsIgnoreCase("error") /*jikes*/ || part1.equalsIgnoreCase("Caused by")) {
        addMessage(callback, CompilerMessageCategory.ERROR, line.substring(colonIndex1));
        return true;
      }
      if (part1.equalsIgnoreCase("warning")) {
        addMessage(callback, CompilerMessageCategory.WARNING, line.substring(colonIndex1));
        return true;
      }
      if (part1.equals("javac")) {
        addMessage(callback, CompilerMessageCategory.ERROR, line);
        return true;
      }

      final int colonIndex2 = line.indexOf(':', colonIndex1 + 1);
      if (colonIndex2 >= 0) {
        final String filePath = part1.replace(File.separatorChar, '/');
        final Boolean fileExists =
            ApplicationManager.getApplication()
                .runReadAction(
                    new Computable<Boolean>() {
                      public Boolean compute() {
                        return LocalFileSystem.getInstance().findFileByPath(filePath) != null;
                      }
                    });
        if (!fileExists.booleanValue()) {
          // the part one turned out to be something else than a file path
          return true;
        }
        try {
          final int lineNum = Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim());
          String message = line.substring(colonIndex2 + 1).trim();
          CompilerMessageCategory category = CompilerMessageCategory.ERROR;
          if (message.startsWith(WARNING_PREFIX)) {
            message = message.substring(WARNING_PREFIX.length()).trim();
            category = CompilerMessageCategory.WARNING;
          }

          List<String> messages = new ArrayList<String>();
          messages.add(message);
          int colNum;
          String prevLine = null;
          do {
            final String nextLine = callback.getNextLine();
            if (nextLine == null) {
              return false;
            }
            if (nextLine.trim().equals("^")) {
              final CharSequence chars = prevLine == null ? line : prevLine;
              final int offset = Math.max(0, Math.min(chars.length(), nextLine.indexOf('^')));
              colNum = EditorUtil.calcColumnNumber(null, chars, 0, offset, myTabSize);
              String messageEnd = callback.getNextLine();
              while (isMessageEnd(messageEnd)) {
                messages.add(messageEnd.trim());
                messageEnd = callback.getNextLine();
              }
              if (messageEnd != null) {
                callback.pushBack(messageEnd);
              }
              break;
            }
            if (prevLine != null) {
              messages.add(prevLine);
            }
            prevLine = nextLine;
          } while (true);

          if (colNum >= 0) {
            messages = convertMessages(messages);
            final StringBuilder buf = StringBuilderSpinAllocator.alloc();
            try {
              for (final String m : messages) {
                if (buf.length() > 0) {
                  buf.append("\n");
                }
                buf.append(m);
              }
              addMessage(
                  callback,
                  category,
                  buf.toString(),
                  VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, filePath),
                  lineNum,
                  colNum + 1);
            } finally {
              StringBuilderSpinAllocator.dispose(buf);
            }
            return true;
          }
        } catch (NumberFormatException ignored) {
        }
      }
    }

    if (line.endsWith("java.lang.OutOfMemoryError")) {
      addMessage(
          callback,
          CompilerMessageCategory.ERROR,
          CompilerBundle.message("error.javac.out.of.memory"));
      return true;
    }

    addMessage(callback, CompilerMessageCategory.INFORMATION, line);
    return true;
  }