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); }
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); }