mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-124155 Performance problem on live search in long lines
This commit is contained in:
+4
-4
@@ -203,12 +203,12 @@ public class UpdateHighlightersUtil {
|
||||
final boolean[] changed = {false};
|
||||
RangeMarkerTree.sweep(new RangeMarkerTree.Generator<HighlightInfo>(){
|
||||
@Override
|
||||
public boolean generate(Processor<HighlightInfo> processor) {
|
||||
public boolean generateInStartOffsetOrder(@NotNull Processor<HighlightInfo> processor) {
|
||||
return ContainerUtil.process(infos, processor);
|
||||
}
|
||||
}, new SweepProcessor<HighlightInfo>() {
|
||||
@Override
|
||||
public boolean process(int offset, HighlightInfo info, boolean atStart, Collection<HighlightInfo> overlappingIntervals) {
|
||||
public boolean process(int offset, HighlightInfo info, boolean atStart, @NotNull Collection<HighlightInfo> overlappingIntervals) {
|
||||
if (!atStart) return true;
|
||||
if (!info.isFromInjection() && info.getEndOffset() < document.getTextLength() && (info.getEndOffset() <= startOffset || info.getStartOffset()>=endOffset)) return true; // injections are oblivious to restricting range
|
||||
|
||||
@@ -276,12 +276,12 @@ public class UpdateHighlightersUtil {
|
||||
final boolean[] changed = {false};
|
||||
RangeMarkerTree.sweep(new RangeMarkerTree.Generator<HighlightInfo>(){
|
||||
@Override
|
||||
public boolean generate(final Processor<HighlightInfo> processor) {
|
||||
public boolean generateInStartOffsetOrder(@NotNull final Processor<HighlightInfo> processor) {
|
||||
return ContainerUtil.process(infos, processor);
|
||||
}
|
||||
}, new SweepProcessor<HighlightInfo>() {
|
||||
@Override
|
||||
public boolean process(int offset, HighlightInfo info, boolean atStart, Collection<HighlightInfo> overlappingIntervals) {
|
||||
public boolean process(int offset, HighlightInfo info, boolean atStart, @NotNull Collection<HighlightInfo> overlappingIntervals) {
|
||||
if (!atStart) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.ex;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface SweepProcessor<T> {
|
||||
boolean process(int offset, T interval, boolean atStart, Collection<T> overlappingIntervals);
|
||||
boolean process(int offset, T interval, boolean atStart, @NotNull Collection<T> overlappingIntervals);
|
||||
}
|
||||
|
||||
@@ -558,8 +558,38 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
return processContaining(root.getRight(), offset, processor, modCountBefore, delta);
|
||||
}
|
||||
|
||||
public interface PeekableIterator<T> extends DisposableIterator<T> {
|
||||
T peek();
|
||||
PeekableIterator EMPTY = new PeekableIterator() {
|
||||
@Override
|
||||
public Object peek() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
DisposableIterator<T> overlappingIterator(@NotNull final TextRangeInterval rangeInterval) {
|
||||
PeekableIterator<T> overlappingIterator(@NotNull final TextRangeInterval rangeInterval) {
|
||||
TextRange.assertProperRange(rangeInterval);
|
||||
|
||||
l.readLock().lock();
|
||||
@@ -570,13 +600,13 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
final IntervalNode<T> firstOverlap = findMinOverlappingWith(getRoot(), rangeInterval, modCount, 0);
|
||||
if (firstOverlap == null) {
|
||||
l.readLock().unlock();
|
||||
return DisposableIterator.EMPTY;
|
||||
return PeekableIterator.EMPTY;
|
||||
}
|
||||
final int firstOverlapDelta = firstOverlap.computeDeltaUpToRoot();
|
||||
final int firstOverlapStart = firstOverlap.intervalStart() + firstOverlapDelta;
|
||||
final int modCountBefore = modCount;
|
||||
|
||||
return new DisposableIterator<T>() {
|
||||
return new PeekableIterator<T>() {
|
||||
private IntervalNode<T> currentNode = firstOverlap;
|
||||
private int deltaUpToRootExclusive = firstOverlapDelta-firstOverlap.delta;
|
||||
private int indexInCurrentList = 0;
|
||||
@@ -624,6 +654,12 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T peek() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new IncorrectOperationException();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -305,14 +305,14 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
|
||||
public boolean sweep(final int start, final int end, @NotNull final SweepProcessor<T> sweepProcessor) {
|
||||
return sweep(new Generator<T>() {
|
||||
@Override
|
||||
public boolean generate(Processor<T> processor) {
|
||||
public boolean generateInStartOffsetOrder(@NotNull Processor<T> processor) {
|
||||
return processOverlappingWith(start, end, processor);
|
||||
}
|
||||
}, sweepProcessor);
|
||||
}
|
||||
|
||||
public interface Generator<T> {
|
||||
boolean generate(Processor<T> processor);
|
||||
boolean generateInStartOffsetOrder(@NotNull Processor<T> processor);
|
||||
}
|
||||
|
||||
public static <T extends Segment> boolean sweep(@NotNull Generator<T> generator, @NotNull final SweepProcessor<T> sweepProcessor) {
|
||||
@@ -323,7 +323,7 @@ public class RangeMarkerTree<T extends RangeMarkerEx> extends IntervalTreeImpl<T
|
||||
}
|
||||
});
|
||||
final List<T> starts = new ArrayList<T>();
|
||||
if (!generator.generate(new Processor<T>() {
|
||||
if (!generator.generateInStartOffsetOrder(new Processor<T>() {
|
||||
@Override
|
||||
public boolean process(T marker) {
|
||||
// decide whether previous marker ends here or new marker begins
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public interface RangeHighlighterEx extends RangeHighlighter, RangeMarkerEx {
|
||||
RangeHighlighterEx[] EMPTY_ARRAY = new RangeHighlighterEx[0];
|
||||
boolean isAfterEndOfLine();
|
||||
@@ -36,8 +38,13 @@ public interface RangeHighlighterEx extends RangeHighlighter, RangeMarkerEx {
|
||||
int getAffectedAreaStartOffset();
|
||||
|
||||
int getAffectedAreaEndOffset();
|
||||
@Override
|
||||
long getId();
|
||||
|
||||
void setTextAttributes(@NotNull TextAttributes textAttributes);
|
||||
|
||||
Comparator<RangeHighlighterEx> BY_AFFECTED_START_OFFSET = new Comparator<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public int compare(RangeHighlighterEx r1, RangeHighlighterEx r2) {
|
||||
return r1.getAffectedAreaStartOffset() - r2.getAffectedAreaStartOffset();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,7 +44,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.MarkupModelImpl");
|
||||
@@ -52,16 +54,19 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
|
||||
private RangeHighlighter[] myCachedHighlighters;
|
||||
private final List<MarkupModelListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private final RangeHighlighterTree myHighlighterTree;
|
||||
private final RangeHighlighterTree myHighlighterTree; // this tree holds regular highlighters with target = HighlighterTargetArea.EXACT_RANGE
|
||||
private final RangeHighlighterTree myHighlighterTreeForLines; // this tree holds line range highlighters with target = HighlighterTargetArea.LINES_IN_RANGE
|
||||
|
||||
MarkupModelImpl(@NotNull DocumentEx document) {
|
||||
myDocument = document;
|
||||
myHighlighterTree = new RangeHighlighterTree(myDocument, this);
|
||||
myHighlighterTree = new RangeHighlighterTree(document, this);
|
||||
myHighlighterTreeForLines = new RangeHighlighterTree(document, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
myHighlighterTree.dispose();
|
||||
myHighlighterTreeForLines.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,10 +101,12 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
public RangeHighlighter[] getAllHighlighters() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (myCachedHighlighters == null) {
|
||||
int size = myHighlighterTree.size();
|
||||
int size = myHighlighterTree.size() + myHighlighterTreeForLines.size();
|
||||
if (size == 0) return RangeHighlighter.EMPTY_ARRAY;
|
||||
List<RangeHighlighterEx> list = new ArrayList<RangeHighlighterEx>(size);
|
||||
myHighlighterTree.process(new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list));
|
||||
CommonProcessors.CollectProcessor<RangeHighlighterEx> collectProcessor = new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list);
|
||||
myHighlighterTree.process(collectProcessor);
|
||||
myHighlighterTreeForLines.process(collectProcessor);
|
||||
myCachedHighlighters = list.toArray(new RangeHighlighter[list.size()]);
|
||||
}
|
||||
return myCachedHighlighters;
|
||||
@@ -150,7 +157,11 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
boolean greedyToRight,
|
||||
int layer) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
myHighlighterTree.addInterval(marker, start, end, greedyToLeft, greedyToRight, layer);
|
||||
treeFor(marker).addInterval(marker, start, end, greedyToLeft, greedyToRight, layer);
|
||||
}
|
||||
|
||||
private RangeHighlighterTree treeFor(RangeHighlighter marker) {
|
||||
return marker.getTargetArea() == HighlighterTargetArea.EXACT_RANGE ? myHighlighterTree : myHighlighterTreeForLines;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,7 +180,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
myCachedHighlighters = null;
|
||||
if (!segmentHighlighter.isValid()) return;
|
||||
|
||||
boolean removed = myHighlighterTree.removeInterval((RangeHighlighterEx)segmentHighlighter);
|
||||
boolean removed = treeFor(segmentHighlighter).removeInterval((RangeHighlighterEx)segmentHighlighter);
|
||||
LOG.assertTrue(removed);
|
||||
}
|
||||
|
||||
@@ -181,6 +192,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
}
|
||||
myCachedHighlighters = null;
|
||||
myHighlighterTree.clear();
|
||||
myHighlighterTreeForLines.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -235,30 +247,69 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
@Override
|
||||
public boolean containsHighlighter(@NotNull final RangeHighlighter highlighter) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
return !myHighlighterTree
|
||||
.processOverlappingWith(highlighter.getStartOffset(), highlighter.getEndOffset(), new Processor<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public boolean process(RangeHighlighterEx h) {
|
||||
return h.getId() != ((RangeHighlighterEx)highlighter).getId();
|
||||
}
|
||||
});
|
||||
Processor<RangeHighlighterEx> equalId = new Processor<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public boolean process(RangeHighlighterEx h) {
|
||||
return h.getId() != ((RangeHighlighterEx)highlighter).getId();
|
||||
}
|
||||
};
|
||||
return !treeFor(highlighter).processOverlappingWith(highlighter.getStartOffset(), highlighter.getEndOffset(), equalId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processRangeHighlightersOverlappingWith(int start, int end, @NotNull Processor<? super RangeHighlighterEx> processor) {
|
||||
TextRangeInterval rangeInterval = roundToLineBoundaries(start, end);
|
||||
return myHighlighterTree.processOverlappingWith(rangeInterval.getStartOffset(), rangeInterval.getEndOffset(), processor);
|
||||
if (!myHighlighterTree.processOverlappingWith(start, end, processor)) return false;
|
||||
TextRangeInterval lines = roundToLineBoundaries(start, end);
|
||||
return myHighlighterTreeForLines.processOverlappingWith(lines.getStartOffset(), lines.getEndOffset(), processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processRangeHighlightersOutside(int start, int end, @NotNull Processor<? super RangeHighlighterEx> processor) {
|
||||
return myHighlighterTree.processOverlappingWithOutside(start, end, processor);
|
||||
return myHighlighterTree.processOverlappingWithOutside(start, end, processor)
|
||||
&& myHighlighterTreeForLines.processOverlappingWithOutside(start, end, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public DisposableIterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
|
||||
return myHighlighterTree.overlappingIterator(roundToLineBoundaries(startOffset, endOffset));
|
||||
IntervalTreeImpl.PeekableIterator<RangeHighlighterEx> exact = myHighlighterTree.overlappingIterator(new TextRangeInterval(startOffset, endOffset));
|
||||
IntervalTreeImpl.PeekableIterator<RangeHighlighterEx> lines = myHighlighterTreeForLines.overlappingIterator(roundToLineBoundaries(startOffset, endOffset));
|
||||
return merge(exact, lines);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <T extends RangeHighlighterEx> DisposableIterator<T> merge(@NotNull final IntervalTreeImpl.PeekableIterator<T> iterator1, @NotNull final IntervalTreeImpl.PeekableIterator<T> iterator2) {
|
||||
return new DisposableIterator<T>() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
iterator1.dispose();
|
||||
iterator2.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator1.hasNext() || iterator2.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
T t1 = iterator1.hasNext() ? iterator1.peek() : null;
|
||||
T t2 = iterator2.hasNext() ? iterator2.peek() : null;
|
||||
if (t1 == null) {
|
||||
return iterator2.next();
|
||||
}
|
||||
if (t2 == null) {
|
||||
return iterator1.next();
|
||||
}
|
||||
int compare = RangeHighlighterEx.BY_AFFECTED_START_OFFSET.compare(t1, t2);
|
||||
return (compare < 0 ? iterator1 : iterator2).next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -271,7 +322,22 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
|
||||
@Override
|
||||
public boolean sweep(int start, int end, @NotNull SweepProcessor<RangeHighlighterEx> sweepProcessor) {
|
||||
TextRangeInterval rangeInterval = roundToLineBoundaries(start, end);
|
||||
return myHighlighterTree.sweep(rangeInterval.getStartOffset(), rangeInterval.getEndOffset(), sweepProcessor);
|
||||
TextRangeInterval lines = roundToLineBoundaries(start, end);
|
||||
List<RangeHighlighterEx> linesInRange = new ArrayList<RangeHighlighterEx>();
|
||||
myHighlighterTreeForLines.processOverlappingWith(lines.getStartOffset(), lines.getEndOffset(), new CommonProcessors.CollectProcessor<RangeHighlighterEx>(linesInRange));
|
||||
if (linesInRange.isEmpty()) {
|
||||
return myHighlighterTree.sweep(start, end, sweepProcessor);
|
||||
}
|
||||
final List<RangeHighlighterEx> highlighters = new ArrayList<RangeHighlighterEx>();
|
||||
myHighlighterTree.processOverlappingWith(start, end, new CommonProcessors.CollectProcessor<RangeHighlighterEx>(highlighters));
|
||||
highlighters.addAll(linesInRange);
|
||||
Collections.sort(highlighters, RangeHighlighterEx.BY_AFFECTED_START_OFFSET);
|
||||
|
||||
return RangeMarkerTree.sweep(new RangeMarkerTree.Generator<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public boolean generateInStartOffsetOrder(@NotNull Processor<RangeHighlighterEx> processor) {
|
||||
return ContainerUtil.process(highlighters, processor);
|
||||
}
|
||||
}, sweepProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,9 @@ class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx
|
||||
int end,
|
||||
int layer,
|
||||
@NotNull HighlighterTargetArea target,
|
||||
TextAttributes textAttributes, boolean greedyToLeft, boolean greedyToRight) {
|
||||
TextAttributes textAttributes,
|
||||
boolean greedyToLeft,
|
||||
boolean greedyToRight) {
|
||||
super((DocumentEx)model.getDocument(), start, end,false);
|
||||
|
||||
data = new RangeHighlighterData(model, target, textAttributes) {
|
||||
|
||||
@@ -24,16 +24,21 @@ import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.ex.*;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.editor.markup.*;
|
||||
import com.intellij.openapi.editor.markup.EffectType;
|
||||
import com.intellij.openapi.editor.markup.HighlighterLayer;
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public final class IterationState {
|
||||
@@ -75,12 +80,6 @@ public final class IterationState {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
private static final Comparator<RangeHighlighterEx> BY_AFFECTED_START_OFFSET = new Comparator<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public int compare(RangeHighlighterEx r1, RangeHighlighterEx r2) {
|
||||
return r1.getAffectedAreaStartOffset() - r2.getAffectedAreaStartOffset();
|
||||
}
|
||||
};
|
||||
|
||||
private final TextAttributes myMergedAttributes = new TextAttributes();
|
||||
|
||||
@@ -193,15 +192,9 @@ public final class IterationState {
|
||||
// we have to get all highlighters in advance and sort them by affected offsets
|
||||
// since these can be different from the real offsets the highlighters are sorted by in the tree. (See LINES_IN_RANGE perverts)
|
||||
final List<RangeHighlighterEx> list = new ArrayList<RangeHighlighterEx>();
|
||||
markupModel.processRangeHighlightersOverlappingWith(start, end, new Processor<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public boolean process(RangeHighlighterEx highlighter) {
|
||||
list.add(highlighter);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
markupModel.processRangeHighlightersOverlappingWith(start, end, new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list));
|
||||
highlighters = list.isEmpty() ? RangeHighlighterEx.EMPTY_ARRAY : list.toArray(new RangeHighlighterEx[list.size()]);
|
||||
Arrays.sort(highlighters, BY_AFFECTED_START_OFFSET);
|
||||
Arrays.sort(highlighters, RangeHighlighterEx.BY_AFFECTED_START_OFFSET);
|
||||
|
||||
int skipped = 0;
|
||||
while (i < highlighters.length) {
|
||||
|
||||
+38
-19
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.command.impl.UndoManagerImpl;
|
||||
import com.intellij.openapi.command.undo.UndoManager;
|
||||
@@ -25,11 +23,14 @@ import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.MarkupModelEx;
|
||||
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
|
||||
import com.intellij.openapi.editor.ex.RangeMarkerEx;
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
|
||||
import com.intellij.openapi.editor.markup.MarkupModel;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
@@ -37,7 +38,10 @@ import com.intellij.psi.impl.PsiDocumentManagerImpl;
|
||||
import com.intellij.psi.impl.PsiToDocumentSynchronizer;
|
||||
import com.intellij.testFramework.LeakHunter;
|
||||
import com.intellij.testFramework.LightPlatformTestCase;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.Timings;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -57,29 +61,20 @@ public class RangeMarkerTest extends LightPlatformTestCase {
|
||||
return;
|
||||
}
|
||||
boolean oldVerify = RedBlackTree.VERIFY;
|
||||
RedBlackTree.VERIFY = true;
|
||||
RedBlackTree.VERIFY = !isPerformanceTest();
|
||||
final Throwable[] ex = {null};
|
||||
try {
|
||||
if (getTestName(false).contains("NoCommand")) {
|
||||
super.runTest();
|
||||
return;
|
||||
}
|
||||
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
RangeMarkerTest.super.runTest();
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
ex[0] = throwable;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "", null);
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), new ThrowableComputable<Void, Throwable>() {
|
||||
@Override
|
||||
public Void compute() throws Throwable {
|
||||
RangeMarkerTest.super.runTest();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
RedBlackTree.VERIFY = oldVerify;
|
||||
@@ -1071,4 +1066,28 @@ public class RangeMarkerTest extends LightPlatformTestCase {
|
||||
m.dispose();
|
||||
assertFalse(m.isValid());
|
||||
}
|
||||
|
||||
public void testRangeHighlighterLinesInRangeForLongLinePerformance() throws Exception {
|
||||
final int N = 50000;
|
||||
Document document = EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol('x', 2*N));
|
||||
|
||||
final MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, ourProject, true);
|
||||
for (int i=0; i<N-1;i++) {
|
||||
markupModel.addRangeHighlighter(2*i, 2*i+1, 0, null, HighlighterTargetArea.EXACT_RANGE);
|
||||
}
|
||||
markupModel.addRangeHighlighter(N/2, N/2+1, 0, null, HighlighterTargetArea.LINES_IN_RANGE);
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("slow highlighters lookup", (int)(N*Math.log(N)/1000), new ThrowableRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<RangeHighlighterEx> list = new ArrayList<RangeHighlighterEx>();
|
||||
CommonProcessors.CollectProcessor<RangeHighlighterEx> coll = new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list);
|
||||
for (int i=0; i<N-1;i++) {
|
||||
list.clear();
|
||||
markupModel.processRangeHighlightersOverlappingWith(2*i, 2*i+1, coll);
|
||||
assertEquals(2, list.size()); // 1 line plus one exact range marker
|
||||
}
|
||||
}
|
||||
}).assertTiming();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user