private void initGuardedBlocks(Place shreds) {
   int origOffset = -1;
   int curOffset = 0;
   for (PsiLanguageInjectionHost.Shred shred : shreds) {
     Segment hostRangeMarker = shred.getHostRangeMarker();
     int start = shred.getRange().getStartOffset() + shred.getPrefix().length();
     int end = shred.getRange().getEndOffset() - shred.getSuffix().length();
     if (curOffset < start) {
       RangeMarker guard = myNewDocument.createGuardedBlock(curOffset, start);
       if (curOffset == 0 && shred == shreds.get(0)) guard.setGreedyToLeft(true);
       String padding =
           origOffset < 0
               ? ""
               : myOrigDocument.getText().substring(origOffset, hostRangeMarker.getStartOffset());
       guard.putUserData(REPLACEMENT_KEY, fixQuotes(padding));
     }
     curOffset = end;
     origOffset = hostRangeMarker.getEndOffset();
   }
   if (curOffset < myNewDocument.getTextLength()) {
     RangeMarker guard =
         myNewDocument.createGuardedBlock(curOffset, myNewDocument.getTextLength());
     guard.setGreedyToRight(true);
     guard.putUserData(REPLACEMENT_KEY, "");
   }
 }
Exemplo n.º 2
0
  public void documentChanged(DocumentEvent e) {
    finishUpdate();

    DocumentEventImpl event = (DocumentEventImpl) e;
    final Document document = myEditor.getDocument();
    boolean performSoftWrapAdjustment =
        e.getNewLength() > 0 // We want to put caret just after the last added symbol
            // There is a possible case that the user removes text just before the soft wrap. We
            // want to keep caret
            // on a visual line with soft wrap start then.
            || myEditor.getSoftWrapModel().getSoftWrap(e.getOffset()) != null;

    if (event.isWholeTextReplaced()) {
      int newLength = document.getTextLength();
      if (myOffset == newLength - e.getNewLength() + e.getOldLength() || newLength == 0) {
        moveToOffset(newLength, performSoftWrapAdjustment);
      } else {
        final int line;
        try {
          line = event.translateLineViaDiff(myLogicalCaret.line);
          moveToLogicalPosition(
              new LogicalPosition(line, myLogicalCaret.column), performSoftWrapAdjustment);
        } catch (FilesTooBigForDiffException e1) {
          LOG.info(e1);
          moveToOffset(0);
        }
      }
    } else {
      if (document instanceof DocumentEx && ((DocumentEx) document).isInBulkUpdate()) return;
      int startOffset = e.getOffset();
      int oldEndOffset = startOffset + e.getOldLength();

      int newOffset = myOffset;

      if (myOffset > oldEndOffset || myOffset == oldEndOffset && needToShiftWhiteSpaces(e)) {
        newOffset += e.getNewLength() - e.getOldLength();
      } else if (myOffset >= startOffset && myOffset <= oldEndOffset) {
        newOffset = Math.min(newOffset, startOffset + e.getNewLength());
      }

      newOffset = Math.min(newOffset, document.getTextLength());

      // if (newOffset != myOffset) {
      moveToOffset(newOffset, performSoftWrapAdjustment);
      // }
      // else {
      //  moveToVisualPosition(oldPosition);
      // }
    }

    myVisualLineStart =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0)));
    myVisualLineEnd =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line + 1, 0)));
  }
  private void paintCaret(Graphics2D g_) {
    EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations(true);
    if (locations == null) return;

    Graphics2D g = IdeBackgroundUtil.getOriginalGraphics(g_);
    int lineHeight = myView.getLineHeight();
    EditorSettings settings = myEditor.getSettings();
    Color caretColor = myEditor.getColorsScheme().getColor(EditorColors.CARET_COLOR);
    if (caretColor == null) caretColor = new JBColor(CARET_DARK, CARET_LIGHT);
    g.setColor(caretColor);
    for (EditorImpl.CaretRectangle location : locations) {
      int x = location.myPoint.x;
      int y = location.myPoint.y;
      Caret caret = location.myCaret;
      boolean isRtl = location.myIsRtl;
      if (myEditor.isInsertMode() != settings.isBlockCursor()) {
        int lineWidth = JBUI.scale(settings.getLineCursorWidth());
        g.fillRect(x, y, lineWidth, lineHeight);
        if (myDocument.getTextLength() > 0
            && caret != null
            && !myView.getLineLayout(caret.getLogicalPosition().line).isLtr()) {
          g.fillPolygon(
              new int[] {
                isRtl ? x + lineWidth : x,
                isRtl ? x + lineWidth - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE,
                isRtl ? x + lineWidth : x
              },
              new int[] {y, y, y + CARET_DIRECTION_MARK_SIZE},
              3);
        }
      } else {
        int width = location.myWidth;
        int startX = Math.max(0, isRtl ? x - width : x);
        g.fillRect(startX, y, width, lineHeight - 1);
        if (myDocument.getTextLength() > 0 && caret != null) {
          int targetVisualColumn = caret.getVisualPosition().column;
          for (VisualLineFragmentsIterator.Fragment fragment :
              VisualLineFragmentsIterator.create(myView, caret.getVisualLineStart(), false)) {
            int startVisualColumn = fragment.getStartVisualColumn();
            int endVisualColumn = fragment.getEndVisualColumn();
            if (startVisualColumn < targetVisualColumn && endVisualColumn > targetVisualColumn
                || startVisualColumn == targetVisualColumn && !isRtl
                || endVisualColumn == targetVisualColumn && isRtl) {
              g.setColor(ColorUtil.isDark(caretColor) ? CARET_LIGHT : CARET_DARK);
              fragment.draw(
                  g,
                  startX,
                  y + myView.getAscent(),
                  targetVisualColumn - startVisualColumn - (isRtl ? 1 : 0),
                  targetVisualColumn - startVisualColumn + (isRtl ? 0 : 1));
              break;
            }
          }
        }
      }
    }
  }
  /**
   * Emulates pressing <code>Enter</code> at current caret position.
   *
   * @param editor target editor
   * @param project target project
   * @param shifts two-elements array which is expected to be filled with the following info: 1. The
   *     first element holds added lines number; 2. The second element holds added symbols number;
   */
  private static void emulateEnter(
      @NotNull final Editor editor, @NotNull Project project, int[] shifts) {
    final DataContext dataContext = prepareContext(editor.getComponent(), project);
    int caretOffset = editor.getCaretModel().getOffset();
    Document document = editor.getDocument();
    SelectionModel selectionModel = editor.getSelectionModel();
    int startSelectionOffset = 0;
    int endSelectionOffset = 0;
    boolean restoreSelection = selectionModel.hasSelection();
    if (restoreSelection) {
      startSelectionOffset = selectionModel.getSelectionStart();
      endSelectionOffset = selectionModel.getSelectionEnd();
      selectionModel.removeSelection();
    }
    int textLengthBeforeWrap = document.getTextLength();
    int lineCountBeforeWrap = document.getLineCount();

    DataManager.getInstance()
        .saveInDataContext(dataContext, WRAP_LONG_LINE_DURING_FORMATTING_IN_PROGRESS_KEY, true);
    CommandProcessor commandProcessor = CommandProcessor.getInstance();
    try {
      Runnable command =
          new Runnable() {
            @Override
            public void run() {
              EditorActionManager.getInstance()
                  .getActionHandler(IdeActions.ACTION_EDITOR_ENTER)
                  .execute(editor, dataContext);
            }
          };
      if (commandProcessor.getCurrentCommand() == null) {
        commandProcessor.executeCommand(editor.getProject(), command, WRAP_LINE_COMMAND_NAME, null);
      } else {
        command.run();
      }
    } finally {
      DataManager.getInstance()
          .saveInDataContext(dataContext, WRAP_LONG_LINE_DURING_FORMATTING_IN_PROGRESS_KEY, null);
    }
    int symbolsDiff = document.getTextLength() - textLengthBeforeWrap;
    if (restoreSelection) {
      int newSelectionStart = startSelectionOffset;
      int newSelectionEnd = endSelectionOffset;
      if (startSelectionOffset >= caretOffset) {
        newSelectionStart += symbolsDiff;
      }
      if (endSelectionOffset >= caretOffset) {
        newSelectionEnd += symbolsDiff;
      }
      selectionModel.setSelection(newSelectionStart, newSelectionEnd);
    }
    shifts[0] = document.getLineCount() - lineCountBeforeWrap;
    shifts[1] = symbolsDiff;
  }
  private boolean paintPlaceholderText(Graphics2D g) {
    CharSequence hintText = myEditor.getPlaceholder();
    EditorComponentImpl editorComponent = myEditor.getContentComponent();
    if (myDocument.getTextLength() > 0
        || hintText == null
        || hintText.length() == 0
        || KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == editorComponent
            && !myEditor.getShowPlaceholderWhenFocused()) {
      return false;
    }

    hintText =
        SwingUtilities.layoutCompoundLabel(
            g.getFontMetrics(),
            hintText.toString(),
            null,
            0,
            0,
            0,
            0,
            editorComponent.getBounds(),
            new Rectangle(),
            new Rectangle(),
            0);
    g.setColor(myEditor.getFoldingModel().getPlaceholderAttributes().getForegroundColor());
    g.setFont(myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
    g.drawString(hintText.toString(), 0, myView.getAscent());
    return true;
  }
 private void updateDocumentFromPropertyValue(
     final String value, final Document document, final PropertiesFile propertiesFile) {
   @NonNls String text = value;
   if (myBackSlashPressed.contains(propertiesFile)) {
     text += "\\";
   }
   document.replaceString(0, document.getTextLength(), text);
 }
  public static String getNewText(PsiElement elt) {
    Project project = elt.getProject();
    PsiFile psiFile = getContainingFile(elt);

    final Document doc = PsiDocumentManager.getInstance(project).getDocument(psiFile);
    if (doc == null) return null;

    final ImplementationTextSelectioner implementationTextSelectioner =
        LanguageImplementationTextSelectioner.INSTANCE.forLanguage(elt.getLanguage());
    int start = implementationTextSelectioner.getTextStartOffset(elt);
    final int end = implementationTextSelectioner.getTextEndOffset(elt);

    final int lineStart = doc.getLineStartOffset(doc.getLineNumber(start));
    final int lineEnd =
        end < doc.getTextLength()
            ? doc.getLineEndOffset(doc.getLineNumber(end))
            : doc.getTextLength();
    return doc.getCharsSequence().subSequence(lineStart, lineEnd).toString();
  }
  private void paintComposedTextDecoration(Graphics2D g) {
    TextRange composedTextRange = myEditor.getComposedTextRange();
    if (composedTextRange != null) {
      Point p1 =
          myView.offsetToXY(
              Math.min(composedTextRange.getStartOffset(), myDocument.getTextLength()),
              true,
              false);
      Point p2 =
          myView.offsetToXY(
              Math.min(composedTextRange.getEndOffset(), myDocument.getTextLength()), false, true);

      int y = p1.y + myView.getAscent() + 1;

      g.setStroke(IME_COMPOSED_TEXT_UNDERLINE_STROKE);
      g.setColor(myEditor.getColorsScheme().getDefaultForeground());
      UIUtil.drawLine(g, p1.x, y, p2.x, y);
    }
  }
 public void printToHistory(String text, final TextAttributes attributes) {
   ApplicationManager.getApplication().assertIsDispatchThread();
   text = StringUtil.convertLineSeparators(text);
   final boolean scrollToEnd = shouldScrollHistoryToEnd();
   final Document history = myHistoryViewer.getDocument();
   final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
   final int offset = history.getTextLength();
   appendToHistoryDocument(history, text);
   markupModel.addRangeHighlighter(
       offset,
       history.getTextLength(),
       HighlighterLayer.SYNTAX,
       attributes,
       HighlighterTargetArea.EXACT_RANGE);
   if (scrollToEnd) {
     scrollHistoryToEnd();
   }
   queueUiUpdate(scrollToEnd);
 }
  private int yPositionToOffset(int y, boolean beginLine) {
    if (myEditorScrollbarTop == -1 || myEditorTargetHeight == -1) {
      recalcEditorDimensions();
    }
    final int safeY = Math.max(0, y - myEditorScrollbarTop);
    VisualPosition visual;
    if (myEditorSourceHeight < myEditorTargetHeight) {
      visual = myEditor.xyToVisualPosition(new Point(0, safeY));
    } else {
      float fraction = Math.max(0, Math.min(1, safeY / (float) myEditorTargetHeight));
      final int lineCount = myEditorSourceHeight / myEditor.getLineHeight();
      visual = new VisualPosition((int) (fraction * lineCount), 0);
    }
    int line = myEditor.visualToLogicalPosition(visual).line;
    Document document = myEditor.getDocument();
    if (line < 0) return 0;
    if (line >= document.getLineCount()) return document.getTextLength();

    return beginLine ? document.getLineStartOffset(line) : document.getLineEndOffset(line);
  }
Exemplo n.º 11
0
  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);
  }
Exemplo n.º 12
0
  private void dumpEditorMarkupAndSelection(PrintStream dumpStream) {
    dumpStream.println(mySearchResults.getFindModel());
    if (myReplacementPreviewText != null) {
      dumpStream.println("--");
      dumpStream.println("Replacement Preview: " + myReplacementPreviewText);
    }
    dumpStream.println("--");

    Editor editor = mySearchResults.getEditor();

    RangeHighlighter[] highlighters = editor.getMarkupModel().getAllHighlighters();
    List<Pair<Integer, Character>> ranges = new ArrayList<Pair<Integer, Character>>();
    for (RangeHighlighter highlighter : highlighters) {
      ranges.add(new Pair<Integer, Character>(highlighter.getStartOffset(), '['));
      ranges.add(new Pair<Integer, Character>(highlighter.getEndOffset(), ']'));
    }

    SelectionModel selectionModel = editor.getSelectionModel();

    if (selectionModel.getSelectionStart() != selectionModel.getSelectionEnd()) {
      ranges.add(new Pair<Integer, Character>(selectionModel.getSelectionStart(), '<'));
      ranges.add(new Pair<Integer, Character>(selectionModel.getSelectionEnd(), '>'));
    }
    ranges.add(new Pair<Integer, Character>(-1, '\n'));
    ranges.add(new Pair<Integer, Character>(editor.getDocument().getTextLength() + 1, '\n'));
    ContainerUtil.sort(
        ranges,
        new Comparator<Pair<Integer, Character>>() {
          @Override
          public int compare(Pair<Integer, Character> pair, Pair<Integer, Character> pair2) {
            int res = pair.first - pair2.first;
            if (res == 0) {

              Character c1 = pair.second;
              Character c2 = pair2.second;
              if (c1 == '<' && c2 == '[') {
                return 1;
              } else if (c1 == '[' && c2 == '<') {
                return -1;
              }
              return c1.compareTo(c2);
            }
            return res;
          }
        });

    Document document = editor.getDocument();
    for (int i = 0; i < ranges.size() - 1; ++i) {
      Pair<Integer, Character> pair = ranges.get(i);
      Pair<Integer, Character> pair1 = ranges.get(i + 1);
      dumpStream.print(
          pair.second
              + document.getText(
                  TextRange.create(
                      Math.max(pair.first, 0), Math.min(pair1.first, document.getTextLength()))));
    }
    dumpStream.println("\n--");

    if (NotFound) {
      dumpStream.println("Not Found");
      dumpStream.println("--");
      NotFound = false;
    }

    for (RangeHighlighter highlighter : highlighters) {
      dumpStream.println(highlighter + " : " + highlighter.getTextAttributes());
    }
    dumpStream.println("------------");
  }
  protected String addTextRangeToHistory(
      TextRange textRange, final EditorEx consoleEditor, boolean preserveMarkup) {
    final Document history = myHistoryViewer.getDocument();
    final MarkupModel markupModel = DocumentMarkupModel.forDocument(history, myProject, true);
    if (myPrompt != null) {
      appendToHistoryDocument(history, myPrompt);
    }
    markupModel.addRangeHighlighter(
        history.getTextLength() - StringUtil.length(myPrompt),
        history.getTextLength(),
        HighlighterLayer.SYNTAX,
        ConsoleViewContentType.USER_INPUT.getAttributes(),
        HighlighterTargetArea.EXACT_RANGE);
    final int localStartOffset = textRange.getStartOffset();
    String text;
    EditorHighlighter highlighter;
    if (consoleEditor instanceof EditorWindow) {
      EditorWindow editorWindow = (EditorWindow) consoleEditor;
      EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
      PsiFile file = editorWindow.getInjectedFile();
      final VirtualFile virtualFile = file.getVirtualFile();
      assert virtualFile != null;
      highlighter = HighlighterFactory.createHighlighter(virtualFile, scheme, getProject());
      String fullText = InjectedLanguageUtil.getUnescapedText(file, null, null);
      highlighter.setText(fullText);
      text = textRange.substring(fullText);
    } else {
      text = consoleEditor.getDocument().getText(textRange);
      highlighter = consoleEditor.getHighlighter();
    }
    // offset can be changed after text trimming after insert due to buffer constraints
    appendToHistoryDocument(history, text);
    int offset = history.getTextLength() - text.length();

    final HighlighterIterator iterator = highlighter.createIterator(localStartOffset);
    final int localEndOffset = textRange.getEndOffset();
    while (!iterator.atEnd()) {
      final int itStart = iterator.getStart();
      if (itStart > localEndOffset) break;
      final int itEnd = iterator.getEnd();
      if (itEnd >= localStartOffset) {
        final int start = Math.max(itStart, localStartOffset) - localStartOffset + offset;
        final int end = Math.min(itEnd, localEndOffset) - localStartOffset + offset;
        markupModel.addRangeHighlighter(
            start,
            end,
            HighlighterLayer.SYNTAX,
            iterator.getTextAttributes(),
            HighlighterTargetArea.EXACT_RANGE);
      }
      iterator.advance();
    }
    if (preserveMarkup) {
      duplicateHighlighters(
          markupModel,
          DocumentMarkupModel.forDocument(consoleEditor.getDocument(), myProject, true),
          offset,
          textRange);
      duplicateHighlighters(markupModel, consoleEditor.getMarkupModel(), offset, textRange);
    }
    if (!text.endsWith("\n")) {
      appendToHistoryDocument(history, "\n");
    }
    return text;
  }
 protected void appendToHistoryDocument(@NotNull Document history, @NotNull String text) {
   history.insertString(history.getTextLength(), text);
 }
  public ASTNode processRange(final ASTNode element, final int startOffset, final int endOffset) {
    final PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element);
    assert psiElement != null;
    final PsiFile file = psiElement.getContainingFile();
    final Document document = file.getViewProvider().getDocument();
    final RangeMarker rangeMarker =
        document != null && endOffset < document.getTextLength()
            ? document.createRangeMarker(startOffset, endOffset)
            : null;

    PsiElement elementToFormat =
        document instanceof DocumentWindow
            ? InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file)
            : psiElement;
    final PsiFile fileToFormat = elementToFormat.getContainingFile();

    final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(fileToFormat);
    if (builder != null) {
      TextRange range = preprocess(element, TextRange.create(startOffset, endOffset));
      if (document instanceof DocumentWindow) {
        DocumentWindow documentWindow = (DocumentWindow) document;
        range = documentWindow.injectedToHost(range);
      }

      // final SmartPsiElementPointer pointer =
      // SmartPointerManager.getInstance(psiElement.getProject()).createSmartPsiElementPointer(psiElement);
      final FormattingModel model =
          CoreFormatterUtil.buildModel(
              builder, elementToFormat, mySettings, FormattingMode.REFORMAT);
      if (file.getTextLength() > 0) {
        try {
          FormatterEx.getInstanceEx()
              .format(
                  model,
                  mySettings,
                  mySettings.getIndentOptions(fileToFormat.getFileType()),
                  new FormatTextRanges(range, true));

          wrapLongLinesIfNecessary(file, document, startOffset, endOffset);
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }

      if (!psiElement.isValid()) {
        if (rangeMarker != null) {
          final PsiElement at = file.findElementAt(rangeMarker.getStartOffset());
          final PsiElement result = PsiTreeUtil.getParentOfType(at, psiElement.getClass(), false);
          assert result != null;
          rangeMarker.dispose();
          return result.getNode();
        } else {
          assert false;
        }
      }
      //      return SourceTreeToPsiMap.psiElementToTree(pointer.getElement());
    }

    if (rangeMarker != null) {
      rangeMarker.dispose();
    }
    return element;
  }
 private int offsetToLine(int offset, Document document) {
   if (offset > document.getTextLength()) {
     return document.getLineCount();
   }
   return myEditor.offsetToVisualLine(offset);
 }
  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];
    }
  }
Exemplo n.º 18
0
        @Override
        @SuppressWarnings({"AssignmentToForLoopParameter"})
        public void paint(
            @NotNull Editor editor, @NotNull RangeHighlighter highlighter, @NotNull Graphics g) {
          int startOffset = highlighter.getStartOffset();
          final Document doc = highlighter.getDocument();
          if (startOffset >= doc.getTextLength()) return;

          final int endOffset = highlighter.getEndOffset();
          final int endLine = doc.getLineNumber(endOffset);

          int off;
          int startLine = doc.getLineNumber(startOffset);
          IndentGuideDescriptor descriptor =
              editor.getIndentsModel().getDescriptor(startLine, endLine);

          final CharSequence chars = doc.getCharsSequence();
          do {
            int start = doc.getLineStartOffset(startLine);
            int end = doc.getLineEndOffset(startLine);
            off = CharArrayUtil.shiftForward(chars, start, end, " \t");
            startLine--;
          } while (startLine > 1 && off < doc.getTextLength() && chars.charAt(off) == '\n');

          final VisualPosition startPosition = editor.offsetToVisualPosition(off);
          int indentColumn = startPosition.column;

          // It's considered that indent guide can cross not only white space but comments, javadocs
          // etc. Hence, there is a possible
          // case that the first indent guide line is, say, single-line comment where comment
          // symbols ('//') are located at the first
          // visual column. We need to calculate correct indent guide column then.
          int lineShift = 1;
          if (indentColumn <= 0 && descriptor != null) {
            indentColumn = descriptor.indentLevel;
            lineShift = 0;
          }
          if (indentColumn <= 0) return;

          final FoldingModel foldingModel = editor.getFoldingModel();
          if (foldingModel.isOffsetCollapsed(off)) return;

          final FoldRegion headerRegion =
              foldingModel.getCollapsedRegionAtOffset(doc.getLineEndOffset(doc.getLineNumber(off)));
          final FoldRegion tailRegion =
              foldingModel.getCollapsedRegionAtOffset(
                  doc.getLineStartOffset(doc.getLineNumber(endOffset)));

          if (tailRegion != null && tailRegion == headerRegion) return;

          final boolean selected;
          final IndentGuideDescriptor guide = editor.getIndentsModel().getCaretIndentGuide();
          if (guide != null) {
            final CaretModel caretModel = editor.getCaretModel();
            final int caretOffset = caretModel.getOffset();
            selected =
                caretOffset >= off
                    && caretOffset < endOffset
                    && caretModel.getLogicalPosition().column == indentColumn;
          } else {
            selected = false;
          }

          Point start =
              editor.visualPositionToXY(
                  new VisualPosition(startPosition.line + lineShift, indentColumn));
          final VisualPosition endPosition = editor.offsetToVisualPosition(endOffset);
          Point end =
              editor.visualPositionToXY(new VisualPosition(endPosition.line, endPosition.column));
          int maxY = end.y;
          if (endPosition.line == editor.offsetToVisualPosition(doc.getTextLength()).line) {
            maxY += editor.getLineHeight();
          }

          Rectangle clip = g.getClipBounds();
          if (clip != null) {
            if (clip.y >= maxY || clip.y + clip.height <= start.y) {
              return;
            }
            maxY = Math.min(maxY, clip.y + clip.height);
          }

          final EditorColorsScheme scheme = editor.getColorsScheme();
          g.setColor(
              selected
                  ? scheme.getColor(EditorColors.SELECTED_INDENT_GUIDE_COLOR)
                  : scheme.getColor(EditorColors.INDENT_GUIDE_COLOR));

          // There is a possible case that indent line intersects soft wrap-introduced text.
          // Example:
          //     this is a long line <soft-wrap>
          // that| is soft-wrapped
          //     |
          //     | <- vertical indent
          //
          // Also it's possible that no additional intersections are added because of soft wrap:
          //     this is a long line <soft-wrap>
          //     |   that is soft-wrapped
          //     |
          //     | <- vertical indent
          // We want to use the following approach then:
          //     1. Show only active indent if it crosses soft wrap-introduced text;
          //     2. Show indent as is if it doesn't intersect with soft wrap-introduced text;
          if (selected) {
            g.drawLine(start.x + 2, start.y, start.x + 2, maxY);
          } else {
            int y = start.y;
            int newY = start.y;
            SoftWrapModel softWrapModel = editor.getSoftWrapModel();
            int lineHeight = editor.getLineHeight();
            for (int i = Math.max(0, startLine + lineShift); i < endLine && newY < maxY; i++) {
              List<? extends SoftWrap> softWraps = softWrapModel.getSoftWrapsForLine(i);
              int logicalLineHeight = softWraps.size() * lineHeight;
              if (i > startLine + lineShift) {
                logicalLineHeight +=
                    lineHeight; // We assume that initial 'y' value points just below the target
                // line.
              }
              if (!softWraps.isEmpty() && softWraps.get(0).getIndentInColumns() < indentColumn) {
                if (y < newY
                    || i
                        > startLine
                            + lineShift) { // There is a possible case that soft wrap is located on
                  // indent start line.
                  g.drawLine(start.x + 2, y, start.x + 2, newY + lineHeight);
                }
                newY += logicalLineHeight;
                y = newY;
              } else {
                newY += logicalLineHeight;
              }

              FoldRegion foldRegion =
                  foldingModel.getCollapsedRegionAtOffset(doc.getLineEndOffset(i));
              if (foldRegion != null && foldRegion.getEndOffset() < doc.getTextLength()) {
                i = doc.getLineNumber(foldRegion.getEndOffset());
              }
            }

            if (y < maxY) {
              g.drawLine(start.x + 2, y, start.x + 2, maxY);
            }
          }
        }
  public void processText(
      PsiFile file, final FormatTextRanges ranges, boolean doPostponedFormatting) {
    final Project project = file.getProject();
    Document document = PsiDocumentManager.getInstance(project).getDocument(file);
    final List<FormatTextRanges.FormatTextRange> textRanges = ranges.getRanges();
    if (document instanceof DocumentWindow) {
      file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
      final DocumentWindow documentWindow = (DocumentWindow) document;
      for (FormatTextRanges.FormatTextRange range : textRanges) {
        range.setTextRange(documentWindow.injectedToHost(range.getTextRange()));
      }
      document = documentWindow.getDelegate();
    }

    final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file);

    if (builder != null) {
      if (file.getTextLength() > 0) {
        try {
          final PsiElement startElement =
              file.findElementAt(textRanges.get(0).getTextRange().getStartOffset());
          final PsiElement endElement =
              file.findElementAt(
                  textRanges.get(textRanges.size() - 1).getTextRange().getEndOffset() - 1);
          final PsiElement commonParent =
              startElement != null && endElement != null
                  ? PsiTreeUtil.findCommonParent(startElement, endElement)
                  : null;
          ASTNode node = null;
          if (commonParent != null) {
            node = commonParent.getNode();
          }
          if (node == null) {
            node = file.getNode();
          }
          for (FormatTextRanges.FormatTextRange range : ranges.getRanges()) {
            TextRange rangeToUse = preprocess(node, range.getTextRange());
            range.setTextRange(rangeToUse);
          }
          if (doPostponedFormatting) {
            RangeMarker[] markers = new RangeMarker[textRanges.size()];
            int i = 0;
            for (FormatTextRanges.FormatTextRange range : textRanges) {
              TextRange textRange = range.getTextRange();
              int start = textRange.getStartOffset();
              int end = textRange.getEndOffset();
              if (start >= 0 && end > start && end <= document.getTextLength()) {
                markers[i] = document.createRangeMarker(textRange);
                markers[i].setGreedyToLeft(true);
                markers[i].setGreedyToRight(true);
                i++;
              }
            }
            final PostprocessReformattingAspect component =
                file.getProject().getComponent(PostprocessReformattingAspect.class);
            FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false);
            component.doPostponedFormatting(file.getViewProvider());
            i = 0;
            for (FormatTextRanges.FormatTextRange range : textRanges) {
              RangeMarker marker = markers[i];
              if (marker != null) {
                range.setTextRange(TextRange.create(marker));
                marker.dispose();
              }
              i++;
            }
          }
          if (FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get()) {
            return;
          }

          final FormattingModel originalModel =
              CoreFormatterUtil.buildModel(builder, file, mySettings, FormattingMode.REFORMAT);
          final FormattingModel model =
              new DocumentBasedFormattingModel(
                  originalModel.getRootBlock(),
                  document,
                  project,
                  mySettings,
                  file.getFileType(),
                  file);

          FormatterEx formatter = FormatterEx.getInstanceEx();
          if (CodeStyleManager.getInstance(project).isSequentialProcessingAllowed()) {
            formatter.setProgressTask(new FormattingProgressTask(project, file, document));
          }

          CommonCodeStyleSettings.IndentOptions indentOptions = null;
          if (builder instanceof FormattingModelBuilderEx) {
            indentOptions =
                ((FormattingModelBuilderEx) builder)
                    .getIndentOptionsToUse(file, ranges, mySettings);
          }
          if (indentOptions == null) {
            indentOptions = mySettings.getIndentOptions(file.getFileType());
          }

          formatter.format(model, mySettings, indentOptions, ranges);
          for (FormatTextRanges.FormatTextRange range : textRanges) {
            TextRange textRange = range.getTextRange();
            wrapLongLinesIfNecessary(
                file, document, textRange.getStartOffset(), textRange.getEndOffset());
          }
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }
    }
  }