void updateCachedOffsets() { if (!isFoldingEnabled()) { return; } if (myCachedVisible == null) { rebuild(); return; } for (FoldRegion foldRegion : myCachedVisible) { if (!foldRegion.isValid()) { rebuild(); return; } } int length = myCachedTopLevelRegions.length; if (myCachedEndOffsets == null || myCachedEndOffsets.length != length) { if (length != 0) { myCachedEndOffsets = new int[length]; myCachedStartOffsets = new int[length]; myCachedFoldedLines = new int[length]; } else { myCachedEndOffsets = ArrayUtil.EMPTY_INT_ARRAY; myCachedStartOffsets = ArrayUtil.EMPTY_INT_ARRAY; myCachedFoldedLines = ArrayUtil.EMPTY_INT_ARRAY; } } int sum = 0; for (int i = 0; i < length; i++) { FoldRegion region = myCachedTopLevelRegions[i]; myCachedStartOffsets[i] = region.getStartOffset(); myCachedEndOffsets[i] = region.getEndOffset() - 1; Document document = region.getDocument(); sum += document.getLineNumber(region.getEndOffset()) - document.getLineNumber(region.getStartOffset()); myCachedFoldedLines[i] = sum; } }
@Nullable FoldRegion fetchOutermost(int offset) { if (!isFoldingEnabledAndUpToDate()) return null; final int[] starts = myCachedStartOffsets; final int[] ends = myCachedEndOffsets; if (starts == null || ends == null) { return null; } int start = 0; int end = ends.length - 1; while (start <= end) { int i = (start + end) / 2; if (offset < starts[i]) { end = i - 1; } else if (offset > ends[i]) { start = i + 1; } else { // We encountered situation when cached data is inconsistent. It's not clear what produced // that, so, the following was done: // 1. Corresponding check was added and cached data is rebuilt in case of inconsistency; // 2. Debug asserts are activated if dedicated flag is on (it's off by default); if (myCachedStartOffsets[i] != myCachedTopLevelRegions[i].getStartOffset()) { if (DEBUG) { assert false : "inconsistent cached fold data detected. Start offsets: " + Arrays.toString(myCachedStartOffsets) + ", end offsets: " + Arrays.toString(myCachedEndOffsets) + ", top regions: " + Arrays.toString(myCachedTopLevelRegions) + ", visible regions: " + Arrays.toString(myCachedVisible); } rebuild(); return fetchOutermost(offset); } return myCachedTopLevelRegions[i]; } } return null; }
void onBulkDocumentUpdateFinished() { myFoldTree.rebuild(); }
@Override public void rebuild() { if (!myEditor.getDocument().isInBulkUpdate()) { myFoldTree.rebuild(); } }
@Override public void rebuild() { myFoldTree.rebuild(); }
private void doNotifyBatchFoldingProcessingDone() { myFoldTree.rebuild(); for (FoldingListener listener : myListeners) { listener.onFoldProcessingEnd(); } myEditor.updateCaretCursor(); myEditor.recalculateSizeAndRepaint(); if (myEditor.getGutterComponentEx().isFoldingOutlineShown()) { myEditor.getGutterComponentEx().repaint(); } LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition(); // There is a possible case that caret position is already visual position aware. But visual // position depends on number of folded // logical lines as well, hence, we can't be sure that target logical position defines correct // visual position because fold // regions have just changed. Hence, we use 'raw' logical position instead. if (caretPosition.visualPositionAware) { caretPosition = new LogicalPosition(caretPosition.line, caretPosition.column); } int caretOffset = myEditor.logicalPositionToOffset(caretPosition); boolean hasBlockSelection = myEditor.getSelectionModel().hasBlockSelection(); int selectionStart = myEditor.getSelectionModel().getSelectionStart(); int selectionEnd = myEditor.getSelectionModel().getSelectionEnd(); int column = -1; int line = -1; int offsetToUse = -1; FoldRegion collapsed = myFoldTree.fetchOutermost(caretOffset); if (myCaretPositionSaved) { int savedOffset = myEditor.logicalPositionToOffset(new LogicalPosition(mySavedCaretY, mySavedCaretX)); FoldRegion collapsedAtSaved = myFoldTree.fetchOutermost(savedOffset); if (collapsedAtSaved == null) { column = mySavedCaretX; line = mySavedCaretY; } else { offsetToUse = collapsedAtSaved.getStartOffset(); } } if (collapsed != null && column == -1) { line = collapsed.getDocument().getLineNumber(collapsed.getStartOffset()); column = myEditor.offsetToLogicalPosition(collapsed.getStartOffset()).column; } boolean oldCaretPositionSaved = myCaretPositionSaved; if (offsetToUse >= 0) { myEditor.getCaretModel().moveToOffset(offsetToUse); } else if (column != -1) { myEditor.getCaretModel().moveToLogicalPosition(new LogicalPosition(line, column)); } else { myEditor.getCaretModel().moveToLogicalPosition(caretPosition); } myCaretPositionSaved = oldCaretPositionSaved; if (!hasBlockSelection && selectionStart < myEditor.getDocument().getTextLength()) { myEditor.getSelectionModel().setSelection(selectionStart, selectionEnd); } if (mySavedCaretShift > 0) { myEditor.getScrollingModel().disableAnimation(); int scrollTo = myEditor.visibleLineToY(myEditor.getCaretModel().getVisualPosition().line) - mySavedCaretShift; myEditor.getScrollingModel().scrollVertically(scrollTo); myEditor.getScrollingModel().enableAnimation(); } }