mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
less text range allocations during smart pointer update (IDEA-49250)
This commit is contained in:
@@ -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<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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<TextRange, LinesCols> 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<TextRange, LinesCols> 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);
|
||||
|
||||
+4
-4
@@ -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,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<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;
|
||||
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user