Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Batkovich
2015-10-29 18:22:04 +03:00
8 changed files with 73 additions and 65 deletions
@@ -19,7 +19,8 @@ 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;
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 ProperTextRange 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 ProperTextRange 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()) {
ProperTextRange 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);
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair =
: PersistentRangeMarker.storeLinesAndCols(documentBefore, myStart, myEnd);
Pair<TextRange, PersistentRangeMarker.LinesCols> 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);
}
}
ProperTextRange 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 ProperTextRange 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);
}
}
@@ -20,8 +20,8 @@ import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.ObjectUtils;
import com.intellij.util.diff.FilesTooBigForDiffException;
import org.jetbrains.annotations.NotNull;
@@ -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);
@@ -79,7 +77,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
}
@Nullable
static Pair<ProperTextRange, LinesCols> translateViaDiff(@NotNull final DocumentEventImpl event, @NotNull LinesCols linesCols) {
static Pair<TextRange, LinesCols> translateViaDiff(@NotNull final DocumentEventImpl event, @NotNull LinesCols linesCols) {
try {
int myStartLine = event.translateLineViaDiffStrict(linesCols.myStartLine);
Document document = event.getDocument();
@@ -105,7 +103,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
return null;
}
return Pair.create(new ProperTextRange(start, end), new LinesCols(myStartLine, linesCols.myStartColumn, myEndLine, linesCols.myEndColumn));
return Pair.create(new TextRange(start, end), new LinesCols(myStartLine, linesCols.myStartColumn, myEndLine, linesCols.myEndColumn));
}
catch (FilesTooBigForDiffException e) {
return null;
@@ -116,7 +114,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
protected void changedUpdateImpl(@NotNull DocumentEvent e) {
if (!isValid()) return;
Pair<ProperTextRange, LinesCols> pair =
Pair<TextRange, LinesCols> pair =
applyChange(e, this, intervalStart(), intervalEnd(), isGreedyToLeft(), isGreedyToRight(), myLinesCols);
if (pair == null) {
invalidate(e);
@@ -129,17 +127,17 @@ class PersistentRangeMarker extends RangeMarkerImpl {
}
@Nullable
private static Pair<ProperTextRange, LinesCols> applyChange(DocumentEvent event, Segment range, int intervalStart, int intervalEnd, boolean greedyLeft, boolean greedyRight, LinesCols linesCols) {
final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, range);
Pair<ProperTextRange, LinesCols> translated = null;
private static Pair<TextRange, LinesCols> applyChange(DocumentEvent event, Segment range, int intervalStart, int intervalEnd, boolean greedyLeft, boolean greedyRight, LinesCols linesCols) {
final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, range.getStartOffset(), range.getEndOffset());
Pair<TextRange, LinesCols> translated = null;
if (shouldTranslateViaDiff) {
translated = translateViaDiff((DocumentEventImpl)event, linesCols);
}
if (translated == null) {
ProperTextRange fallback = applyChange(event, intervalStart, intervalEnd, greedyLeft, greedyRight);
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);
@@ -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 <code>true</code> if target document range referenced by the given range marker should be translated via
* diff algorithm; <code>false</code> 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;
}
@@ -21,6 +21,8 @@ import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.RangeMarkerEx;
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UnfairTextRange;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NonNls;
@@ -172,7 +174,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
protected void changedUpdateImpl(@NotNull DocumentEvent e) {
if (!isValid()) return;
ProperTextRange newRange = applyChange(e, intervalStart(), intervalEnd(), isGreedyToLeft(), isGreedyToRight());
TextRange newRange = applyChange(e, intervalStart(), intervalEnd(), isGreedyToLeft(), isGreedyToRight());
if (newRange == null) {
invalidate(e);
return;
@@ -183,9 +185,9 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
}
@Nullable
static ProperTextRange applyChange(@NotNull DocumentEvent e, int intervalStart, int intervalEnd, boolean isGreedyToLeft, boolean isGreedyToRight) {
static TextRange applyChange(@NotNull DocumentEvent e, int intervalStart, int intervalEnd, boolean isGreedyToLeft, boolean isGreedyToRight) {
if (intervalStart == intervalEnd) {
return processIfOnePoint(e, intervalStart, intervalEnd, isGreedyToRight);
return processIfOnePoint(e, intervalStart, isGreedyToRight);
}
final int offset = e.getOffset();
@@ -194,26 +196,26 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
// changes after the end.
if (intervalEnd < offset) {
return new ProperTextRange(intervalStart, intervalEnd);
return new UnfairTextRange(intervalStart, intervalEnd);
}
if (!isGreedyToRight && intervalEnd == offset) {
// handle replaceString that was minimized and resulted in insertString at the range end
if (e instanceof DocumentEventImpl && oldLength == 0 && ((DocumentEventImpl)e).getInitialStartOffset() < offset) {
return new ProperTextRange(intervalStart, intervalEnd + newLength);
return new UnfairTextRange(intervalStart, intervalEnd + newLength);
}
return new ProperTextRange(intervalStart, intervalEnd);
return new UnfairTextRange(intervalStart, intervalEnd);
}
// changes before start
if (intervalStart > offset + oldLength) {
return new ProperTextRange(intervalStart + newLength - oldLength, intervalEnd + newLength - oldLength);
return new UnfairTextRange(intervalStart + newLength - oldLength, intervalEnd + newLength - oldLength);
}
if (!isGreedyToLeft && intervalStart == offset + oldLength) {
// handle replaceString that was minimized and resulted in insertString at the range start
if (e instanceof DocumentEventImpl && oldLength == 0 && ((DocumentEventImpl)e).getInitialStartOffset() + ((DocumentEventImpl)e).getInitialOldLength() > offset) {
return new ProperTextRange(intervalStart - oldLength, intervalEnd + newLength - oldLength);
return new UnfairTextRange(intervalStart - oldLength, intervalEnd + newLength - oldLength);
}
return new ProperTextRange(intervalStart + newLength - oldLength, intervalEnd + newLength - oldLength);
return new UnfairTextRange(intervalStart + newLength - oldLength, intervalEnd + newLength - oldLength);
}
// Changes inside marker's area. Expand/collapse.
@@ -229,14 +231,14 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
}
if (intervalEnd >= offset && intervalEnd <= offset + oldLength && intervalStart < offset) {
return new ProperTextRange(intervalStart, offset);
return new UnfairTextRange(intervalStart, offset);
}
return null;
}
@Nullable
private static ProperTextRange processIfOnePoint(@NotNull DocumentEvent e, int intervalStart, int intervalEnd, boolean greedyRight) {
private static TextRange processIfOnePoint(@NotNull DocumentEvent e, int intervalStart, boolean greedyRight) {
int offset = e.getOffset();
int oldLength = e.getOldLength();
int oldEnd = offset + oldLength;
@@ -245,14 +247,14 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx
}
if (offset == intervalStart && oldLength == 0 && greedyRight) {
return new ProperTextRange(intervalStart, intervalEnd + e.getNewLength());
return new UnfairTextRange(intervalStart, intervalStart + e.getNewLength());
}
if (intervalStart > oldEnd || intervalStart == oldEnd && oldLength > 0) {
return new ProperTextRange(intervalStart + e.getNewLength() - oldLength, intervalEnd + e.getNewLength() - oldLength);
return new UnfairTextRange(intervalStart + e.getNewLength() - oldLength, intervalStart + e.getNewLength() - oldLength);
}
return new ProperTextRange(intervalStart, intervalEnd);
return new UnfairTextRange(intervalStart, intervalStart);
}
@NonNls
@@ -147,7 +147,7 @@ class AnchorElementInfo extends SelfElementInfo {
@Nullable
@Override
public ProperTextRange getPsiRange() {
public TextRange getPsiRange() {
if (getStubId() != -1) {
switchToTree();
}
@@ -20,9 +20,9 @@ import com.intellij.openapi.editor.impl.FrozenDocument;
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.ProperTextRange;
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();
ProperTextRange 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, ProperTextRange 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<DocumentEvent> 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;
@@ -176,11 +176,11 @@ class MarkerCache {
}
@Nullable
ProperTextRange getUpdatedRange(@NotNull SelfElementInfo info, @NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
TextRange getUpdatedRange(@NotNull SelfElementInfo info, @NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
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() {
@@ -102,13 +102,13 @@ public class SelfElementInfo extends SmartPointerElementInfo {
@Nullable
@Override
public ProperTextRange getPsiRange() {
public TextRange getPsiRange() {
return calcPsiRange();
}
@Nullable
private ProperTextRange calcPsiRange() {
return hasRange() ? ProperTextRange.create(myStartOffset, myEndOffset) : null;
private TextRange calcPsiRange() {
return hasRange() ? new UnfairTextRange(myStartOffset, myEndOffset) : null;
}
@Override
@@ -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);