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 ac7777c49cd1..2e4e11c88c46 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 @@ -16,6 +16,7 @@ package com.intellij.openapi.editor.impl; 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.ProperTextRange; @@ -23,47 +24,49 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent)}. + * 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 ProperTextRange myRange; private final boolean myGreedyLeft; private final boolean myGreedyRight; + private final boolean mySurviveOnExternalChange; private final PersistentRangeMarker.LinesCols myLinesCols; - public ManualRangeMarker(@NotNull FrozenDocument document, @NotNull ProperTextRange range, boolean greedyLeft, boolean greedyRight, boolean surviveOnExternalChange) { - this(range, greedyLeft, greedyRight, surviveOnExternalChange ? PersistentRangeMarker.storeLinesAndCols(range, document) : null); - } - - private ManualRangeMarker(@NotNull ProperTextRange range, + public ManualRangeMarker(@NotNull ProperTextRange range, boolean greedyLeft, boolean greedyRight, + boolean surviveOnExternalChange, @Nullable PersistentRangeMarker.LinesCols linesCols) { myRange = range; myGreedyLeft = greedyLeft; myGreedyRight = greedyRight; + mySurviveOnExternalChange = surviveOnExternalChange; myLinesCols = linesCols; } @Nullable - public ManualRangeMarker getUpdatedRange(@NotNull DocumentEvent event) { + 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()) { ProperTextRange range = myRange.shiftRight(((RetargetRangeMarkers)event).getMoveDestinationOffset() - start); - return new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, myLinesCols == null ? null : PersistentRangeMarker.storeLinesAndCols(range, event.getDocument())); + return new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null); } } - if (myLinesCols != null) { - Pair pair = PersistentRangeMarker - .applyChange(event, myRange, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight, myLinesCols); - return pair == null ? null : new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, pair.second); + if (mySurviveOnExternalChange && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, myRange)) { + PersistentRangeMarker.LinesCols linesCols = myLinesCols != null ? myLinesCols + : PersistentRangeMarker.storeLinesAndCols(myRange, documentBefore); + Pair pair = PersistentRangeMarker.translateViaDiff((DocumentEventImpl)event, linesCols); + if (pair != null) { + return new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, true, pair.second); + } } - + ProperTextRange range = RangeMarkerImpl.applyChange(event, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight); - return range == null ? null : new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, null); + return range == null ? null : new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null); } @NotNull 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 62a7e063e58e..c401dbd17e58 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 @@ -79,7 +79,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { } @Nullable - private static Pair translateViaDiff(final DocumentEventImpl event, LinesCols linesCols) { + static Pair translateViaDiff(final DocumentEventImpl event, LinesCols linesCols) { try { int myStartLine = event.translateLineViaDiffStrict(linesCols.myStartLine); Document document = event.getDocument(); @@ -98,6 +98,13 @@ class PersistentRangeMarker extends RangeMarkerImpl { int end = document.getLineStartOffset(myEndLine) + linesCols.myEndColumn; if (end > document.getTextLength() || end < start) return null; + if (end > event.getDocument().getTextLength() || + myEndLine < myStartLine || + myStartLine == myEndLine && linesCols.myEndColumn < linesCols.myStartColumn || + event.getDocument().getLineCount() < myEndLine) { + return null; + } + return Pair.create(new ProperTextRange(start, end), new LinesCols(myStartLine, linesCols.myStartColumn, myEndLine, linesCols.myEndColumn)); } catch (FilesTooBigForDiffException e) { @@ -122,7 +129,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { } @Nullable - static Pair applyChange(DocumentEvent event, Segment range, int intervalStart, int intervalEnd, boolean greedyLeft, boolean greedyRight, LinesCols linesCols) { + 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); Pair translated = null; if (shouldTranslateViaDiff) { @@ -137,13 +144,6 @@ class PersistentRangeMarker extends RangeMarkerImpl { translated = Pair.create(fallback, lc); } - if (translated.first.getEndOffset() > event.getDocument().getTextLength() || - translated.second.myEndLine < translated.second.myStartLine || - translated.second.myStartLine == translated.second.myEndLine && translated.second.myEndColumn < translated.second.myStartColumn || - event.getDocument().getLineCount() < translated.second.myEndLine) { - return null; - } - return translated; } 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 bb2cd46450b4..02678e34f0f4 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 @@ -71,7 +71,7 @@ class MarkerCache { long key = info.markerCacheKey(); if (range != null && key != 0) { boolean forInjected = info.isForInjected(); - answer.put(key, new ManualRangeMarker(frozen, range, forInjected, forInjected, !forInjected)); + answer.put(key, new ManualRangeMarker(range, forInjected, forInjected, !forInjected, null)); } } frozen = applyEvents(frozen, events, answer); @@ -86,6 +86,7 @@ class MarkerCache { @NotNull List events, final TLongObjectHashMap map) { for (DocumentEvent event : events) { + final FrozenDocument before = frozen; final DocumentEvent corrected; if ((event instanceof RetargetRangeMarkers)) { RetargetRangeMarkers retarget = (RetargetRangeMarkers)event; @@ -101,7 +102,7 @@ class MarkerCache { map.transformValues(new TObjectFunction() { @Override public ManualRangeMarker execute(ManualRangeMarker currentRange) { - return currentRange == null ? null : currentRange.getUpdatedRange(corrected); + return currentRange == null ? null : currentRange.getUpdatedRange(corrected, before); } }); }