public static void expandRegionAtCaret(final Project project, @Nullable final Editor editor) {
    if (editor == null) return;

    CodeFoldingManager foldingManager = CodeFoldingManager.getInstance(project);
    foldingManager.updateFoldRegions(editor);

    final int line = editor.getCaretModel().getLogicalPosition().line;
    Runnable processor =
        new Runnable() {
          public void run() {
            FoldRegion region = FoldingUtil.findFoldRegionStartingAtLine(editor, line);
            if (region != null && !region.isExpanded()) {
              region.setExpanded(true);
            } else {
              int offset = editor.getCaretModel().getOffset();
              FoldRegion[] regions = FoldingUtil.getFoldRegionsAtOffset(editor, offset);
              for (int i = regions.length - 1; i >= 0; i--) {
                region = regions[i];
                if (!region.isExpanded()) {
                  region.setExpanded(true);
                  break;
                }
              }
            }
          }
        };
    editor.getFoldingModel().runBatchFoldingOperation(processor);
  }
예제 #2
0
  public void testFoldRegionsUpdate() throws IOException {
    String text =
        "import java.util.List;\n"
            + "import java.util.ArrayList;\n"
            + "\n"
            + "class Test {\n"
            + "}";
    init(40, text);

    final int foldStartOffset = "import".length() + 1;
    int foldEndOffset = text.indexOf("class") - 2;
    addCollapsedFoldRegion(foldStartOffset, foldEndOffset, "...");

    // Simulate addition of the new import that modifies existing fold region.
    myEditor.getDocument().insertString(foldEndOffset, "\nimport java.util.Date;\n");
    final FoldingModel foldingModel = myEditor.getFoldingModel();
    foldingModel.runBatchFoldingOperation(
        new Runnable() {
          @Override
          public void run() {
            FoldRegion oldFoldRegion = getFoldRegion(foldStartOffset);
            assertNotNull(oldFoldRegion);
            foldingModel.removeFoldRegion(oldFoldRegion);

            int newFoldEndOffset = myEditor.getDocument().getText().indexOf("class") - 2;
            FoldRegion newFoldRegion =
                foldingModel.addFoldRegion(foldStartOffset, newFoldEndOffset, "...");
            assertNotNull(newFoldRegion);
            newFoldRegion.setExpanded(false);
          }
        });
    CodeFoldingManager.getInstance(getProject()).updateFoldRegions(myEditor);
    assertEquals(
        new VisualPosition(2, 0), myEditor.logicalToVisualPosition(new LogicalPosition(5, 0)));
  }
  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);
  }
  public final void move(Editor editor, final PsiFile file) {
    myMover.beforeMove(editor, myInfo, myIsDown);
    final Document document = editor.getDocument();
    final int start =
        StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine);
    final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine);
    myInfo.range1 = document.createRangeMarker(start, end);

    String textToInsert = document.getCharsSequence().subSequence(start, end).toString();
    if (!StringUtil.endsWithChar(textToInsert, '\n')) textToInsert += '\n';

    final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine);
    final int end2 = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove2.endLine);
    String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
    if (!StringUtil.endsWithChar(textToInsert2, '\n')) textToInsert2 += '\n';
    myInfo.range2 = document.createRangeMarker(start2, end2);
    if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
      myInfo.range1.setGreedyToLeft(true);
      myInfo.range1.setGreedyToRight(false);
      myInfo.range2.setGreedyToLeft(true);
      myInfo.range2.setGreedyToRight(true);
    } else {
      myInfo.range1.setGreedyToLeft(true);
      myInfo.range1.setGreedyToRight(true);
      myInfo.range2.setGreedyToLeft(true);
      myInfo.range2.setGreedyToRight(false);
    }

    final CaretModel caretModel = editor.getCaretModel();
    final int caretRelativePos = caretModel.getOffset() - start;
    final SelectionModel selectionModel = editor.getSelectionModel();
    final int selectionStart = selectionModel.getSelectionStart();
    final int selectionEnd = selectionModel.getSelectionEnd();
    final boolean hasSelection = selectionModel.hasSelection();

    // to prevent flicker
    caretModel.moveToOffset(0);

    // There is a possible case that the user performs, say, method move. It's also possible that
    // one (or both) of moved methods
    // are folded. We want to preserve their states then. The problem is that folding processing is
    // based on PSI element pointers
    // and the pointers behave as following during move up/down:
    //     method1() {}
    //     method2() {}
    // Pointer for the fold region from method1 points to 'method2()' now and vice versa (check
    // range markers processing on
    // document change for further information). I.e. information about fold regions statuses holds
    // the data swapped for
    // 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status.
    FoldRegion topRegion = null;
    FoldRegion bottomRegion = null;
    for (FoldRegion foldRegion : editor.getFoldingModel().getAllFoldRegions()) {
      if (!foldRegion.isValid()
          || (!contains(myInfo.range1, foldRegion) && !contains(myInfo.range2, foldRegion))) {
        continue;
      }
      if (contains(myInfo.range1, foldRegion) && !contains(topRegion, foldRegion)) {
        topRegion = foldRegion;
      } else if (contains(myInfo.range2, foldRegion) && !contains(bottomRegion, foldRegion)) {
        bottomRegion = foldRegion;
      }
    }

    document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
    document.deleteString(
        myInfo.range1.getStartOffset() + textToInsert2.length(), myInfo.range1.getEndOffset());

    document.insertString(myInfo.range2.getStartOffset(), textToInsert);
    int s = myInfo.range2.getStartOffset() + textToInsert.length();
    int e = myInfo.range2.getEndOffset();
    if (e > s) {
      document.deleteString(s, e);
    }

    final Project project = file.getProject();
    PsiDocumentManager.getInstance(project).commitAllDocuments();

    // Swap fold regions status if necessary.
    if (topRegion != null && bottomRegion != null) {
      final FoldRegion finalTopRegion = topRegion;
      final FoldRegion finalBottomRegion = bottomRegion;
      editor
          .getFoldingModel()
          .runBatchFoldingOperation(
              new Runnable() {
                @Override
                public void run() {
                  boolean topExpanded = finalTopRegion.isExpanded();
                  finalTopRegion.setExpanded(finalBottomRegion.isExpanded());
                  finalBottomRegion.setExpanded(topExpanded);
                }
              });
    }
    CodeFoldingManager.getInstance(project).allowFoldingOnCaretLine(editor);

    if (hasSelection) {
      restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset());
    }

    caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
    if (myInfo.indentTarget) {
      indentLinesIn(editor, file, document, project, myInfo.range2);
    }
    if (myInfo.indentSource) {
      indentLinesIn(editor, file, document, project, myInfo.range1);
    }

    myMover.afterMove(editor, file, myInfo, myIsDown);
    editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
  }