diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/ManualRangeMarker.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/ManualRangeMarker.java index c30442b3777e..cccd00c6de65 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/ManualRangeMarker.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/ManualRangeMarker.java @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Segment; import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,19 +28,21 @@ import org.jetbrains.annotations.Nullable; * A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent, FrozenDocument)}. * Can hold PSI-based range and be updated when the document is committed. */ -public class ManualRangeMarker { - private final TextRange myRange; +public class ManualRangeMarker implements Segment { + private final int myStart; + private final int myEnd; private final boolean myGreedyLeft; private final boolean myGreedyRight; private final boolean mySurviveOnExternalChange; private final PersistentRangeMarker.LinesCols myLinesCols; - public ManualRangeMarker(@NotNull TextRange range, + public ManualRangeMarker(int start, int end, boolean greedyLeft, boolean greedyRight, boolean surviveOnExternalChange, @Nullable PersistentRangeMarker.LinesCols linesCols) { - myRange = range; + myStart = start; + myEnd = end; myGreedyLeft = greedyLeft; myGreedyRight = greedyRight; mySurviveOnExternalChange = surviveOnExternalChange; @@ -50,34 +53,39 @@ public class ManualRangeMarker { public ManualRangeMarker getUpdatedRange(@NotNull DocumentEvent event, @NotNull FrozenDocument documentBefore) { if (event instanceof RetargetRangeMarkers) { int start = ((RetargetRangeMarkers)event).getStartOffset(); - if (myRange.getStartOffset() >= start && myRange.getEndOffset() <= ((RetargetRangeMarkers)event).getEndOffset()) { - TextRange range = myRange.shiftRight(((RetargetRangeMarkers)event).getMoveDestinationOffset() - start); - return new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null); + if (myStart >= start && myEnd <= ((RetargetRangeMarkers)event).getEndOffset()) { + int delta = ((RetargetRangeMarkers)event).getMoveDestinationOffset() - start; + return new ManualRangeMarker(myStart + delta, myEnd + delta, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null); } } - if (mySurviveOnExternalChange && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, myRange)) { + if (mySurviveOnExternalChange && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, myStart, myEnd)) { PersistentRangeMarker.LinesCols linesCols = myLinesCols != null ? myLinesCols - : PersistentRangeMarker.storeLinesAndCols(myRange, documentBefore); + : PersistentRangeMarker.storeLinesAndCols(documentBefore, myStart, myEnd); Pair pair = linesCols == null ? null : PersistentRangeMarker.translateViaDiff((DocumentEventImpl)event, linesCols); if (pair != null) { - return new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, true, pair.second); + return new ManualRangeMarker(pair.first.getStartOffset(), pair.first.getEndOffset(), myGreedyLeft, myGreedyRight, true, pair.second); } } - TextRange range = RangeMarkerImpl.applyChange(event, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight); - return range == null ? null : new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null); + TextRange range = RangeMarkerImpl.applyChange(event, myStart, myEnd, myGreedyLeft, myGreedyRight); + return range == null ? null : new ManualRangeMarker(range.getStartOffset(), range.getEndOffset(), myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null); } - @NotNull - public TextRange getRange() { - return myRange; + @Override + public int getStartOffset() { + return myStart; + } + + @Override + public int getEndOffset() { + return myEnd; } @Override public String toString() { - return "ManualRangeMarker" + myRange; + return "ManualRangeMarker" + TextRange.create(this); } } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java index aa877f8f2688..20946c4c4ed3 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java @@ -41,18 +41,17 @@ class PersistentRangeMarker extends RangeMarkerImpl { PersistentRangeMarker(DocumentEx document, int startOffset, int endOffset, boolean register) { super(document, startOffset, endOffset, register); - myLinesCols = ObjectUtils.assertNotNull(storeLinesAndCols(this, document)); + myLinesCols = ObjectUtils.assertNotNull(storeLinesAndCols(document, getStartOffset(), getEndOffset())); } @Nullable - static LinesCols storeLinesAndCols(Segment range, Document myDocument) { + static LinesCols storeLinesAndCols(Document myDocument, int startOffset, int endOffset) { int myStartLine; int myStartColumn; int myEndLine; int myEndColumn; // document might have been changed already - int startOffset = range.getStartOffset(); if (startOffset <= myDocument.getTextLength()) { myStartLine = myDocument.getLineNumber(startOffset); myStartColumn = startOffset - myDocument.getLineStartOffset(myStartLine); @@ -63,7 +62,6 @@ class PersistentRangeMarker extends RangeMarkerImpl { else { return null; } - int endOffset = range.getEndOffset(); if (endOffset <= myDocument.getTextLength()) { myEndLine = myDocument.getLineNumber(endOffset); myEndColumn = endOffset - myDocument.getLineStartOffset(myEndLine); @@ -130,7 +128,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { @Nullable private static Pair applyChange(DocumentEvent event, Segment range, int intervalStart, int intervalEnd, boolean greedyLeft, boolean greedyRight, LinesCols linesCols) { - final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, range); + final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, range.getStartOffset(), range.getEndOffset()); Pair translated = null; if (shouldTranslateViaDiff) { translated = translateViaDiff((DocumentEventImpl)event, linesCols); @@ -139,7 +137,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { TextRange fallback = applyChange(event, intervalStart, intervalEnd, greedyLeft, greedyRight); if (fallback == null) return null; - LinesCols lc = storeLinesAndCols(fallback, event.getDocument()); + LinesCols lc = storeLinesAndCols(event.getDocument(), fallback.getStartOffset(), fallback.getEndOffset()); if (lc == null) return null; translated = Pair.create(fallback, lc); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java index df4477b0c226..788bb24ad3aa 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java @@ -16,7 +16,6 @@ package com.intellij.openapi.editor.impl; import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.util.Segment; import org.jetbrains.annotations.NotNull; /** @@ -29,17 +28,18 @@ class PersistentRangeMarkerUtil { * identified by the given event. * * @param e event that describes document change - * @param rangeMarker target range marker which update strategy should be selected + * @param rangeStart target range marker start, for which update strategy should be selected + * @param rangeEnd target range marker end * @return true if target document range referenced by the given range marker should be translated via * diff algorithm; false otherwise */ - static boolean shouldTranslateViaDiff(@NotNull DocumentEvent e, @NotNull Segment rangeMarker) { + static boolean shouldTranslateViaDiff(@NotNull DocumentEvent e, int rangeStart, int rangeEnd) { if (e.isWholeTextReplaced()) { // Perform translation if the whole text is replaced. return true; } - if (e.getOffset() >= rangeMarker.getEndOffset() || e.getOffset() + e.getOldLength() <= rangeMarker.getStartOffset()) { + if (e.getOffset() >= rangeEnd || e.getOffset() + e.getOldLength() <= rangeStart) { // Don't perform complex processing if the change doesn't affect target range. return false; } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/MarkerCache.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/MarkerCache.java index 159c65fe9fba..f8e612759449 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/MarkerCache.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/MarkerCache.java @@ -21,8 +21,8 @@ import com.intellij.openapi.editor.impl.ManualRangeMarker; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.UnfairTextRange; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -94,11 +94,12 @@ class MarkerCache { while (i < markers.length) { SelfElementInfo info = infos.get(i); boolean forInjected = info.isForInjected(); - TextRange range = ObjectUtils.assertNotNull(info.getPsiRange()); - markers[i] = new ManualRangeMarker(range, forInjected, forInjected, !forInjected, null); + int start = info.getPsiStartOffset(); + int end = info.getPsiEndOffset(); + markers[i] = new ManualRangeMarker(start, end, forInjected, forInjected, !forInjected, null); i++; - while (i < markers.length && rangeEquals(infos.get(i), range, forInjected)) { + while (i < markers.length && rangeEquals(infos.get(i), start, end, forInjected)) { markers[i] = markers[i - 1]; i++; } @@ -106,8 +107,8 @@ class MarkerCache { return markers; } - private static boolean rangeEquals(SelfElementInfo info, TextRange range, boolean injected) { - return range.getStartOffset() == info.getPsiStartOffset() && range.getEndOffset() == info.getPsiEndOffset() && injected == info.isForInjected(); + private static boolean rangeEquals(SelfElementInfo info, int start, int end, boolean injected) { + return start == info.getPsiStartOffset() && end == info.getPsiEndOffset() && injected == info.isForInjected(); } private static UpdatedRanges applyEvents(@NotNull List events, final UpdatedRanges struct) { @@ -150,8 +151,7 @@ class MarkerCache { UpdatedRanges updated = getUpdatedMarkers(frozen, events); for (int i = 0; i < updated.myMarkers.length; i++) { - ManualRangeMarker newRangeMarker = updated.myMarkers[i]; - updated.mySortedInfos.get(i).setRange(newRangeMarker == null ? null : newRangeMarker.getRange()); + updated.mySortedInfos.get(i).setRange(updated.myMarkers[i]); } myUpdatedRanges = null; @@ -180,7 +180,7 @@ class MarkerCache { UpdatedRanges struct = getUpdatedMarkers(frozen, events); int i = Collections.binarySearch(struct.mySortedInfos, info, BY_RANGE_KEY); ManualRangeMarker updated = i >= 0 ? struct.myMarkers[i] : null; - return updated == null ? null : updated.getRange(); + return updated == null ? null : new UnfairTextRange(updated.getStartOffset(), updated.getEndOffset()); } void rangeChanged() { diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java index 654101355827..4cde8efbcf51 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java @@ -59,7 +59,7 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran protected void changedUpdateImpl(@NotNull DocumentEvent e) { // todo Denis Zhdanov DocumentEventImpl event = (DocumentEventImpl)e; - final boolean shouldTranslateViaDiff = isValid() && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this); + final boolean shouldTranslateViaDiff = isValid() && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, getStartOffset(), getEndOffset()); boolean wasTranslatedViaDiff = shouldTranslateViaDiff; if (shouldTranslateViaDiff) { wasTranslatedViaDiff = translatedViaDiff(e, event);