From ba23594a683098678d2bbfdf704f91322f5f857f Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 28 Apr 2014 13:40:47 +0400 Subject: [PATCH] IDEA-124155 Performance problem on live search in long lines --- .../daemon/impl/UpdateHighlightersUtil.java | 8 +- .../openapi/editor/ex/SweepProcessor.java | 6 +- .../openapi/editor/impl/IntervalTreeImpl.java | 42 ++++++- .../openapi/editor/impl/RangeMarkerTree.java | 8 +- .../openapi/editor/ex/RangeHighlighterEx.java | 11 +- .../openapi/editor/impl/MarkupModelImpl.java | 104 ++++++++++++++---- .../editor/impl/RangeHighlighterImpl.java | 6 +- .../openapi/editor/impl/IterationState.java | 27 ++--- .../openapi/editor/impl/RangeMarkerTest.java | 57 ++++++---- 9 files changed, 197 insertions(+), 72 deletions(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java index c123b5c7835c..f3fe2bddcb11 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java @@ -203,12 +203,12 @@ public class UpdateHighlightersUtil { final boolean[] changed = {false}; RangeMarkerTree.sweep(new RangeMarkerTree.Generator(){ @Override - public boolean generate(Processor processor) { + public boolean generateInStartOffsetOrder(@NotNull Processor processor) { return ContainerUtil.process(infos, processor); } }, new SweepProcessor() { @Override - public boolean process(int offset, HighlightInfo info, boolean atStart, Collection overlappingIntervals) { + public boolean process(int offset, HighlightInfo info, boolean atStart, @NotNull Collection 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(){ @Override - public boolean generate(final Processor processor) { + public boolean generateInStartOffsetOrder(@NotNull final Processor processor) { return ContainerUtil.process(infos, processor); } }, new SweepProcessor() { @Override - public boolean process(int offset, HighlightInfo info, boolean atStart, Collection overlappingIntervals) { + public boolean process(int offset, HighlightInfo info, boolean atStart, @NotNull Collection overlappingIntervals) { if (!atStart) { return true; } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/ex/SweepProcessor.java b/platform/core-impl/src/com/intellij/openapi/editor/ex/SweepProcessor.java index 8d89b8bab76d..0a0dd00f2df7 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/ex/SweepProcessor.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/ex/SweepProcessor.java @@ -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 { - boolean process(int offset, T interval, boolean atStart, Collection overlappingIntervals); + boolean process(int offset, T interval, boolean atStart, @NotNull Collection overlappingIntervals); } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index 13df844563e3..a48ba0469c11 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -558,8 +558,38 @@ public abstract class IntervalTreeImpl extends RedBla return processContaining(root.getRight(), offset, processor, modCountBefore, delta); } + public interface PeekableIterator extends DisposableIterator { + 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 overlappingIterator(@NotNull final TextRangeInterval rangeInterval) { + PeekableIterator overlappingIterator(@NotNull final TextRangeInterval rangeInterval) { TextRange.assertProperRange(rangeInterval); l.readLock().lock(); @@ -570,13 +600,13 @@ public abstract class IntervalTreeImpl extends RedBla final IntervalNode 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() { + return new PeekableIterator() { private IntervalNode currentNode = firstOverlap; private int deltaUpToRootExclusive = firstOverlapDelta-firstOverlap.delta; private int indexInCurrentList = 0; @@ -624,6 +654,12 @@ public abstract class IntervalTreeImpl extends RedBla return t; } + @Override + public T peek() { + if (!hasNext()) throw new NoSuchElementException(); + return current; + } + @Override public void remove() { throw new IncorrectOperationException(); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index b0bf56ec0af7..2e7ebadc3892 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -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 extends IntervalTreeImpl sweepProcessor) { return sweep(new Generator() { @Override - public boolean generate(Processor processor) { + public boolean generateInStartOffsetOrder(@NotNull Processor processor) { return processOverlappingWith(start, end, processor); } }, sweepProcessor); } public interface Generator { - boolean generate(Processor processor); + boolean generateInStartOffsetOrder(@NotNull Processor processor); } public static boolean sweep(@NotNull Generator generator, @NotNull final SweepProcessor sweepProcessor) { @@ -323,7 +323,7 @@ public class RangeMarkerTree extends IntervalTreeImpl starts = new ArrayList(); - if (!generator.generate(new Processor() { + if (!generator.generateInStartOffsetOrder(new Processor() { @Override public boolean process(T marker) { // decide whether previous marker ends here or new marker begins diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/RangeHighlighterEx.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/RangeHighlighterEx.java index 69be3833d44f..06fcfcadcb23 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/RangeHighlighterEx.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/RangeHighlighterEx.java @@ -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 BY_AFFECTED_START_OFFSET = new Comparator() { + @Override + public int compare(RangeHighlighterEx r1, RangeHighlighterEx r2) { + return r1.getAffectedAreaStartOffset() - r2.getAffectedAreaStartOffset(); + } + }; } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index 02b07369a8a7..d2c5c96141f0 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -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 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 list = new ArrayList(size); - myHighlighterTree.process(new CommonProcessors.CollectProcessor(list)); + CommonProcessors.CollectProcessor collectProcessor = new CommonProcessors.CollectProcessor(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() { - @Override - public boolean process(RangeHighlighterEx h) { - return h.getId() != ((RangeHighlighterEx)highlighter).getId(); - } - }); + Processor equalId = new Processor() { + @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 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 processor) { - return myHighlighterTree.processOverlappingWithOutside(start, end, processor); + return myHighlighterTree.processOverlappingWithOutside(start, end, processor) + && myHighlighterTreeForLines.processOverlappingWithOutside(start, end, processor); } @Override @NotNull public DisposableIterator overlappingIterator(int startOffset, int endOffset) { - return myHighlighterTree.overlappingIterator(roundToLineBoundaries(startOffset, endOffset)); + IntervalTreeImpl.PeekableIterator exact = myHighlighterTree.overlappingIterator(new TextRangeInterval(startOffset, endOffset)); + IntervalTreeImpl.PeekableIterator lines = myHighlighterTreeForLines.overlappingIterator(roundToLineBoundaries(startOffset, endOffset)); + return merge(exact, lines); + } + + @NotNull + private static DisposableIterator merge(@NotNull final IntervalTreeImpl.PeekableIterator iterator1, @NotNull final IntervalTreeImpl.PeekableIterator iterator2) { + return new DisposableIterator() { + @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 sweepProcessor) { - TextRangeInterval rangeInterval = roundToLineBoundaries(start, end); - return myHighlighterTree.sweep(rangeInterval.getStartOffset(), rangeInterval.getEndOffset(), sweepProcessor); + TextRangeInterval lines = roundToLineBoundaries(start, end); + List linesInRange = new ArrayList(); + myHighlighterTreeForLines.processOverlappingWith(lines.getStartOffset(), lines.getEndOffset(), new CommonProcessors.CollectProcessor(linesInRange)); + if (linesInRange.isEmpty()) { + return myHighlighterTree.sweep(start, end, sweepProcessor); + } + final List highlighters = new ArrayList(); + myHighlighterTree.processOverlappingWith(start, end, new CommonProcessors.CollectProcessor(highlighters)); + highlighters.addAll(linesInRange); + Collections.sort(highlighters, RangeHighlighterEx.BY_AFFECTED_START_OFFSET); + + return RangeMarkerTree.sweep(new RangeMarkerTree.Generator() { + @Override + public boolean generateInStartOffsetOrder(@NotNull Processor processor) { + return ContainerUtil.process(highlighters, processor); + } + }, sweepProcessor); } } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java index ff7c244aeab0..c59f28edd805 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java @@ -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) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java index cb96a1fea07f..7e855923811c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java @@ -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 BY_AFFECTED_START_OFFSET = new Comparator() { - @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 list = new ArrayList(); - markupModel.processRangeHighlightersOverlappingWith(start, end, new Processor() { - @Override - public boolean process(RangeHighlighterEx highlighter) { - list.add(highlighter); - return true; - } - }); + markupModel.processRangeHighlightersOverlappingWith(start, end, new CommonProcessors.CollectProcessor(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) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java index d6f4df7a5cfe..925d92d93283 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java @@ -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() { + @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 list = new ArrayList(); + CommonProcessors.CollectProcessor coll = new CommonProcessors.CollectProcessor(list); + for (int i=0; i