diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java index 58583c3d12ff..c4a19d9e3403 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java @@ -61,11 +61,34 @@ public class ComparisonManagerImpl extends ComparisonManager { LineOffsets lineOffsets1 = LineOffsetsUtil.create(text1); LineOffsets lineOffsets2 = LineOffsetsUtil.create(text2); - List lineTexts1 = getLineContents(text1, lineOffsets1); - List lineTexts2 = getLineContents(text2, lineOffsets2); + return compareLines(text1, text2, lineOffsets1, lineOffsets2, policy, indicator); + } + + @NotNull + public List compareLines(@NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) throws DiffTooBigException { + Range range = new Range(0, lineOffsets1.getLineCount(), + 0, lineOffsets2.getLineCount()); + return compareLines(range, text1, text2, lineOffsets1, lineOffsets2, policy, indicator); + } + + @NotNull + public List compareLines(@NotNull Range range, + @NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, + @NotNull ComparisonPolicy policy, + @NotNull ProgressIndicator indicator) throws DiffTooBigException { + List lineTexts1 = getLineContents(range.start1, range.end1, text1, lineOffsets1); + List lineTexts2 = getLineContents(range.start2, range.end2, text2, lineOffsets2); FairDiffIterable iterable = ByLine.compare(lineTexts1, lineTexts2, policy, indicator); - return convertIntoLineFragments(lineOffsets1, lineOffsets2, iterable); + return convertIntoLineFragments(range, lineOffsets1, lineOffsets2, iterable); } @NotNull @@ -97,6 +120,41 @@ public class ComparisonManagerImpl extends ComparisonManager { return createInnerFragments(lineFragments, text1, text2, policy, indicator); } + @NotNull + public List compareLinesInner(@NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, + @NotNull ComparisonPolicy policy, + boolean innerFragments, + @NotNull ProgressIndicator indicator) throws DiffTooBigException { + List lineFragments = compareLines(text1, text2, lineOffsets1, lineOffsets2, policy, indicator); + if (innerFragments) { + return createInnerFragments(lineFragments, text1, text2, policy, indicator); + } + else { + return lineFragments; + } + } + + @NotNull + public List compareLinesInner(@NotNull Range range, + @NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, + @NotNull ComparisonPolicy policy, + boolean innerFragments, + @NotNull ProgressIndicator indicator) throws DiffTooBigException { + List lineFragments = compareLines(range, text1, text2, lineOffsets1, lineOffsets2, policy, indicator); + if (innerFragments) { + return createInnerFragments(lineFragments, text1, text2, policy, indicator); + } + else { + return lineFragments; + } + } + private static List createInnerFragments(@NotNull List lineFragments, @NotNull CharSequence text1, @NotNull CharSequence text2, @@ -228,15 +286,21 @@ public class ComparisonManagerImpl extends ComparisonManager { } @NotNull - public static List convertIntoLineFragments(@NotNull LineOffsets lineOffsets1, + public static List convertIntoLineFragments(@NotNull Range range, + @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, @NotNull FairDiffIterable changes) { List fragments = new ArrayList<>(); for (Range ch : changes.iterateChanges()) { - IntPair offsets1 = getOffsets(lineOffsets1, ch.start1, ch.end1); - IntPair offsets2 = getOffsets(lineOffsets2, ch.start2, ch.end2); + int startLine1 = ch.start1 + range.start1; + int startLine2 = ch.start2 + range.start2; + int endLine1 = ch.end1 + range.start1; + int endLine2 = ch.end2 + range.start2; - fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, + IntPair offsets1 = getOffsets(lineOffsets1, startLine1, endLine1); + IntPair offsets2 = getOffsets(lineOffsets2, startLine2, endLine2); + + fragments.add(new LineFragmentImpl(startLine1, endLine1, startLine2, endLine2, offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2)); } return fragments; @@ -419,21 +483,26 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull private static List getLineContents(@NotNull CharSequence text, @NotNull LineOffsets lineOffsets) { - List lines = new ArrayList<>(lineOffsets.getLineCount()); - for (int line = 0; line < lineOffsets.getLineCount(); line++) { + return getLineContents(0, lineOffsets.getLineCount(), text, lineOffsets); + } + + @NotNull + private static List getLineContents(int start, int end, @NotNull CharSequence text, @NotNull LineOffsets lineOffsets) { + List lines = new ArrayList<>(end - start); + for (int line = start; line < end; line++) { lines.add(new CharSequenceSubSequence(text, lineOffsets.getLineStart(line), lineOffsets.getLineEnd(line))); } return lines; } @NotNull - private static List getNotIgnoredLineContents(@NotNull CharSequence text, + private static List getNotIgnoredLineContents(int start, int end, + @NotNull CharSequence text, @NotNull LineOffsets lineOffsets, @NotNull BitSet ignored) { StringBuilder sb = new StringBuilder(); - - List lines = new ArrayList<>(lineOffsets.getLineCount()); - for (int line = 0; line < lineOffsets.getLineCount(); line++) { + List lines = new ArrayList<>(end - start); + for (int line = start; line < end; line++) { for (int offset = lineOffsets.getLineStart(line); offset < lineOffsets.getLineEnd(line); offset++) { if (ignored.get(offset)) continue; sb.append(text.charAt(offset)); @@ -445,31 +514,43 @@ public class ComparisonManagerImpl extends ComparisonManager { } + @NotNull + public List compareLinesWithIgnoredRanges(@NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, + @NotNull BitSet ignored1, + @NotNull BitSet ignored2, + boolean innerFragments, + @NotNull ProgressIndicator indicator) throws DiffTooBigException { + Range range = new Range(0, lineOffsets1.getLineCount(), + 0, lineOffsets2.getLineCount()); + return compareLinesWithIgnoredRanges(range, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, + innerFragments, indicator); + } + /** * Compare two texts by-line and then compare changed fragments by-word */ @NotNull - public List compareLinesWithIgnoredRanges(@NotNull CharSequence text1, + public List compareLinesWithIgnoredRanges(@NotNull Range range, + @NotNull CharSequence text1, @NotNull CharSequence text2, - @NotNull List ignoredRanges1, - @NotNull List ignoredRanges2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, + @NotNull BitSet ignored1, + @NotNull BitSet ignored2, boolean innerFragments, @NotNull ProgressIndicator indicator) throws DiffTooBigException { - BitSet ignored1 = collectIgnoredRanges(ignoredRanges1); - BitSet ignored2 = collectIgnoredRanges(ignoredRanges2); - - LineOffsets lineOffsets1 = LineOffsetsUtil.create(text1); - LineOffsets lineOffsets2 = LineOffsetsUtil.create(text2); - - List lineTexts1 = getNotIgnoredLineContents(text1, lineOffsets1, ignored1); - List lineTexts2 = getNotIgnoredLineContents(text2, lineOffsets2, ignored2); + List lineTexts1 = getNotIgnoredLineContents(range.start1, range.end1, text1, lineOffsets1, ignored1); + List lineTexts2 = getNotIgnoredLineContents(range.start2, range.end2, text2, lineOffsets2, ignored2); FairDiffIterable iterable = ByLine.compare(lineTexts1, lineTexts2, ComparisonPolicy.DEFAULT, indicator); FairDiffIterable correctedIterable = correctIgnoredRangesSecondStep(iterable, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2); - List lineFragments = convertIntoLineFragments(lineOffsets1, lineOffsets2, correctedIterable); + List lineFragments = convertIntoLineFragments(range, lineOffsets1, lineOffsets2, correctedIterable); if (innerFragments) { lineFragments = createInnerFragments(lineFragments, text1, text2, ComparisonPolicy.DEFAULT, indicator); @@ -497,7 +578,7 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull LineOffsets lineOffsets2, @NotNull BitSet ignored1, @NotNull BitSet ignored2) { - DiffIterableUtil.ChangeBuilder builder = new DiffIterableUtil.ChangeBuilder(lineOffsets1.getLineCount(), lineOffsets2.getLineCount()); + DiffIterableUtil.ChangeBuilder builder = new DiffIterableUtil.ChangeBuilder(iterable.getLength1(), iterable.getLength2()); for (Range range : iterable.iterateUnchanged()) { int count = range.end1 - range.start1; for (int i = 0; i < count; i++) { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/text/SimpleTextDiffProvider.java b/platform/diff-impl/src/com/intellij/diff/tools/util/text/SimpleTextDiffProvider.java index 8f77671911cb..630a90b2cb86 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/text/SimpleTextDiffProvider.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/text/SimpleTextDiffProvider.java @@ -15,23 +15,20 @@ */ package com.intellij.diff.tools.util.text; -import com.intellij.diff.comparison.ComparisonManager; +import com.intellij.diff.comparison.ComparisonManagerImpl; import com.intellij.diff.comparison.ComparisonPolicy; -import com.intellij.diff.comparison.ComparisonUtil; import com.intellij.diff.fragments.LineFragment; -import com.intellij.diff.fragments.LineFragmentImpl; import com.intellij.diff.tools.util.base.HighlightPolicy; import com.intellij.diff.tools.util.base.IgnorePolicy; import com.intellij.diff.tools.util.base.TextDiffSettingsHolder.TextDiffSettings; import com.intellij.diff.util.DiffUserDataKeysEx.DiffComputer; -import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.Range; import com.intellij.openapi.Disposable; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.util.TextRange; import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -39,40 +36,32 @@ import java.util.List; import static com.intellij.diff.tools.util.base.HighlightPolicy.*; import static com.intellij.diff.tools.util.base.IgnorePolicy.*; -import static java.util.Collections.singletonList; public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implements TwosideTextDiffProvider { - static final DiffComputer DEFAULT_COMPUTER = (text1, text2, policy, innerChanges, indicator) -> { - if (innerChanges) { - return ComparisonManager.getInstance().compareLinesInner(text1, text2, policy, indicator); - } - else { - return ComparisonManager.getInstance().compareLines(text1, text2, policy, indicator); - } - }; + private static final Logger LOG = Logger.getInstance(SimpleTextDiffProvider.class); private static final IgnorePolicy[] IGNORE_POLICIES = {DEFAULT, TRIM_WHITESPACES, IGNORE_WHITESPACES, IGNORE_WHITESPACES_CHUNKS}; private static final HighlightPolicy[] HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD, BY_WORD_SPLIT, DO_NOT_HIGHLIGHT}; - @NotNull private final DiffComputer myDiffComputer; + @Nullable private final DiffComputer myDiffComputer; public SimpleTextDiffProvider(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @NotNull Disposable disposable) { - this(settings, rediff, disposable, DEFAULT_COMPUTER); + this(settings, rediff, disposable, null); } public SimpleTextDiffProvider(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @NotNull Disposable disposable, - @NotNull DiffComputer diffComputer) { + @Nullable DiffComputer diffComputer) { this(settings, rediff, disposable, diffComputer, IGNORE_POLICIES, HIGHLIGHT_POLICIES); } private SimpleTextDiffProvider(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @NotNull Disposable disposable, - @NotNull DiffComputer diffComputer, + @Nullable DiffComputer diffComputer, @NotNull IgnorePolicy[] ignorePolicies, @NotNull HighlightPolicy[] highlightPolicies) { super(settings, rediff, disposable, ignorePolicies, highlightPolicies); @@ -85,7 +74,7 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen @NotNull CharSequence text2, @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, - @NotNull List linesRanges, + @Nullable List linesRanges, @NotNull IgnorePolicy ignorePolicy, boolean innerFragments, @NotNull ProgressIndicator indicator) { @@ -93,73 +82,46 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen } @NotNull - public static List> compareRange(@NotNull DiffComputer diffComputer, + public static List> compareRange(@Nullable DiffComputer diffComputer, @NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, - @NotNull List linesRanges, + @Nullable List linesRanges, @NotNull IgnorePolicy ignorePolicy, boolean innerFragments, @NotNull ProgressIndicator indicator) { ComparisonPolicy policy = ignorePolicy.getComparisonPolicy(); - List> result = new ArrayList<>(); - for (Range range : linesRanges) { - CharSequence content1 = DiffUtil.getLinesContent(text1, lineOffsets1, range.start1, range.end1, true); - CharSequence content2 = DiffUtil.getLinesContent(text2, lineOffsets2, range.start2, range.end2, true); - - if (range.start1 == range.end1 || range.start2 == range.end2) { - boolean isEquals = ComparisonUtil.isEquals(content1, content2, policy); - result.add(singletonList(createSimpleFragment(range, lineOffsets1, lineOffsets2, isEquals))); - } - else { - List fragments = diffComputer.compute(content1, content2, policy, innerFragments, indicator); - - int startOffset1 = lineOffsets1.getLineStart(range.start1); - int startOffset2 = lineOffsets2.getLineStart(range.start2); - result.add(ContainerUtil.map(fragments, fragment -> { - return transferFragment(fragment, range.start1, range.start2, startOffset1, startOffset2); - })); - } + if (diffComputer != null && linesRanges != null) { + LOG.error(new Throwable("Unsupported operation: ranged diff with custom DiffComputer - " + diffComputer)); } - return result; - } - - @NotNull - public static LineFragment createSimpleFragment(@NotNull Range linesRange, - @NotNull LineOffsets lineOffsets1, - @NotNull LineOffsets lineOffsets2, - boolean isEquals) { - TextRange textRange1 = DiffUtil.getLinesRange(lineOffsets1, linesRange.start1, linesRange.end1, true); - TextRange textRange2 = DiffUtil.getLinesRange(lineOffsets2, linesRange.start2, linesRange.end2, true); - - return new LineFragmentImpl(linesRange.start1, linesRange.end1, - linesRange.start2, linesRange.end2, - textRange1.getStartOffset(), textRange1.getEndOffset(), - textRange2.getStartOffset(), textRange2.getEndOffset(), - isEquals ? Collections.emptyList() : null); - } - - @NotNull - public static LineFragment transferFragment(@NotNull LineFragment fragment, - int startLine1, int startLine2, - int startOffset1, int startOffset2) { - if (startLine1 == 0 && startLine2 == 0 && startOffset1 == 0 && startOffset2 == 0) return fragment; - return new LineFragmentImpl(fragment.getStartLine1() + startLine1, fragment.getEndLine1() + startLine1, - fragment.getStartLine2() + startLine2, fragment.getEndLine2() + startLine2, - fragment.getStartOffset1() + startOffset1, fragment.getEndOffset1() + startOffset1, - fragment.getStartOffset2() + startOffset2, fragment.getEndOffset2() + startOffset2, - fragment.getInnerFragments()); + ComparisonManagerImpl comparisonManager = ComparisonManagerImpl.getInstanceImpl(); + if (diffComputer != null || linesRanges == null) { + List fragments = comparisonManager.compareLinesInner(text1, text2, lineOffsets1, lineOffsets2, + policy, innerFragments, indicator); + return Collections.singletonList(fragments); + } + else { + List> result = new ArrayList<>(); + for (Range range : linesRanges) { + result.add(comparisonManager.compareLinesInner(range, text1, text2, lineOffsets1, lineOffsets2, + policy, innerFragments, indicator)); + } + return result; + } } public static class NoIgnore extends SimpleTextDiffProvider implements TwosideTextDiffProvider.NoIgnore { public NoIgnore(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @NotNull Disposable disposable) { - this(settings, rediff, disposable, DEFAULT_COMPUTER); + this(settings, rediff, disposable, null); } - public NoIgnore(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @NotNull Disposable disposable, @NotNull DiffComputer diffComputer) { + public NoIgnore(@NotNull TextDiffSettings settings, + @NotNull Runnable rediff, + @NotNull Disposable disposable, + @Nullable DiffComputer diffComputer) { super(settings, rediff, disposable, diffComputer, IGNORE_POLICIES, ArrayUtil.remove(HIGHLIGHT_POLICIES, DO_NOT_HIGHLIGHT)); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/text/SmartTextDiffProvider.java b/platform/diff-impl/src/com/intellij/diff/tools/util/text/SmartTextDiffProvider.java index f2373af523cd..6daaf8ecd294 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/text/SmartTextDiffProvider.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/text/SmartTextDiffProvider.java @@ -23,7 +23,6 @@ import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.tools.util.base.HighlightPolicy; import com.intellij.diff.tools.util.base.IgnorePolicy; import com.intellij.diff.tools.util.base.TextDiffSettingsHolder.TextDiffSettings; -import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.Range; import com.intellij.diff.util.Side; import com.intellij.openapi.Disposable; @@ -32,11 +31,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collections; import java.util.List; import static com.intellij.diff.tools.util.base.HighlightPolicy.*; @@ -116,7 +116,7 @@ public class SmartTextDiffProvider extends TwosideTextDiffProviderBase implement @NotNull CharSequence text2, @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, - @NotNull List linesRanges, + @Nullable List linesRanges, @NotNull IgnorePolicy ignorePolicy, boolean innerFragments, @NotNull ProgressIndicator indicator) { @@ -124,8 +124,7 @@ public class SmartTextDiffProvider extends TwosideTextDiffProviderBase implement return compareIgnoreFormatting(text1, text2, lineOffsets1, lineOffsets2, linesRanges, innerFragments, indicator); } else { - return SimpleTextDiffProvider.compareRange(SimpleTextDiffProvider.DEFAULT_COMPUTER, - text1, text2, lineOffsets1, lineOffsets2, linesRanges, + return SimpleTextDiffProvider.compareRange(null, text1, text2, lineOffsets1, lineOffsets2, linesRanges, ignorePolicy, innerFragments, indicator); } } @@ -135,47 +134,29 @@ public class SmartTextDiffProvider extends TwosideTextDiffProviderBase implement @NotNull CharSequence text2, @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, - @NotNull List linesRanges, + @Nullable List linesRanges, boolean innerFragments, @NotNull ProgressIndicator indicator) { - List ranges1 = myProvider.getIgnoredRanges(myProject, text1, myContent1); - List ranges2 = myProvider.getIgnoredRanges(myProject, text2, myContent2); + List ignoredRanges1 = myProvider.getIgnoredRanges(myProject, text1, myContent1); + List ignoredRanges2 = myProvider.getIgnoredRanges(myProject, text2, myContent2); - List> result = new ArrayList<>(); - for (Range range : linesRanges) { - TextRange offsets1 = DiffUtil.getLinesRange(lineOffsets1, range.start1, range.end1, true); - TextRange offsets2 = DiffUtil.getLinesRange(lineOffsets2, range.start2, range.end2, true); + BitSet ignored1 = ComparisonManagerImpl.collectIgnoredRanges(ignoredRanges1); + BitSet ignored2 = ComparisonManagerImpl.collectIgnoredRanges(ignoredRanges2); - CharSequence subText1 = offsets1.subSequence(text1); - CharSequence subText2 = offsets2.subSequence(text2); - - List subRanges1 = getSubRanges(ranges1, offsets1); - List subRanges2 = getSubRanges(ranges2, offsets2); - - ComparisonManagerImpl comparisonManager = ComparisonManagerImpl.getInstanceImpl(); - List fragments = comparisonManager.compareLinesWithIgnoredRanges(subText1, subText2, subRanges1, subRanges2, - innerFragments, indicator); - - int startOffset1 = offsets1.getStartOffset(); - int startOffset2 = offsets2.getStartOffset(); - result.add(ContainerUtil.map(fragments, fragment -> { - return SimpleTextDiffProvider.transferFragment(fragment, range.start1, range.start2, startOffset1, startOffset2); - })); + ComparisonManagerImpl comparisonManager = ComparisonManagerImpl.getInstanceImpl(); + if (linesRanges == null) { + List fragments = comparisonManager.compareLinesWithIgnoredRanges(text1, text2, lineOffsets1, lineOffsets2, + ignored1, ignored2, innerFragments, indicator); + return Collections.singletonList(fragments); } - return result; - } - - @NotNull - private static List getSubRanges(@NotNull List ignoredRanges, @NotNull TextRange offsets) { - List result = new ArrayList<>(); - for (TextRange range : ignoredRanges) { - TextRange intersection = range.intersection(offsets); - if (intersection != null) { - result.add(new TextRange(intersection.getStartOffset() - offsets.getStartOffset(), - intersection.getEndOffset() - offsets.getStartOffset())); + else { + List> result = new ArrayList<>(); + for (Range range : linesRanges) { + result.add(comparisonManager.compareLinesWithIgnoredRanges(range, text1, text2, lineOffsets1, lineOffsets2, + ignored1, ignored2, innerFragments, indicator)); } + return result; } - return result; } @Nullable diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/text/TwosideTextDiffProviderBase.java b/platform/diff-impl/src/com/intellij/diff/tools/util/text/TwosideTextDiffProviderBase.java index b1ac131b5abc..6730e7dea9b4 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/text/TwosideTextDiffProviderBase.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/text/TwosideTextDiffProviderBase.java @@ -30,8 +30,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static java.util.Collections.singletonList; - abstract class TwosideTextDiffProviderBase extends TextDiffProviderBase implements TwosideTextDiffProvider { protected TwosideTextDiffProviderBase(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @@ -49,8 +47,7 @@ abstract class TwosideTextDiffProviderBase extends TextDiffProviderBase implemen LineOffsets lineOffsets1 = LineOffsetsUtil.create(text1); LineOffsets lineOffsets2 = LineOffsetsUtil.create(text2); - Range linesRange = new Range(0, lineOffsets1.getLineCount(), 0, lineOffsets2.getLineCount()); - List> fragments = doCompare(text1, text2, lineOffsets1, lineOffsets2, singletonList(linesRange), indicator); + List> fragments = doCompare(text1, text2, lineOffsets1, lineOffsets2, null, indicator); if (fragments == null) return null; @@ -74,7 +71,7 @@ abstract class TwosideTextDiffProviderBase extends TextDiffProviderBase implemen @NotNull CharSequence text2, @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, - @NotNull List linesRanges, + @Nullable List linesRanges, @NotNull ProgressIndicator indicator) { IgnorePolicy ignorePolicy = getIgnorePolicy(); HighlightPolicy highlightPolicy = getHighlightPolicy(); @@ -89,7 +86,7 @@ abstract class TwosideTextDiffProviderBase extends TextDiffProviderBase implemen indicator.checkCanceled(); List> fragments = doCompare(text1, text2, lineOffsets1, lineOffsets2, linesRanges, ignorePolicy, innerFragments, indicator); - assert fragments.size() == linesRanges.size(); + assert fragments.size() == (linesRanges != null ? linesRanges.size() : 1); indicator.checkCanceled(); return ContainerUtil.map(fragments, rangeFragments -> { @@ -103,7 +100,7 @@ abstract class TwosideTextDiffProviderBase extends TextDiffProviderBase implemen @NotNull CharSequence text2, @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, - @NotNull List linesRanges, + @Nullable List linesRanges, @NotNull IgnorePolicy ignorePolicy, boolean innerFragments, @NotNull ProgressIndicator indicator); diff --git a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt index 52d496fd4fed..2afa56373829 100644 --- a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt @@ -133,7 +133,7 @@ abstract class DiffTestCase : TestCase() { fun textToReadableFormat(text: CharSequence?): String { if (text == null) return "null" - return "'" + text.toString().replace('\n', '*').replace('\t', '+') + "'" + return "\"" + text.toString().replace('\n', '*').replace('\t', '+') + "\"" } fun parseSource(string: CharSequence): String = string.toString().replace('_', '\n') diff --git a/platform/diff-impl/tests/com/intellij/diff/HeavyDiffTestCase.kt b/platform/diff-impl/tests/com/intellij/diff/HeavyDiffTestCase.kt index d03a7fc3d75d..f15057c06705 100644 --- a/platform/diff-impl/tests/com/intellij/diff/HeavyDiffTestCase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/HeavyDiffTestCase.kt @@ -15,7 +15,14 @@ */ package com.intellij.diff +import com.intellij.diff.fragments.LineFragment +import com.intellij.diff.tools.util.base.HighlightPolicy +import com.intellij.diff.tools.util.base.IgnorePolicy +import com.intellij.diff.tools.util.base.TextDiffSettingsHolder +import com.intellij.diff.tools.util.text.SimpleTextDiffProvider +import com.intellij.diff.util.Range import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer import com.intellij.testFramework.fixtures.IdeaProjectTestFixture import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory import com.intellij.testFramework.runInEdtAndWait @@ -47,4 +54,21 @@ abstract class HeavyDiffTestCase : DiffTestCase() { super.runBare() } } + + + protected fun compareExplicitBlocks(text1: CharSequence, text2: CharSequence, ranges: List, + highlightPolicy: HighlightPolicy, ignorePolicy: IgnorePolicy): List { + val settings = TextDiffSettingsHolder.TextDiffSettings() + settings.highlightPolicy = highlightPolicy + settings.ignorePolicy = ignorePolicy + + val disposable = Disposer.newDisposable() + try { + val diffProvider = SimpleTextDiffProvider(settings, Runnable {}, disposable) + return diffProvider.compare(text1, text2, ranges, INDICATOR)!!.flatMap { it } + } + finally { + Disposer.dispose(disposable) + } + } } \ No newline at end of file diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/BlocksComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/BlocksComparisonUtilTest.kt new file mode 100644 index 000000000000..98e26372fa6a --- /dev/null +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/BlocksComparisonUtilTest.kt @@ -0,0 +1,364 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.diff.comparison + +import com.intellij.diff.HeavyDiffTestCase +import com.intellij.diff.fragments.DiffFragmentImpl +import com.intellij.diff.fragments.LineFragment +import com.intellij.diff.tools.util.base.HighlightPolicy +import com.intellij.diff.tools.util.base.IgnorePolicy +import com.intellij.diff.util.Range +import com.intellij.diff.util.Side +import java.util.* + +class BlocksComparisonUtilTest : HeavyDiffTestCase() { + fun `test simple blocks`() { + Test("X_a_Y_c_Z", "X_ a__Y__ c_Z") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .default() + + Test("X_a_Y_c_Z", "X_ a__Y__ c_Z") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + Range(2, 2, 2, 3), Range(3, 3, 4, 5)) + .trim() + .ignore() + + Test("X_a_Y_c_Z", "X_ a__Y__ c_Z") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + ) + .ignore_chunks() + } + + fun `test changes outside of blocks are ignored`() { + Test("X_a_Y_c_Z", "N_ a__N__ c_N") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .default() + + Test("X_X_X_a_Y_c_Z", "N_ a__N__ c_N") + .blocks( + Range(5, 6, 4, 6)) + .expected( + Range(5, 6, 4, 6)) + .default() + } + + fun `test multiple fragments in a block`() { + Test("X_a_b_c_Y", "X_a1_ b_c2_Y") + .blocks( + Range(1, 4, 1, 4)) + .expected( + Range(1, 4, 1, 4)) + .default() + + Test("X_a_b_c_Y", "X_a1_ b_c2_Y") + .blocks( + Range(1, 4, 1, 4)) + .expected( + Range(1, 2, 1, 2), Range(3, 4, 3, 4)) + .trim() + .ignore() + .ignore_chunks() + } + + fun `test fragments respect ignore options`() { + Test("X_a_b_c_Y", "X_a1_ b_c2_Y") + .blocks( + Range(1, 4, 1, 4)) + .expected( + Range(1, 4, 1, 4)) + .default() + + Test("X_Y", "X_a_c_Y") + .blocks( + Range(1, 1, 1, 3)) + .expected( + Range(1, 1, 1, 3)) + .default() + .trim() + .ignore() + .ignore_chunks() + + Test("X_Y", "X___Y") + .blocks( + Range(1, 1, 1, 3)) + .expected( + Range(1, 1, 1, 3)) + .default() + .trim() + .ignore() + + Test("X_Y", "X___Y") + .blocks( + Range(1, 1, 1, 3)) + .expected( + ) + .ignore_chunks() + } + + fun `test leading-trailing empty lines`() { + Test("X_a__Y", "X__y_Y") + .blocks( + Range(1, 3, 1, 3)) + .expected( + Range(1, 2, 1, 1), Range(3, 3, 2, 3)) + .default() + .trim() + .ignore() + + Test("X_a__", "X__y_") + .blocks( + Range(1, 3, 1, 3)) + .expected( + Range(1, 2, 1, 1), Range(3, 3, 2, 3)) + .default() + .trim() + .ignore() + + Test("a__", "_y_") + .blocks( + Range(0, 2, 0, 2)) + .expected( + Range(0, 1, 0, 0), Range(2, 2, 1, 2)) + .default() + .trim() + .ignore() + + Test("a__", "_y_") + .blocks( + Range(0, 3, 0, 3)) + .expected( + Range(0, 1, 0, 0), Range(2, 2, 1, 2)) + .default() + .trim() + .ignore() + + Test("a_", "_y") + .blocks( + Range(0, 2, 0, 2)) + .expected( + Range(0, 1, 0, 0), Range(2, 2, 1, 2)) + .default() + .trim() + .ignore() + } + + fun `test inner changes`() { + Test("X_a_Y", "X_b_Y", + " - ", " - ") + .blocks( + Range(1, 2, 1, 2) + ) + .default() + .trim() + .ignore() + .ignore_chunks() + + Test("X_a_Y", "X_ a_b_Y", + " ", " -- -- ") + .blocks( + Range(1, 2, 1, 3) + ) + .default() + + Test("X_a_Y", "X_ a_b_Y", + " ", " -- ") + .blocks( + Range(1, 2, 1, 3) + ) + .expected( + Range(2, 2, 2, 3) + ) + .trim() + .ignore() + + Test("X_a b_Y", "X_a b_Y", + " ", " - ") + .blocks( + Range(1, 2, 1, 2) + ) + .default() + .trim() + + Test("X_a b_Y", "X_a b_Y", + " ", " ") + .blocks( + Range(1, 2, 1, 2) + ) + .ignore() + .ignore_chunks() + + Test("X_a_Y_c_Z", "X_ a__Y__ c_Z", + " ", " - - -- ") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .default() + + Test("X_a_Y_c_Z", "X_ a__Y__ c_Z", + " ", " - - ") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + Range(2, 2, 2, 3), Range(3, 3, 4, 5)) + .trim() + + Test("X_a_Y_c_Z", "X_ a__Y__ c_Z", + " ", " ") + .blocks( + Range(1, 2, 1, 3), Range(3, 4, 4, 6)) + .expected( + Range(2, 2, 2, 3), Range(3, 3, 4, 5)) + .ignore() + } + + fun `test inner changes for inserted empty line`() { + Test("X_Y", "X_ _Y", + " ", " -- ") + .blocks( + Range(1, 1, 1, 2) + ) + .trim() + .default() + + Test("X_Y", "X_ _Y", + " ", " ") + .blocks( + Range(1, 1, 1, 2) + ) + .expected( + Range(1, 1, 1, 2) + ) + .ignore() + + Test("X_Y", "X_ _Y", + " ", " ") + .blocks( + Range(1, 1, 1, 2) + ) + .expected( + ) + .ignore_chunks() + } + + fun `test inner changes with leading-trailing empty lines`() { + Test("X_a__Y", "X__y_Y", + " -- ", " -- ") + .blocks( + Range(1, 3, 1, 3)) + .expected( + Range(1, 2, 1, 1), Range(3, 3, 2, 3)) + .default() + .trim() + .ignore() + + Test("a__", "_y_", + "-- ", " --") + .blocks( + Range(0, 2, 0, 2)) + .expected( + Range(0, 1, 0, 0), Range(2, 2, 1, 2)) + .default() + .trim() + .ignore() + } + + private inner class Test(val input1: String, val input2: String, + val inner1: String? = null, val inner2: String? = null) { + var blocks: List? = null + var expected: List? = null + + fun expected(vararg ranges: Range): Test { + expected = ranges.toList() + return this + } + + + fun blocks(vararg ranges: Range): Test { + blocks = ranges.toList() + return this + } + + fun default(): Test { + doTest(IgnorePolicy.DEFAULT) + return this + } + + fun trim(): Test { + doTest(IgnorePolicy.TRIM_WHITESPACES) + return this + } + + fun ignore(): Test { + doTest(IgnorePolicy.IGNORE_WHITESPACES) + return this + } + + fun ignore_chunks(): Test { + doTest(IgnorePolicy.IGNORE_WHITESPACES_CHUNKS) + return this + } + + + private fun doTest(ignorePolicy: IgnorePolicy) { + if (expected == null && (inner1 == null || inner2 == null)) throw IllegalArgumentException() + + if (expected != null) { + val fragments1 = compareExplicitBlocks(parseSource(input1), parseSource(input2), blocks!!, HighlightPolicy.BY_LINE, ignorePolicy) + val fragments2 = compareExplicitBlocks(parseSource(input1), parseSource(input2), blocks!!, HighlightPolicy.BY_WORD, ignorePolicy) + + assertEquals(expected!!, fragments1.toRanges()) + assertEquals(expected!!, fragments2.toRanges()) + } + + if (inner1 != null && inner2 != null) { + val fragments = compareExplicitBlocks(parseSource(input1), parseSource(input2), blocks!!, HighlightPolicy.BY_WORD, ignorePolicy) + + val expected1 = parseInnerExpected(inner1) + val expected2 = parseInnerExpected(inner2) + + val actual1 = parseInnerActual(fragments, Side.LEFT) + val actual2 = parseInnerActual(fragments, Side.RIGHT) + + assertEquals(expected1, actual1) + assertEquals(expected2, actual2) + } + } + + private fun parseInnerExpected(inner: String): BitSet { + val set = BitSet() + inner.forEachIndexed { index, c -> + if (c == '-') set.set(index) + } + return set + } + + private fun parseInnerActual(fragments: List, side: Side): BitSet { + val set = BitSet() + fragments.flatMap { fragment -> + fragment.innerFragments?.map { + DiffFragmentImpl(fragment.startOffset1 + it.startOffset1, fragment.startOffset1 + it.endOffset1, + fragment.startOffset2 + it.startOffset2, fragment.startOffset2 + it.endOffset2) + } ?: listOf(fragment) + }.forEach { + val start = side.getStartOffset(it) + val end = side.getEndOffset(it) + set.set(start, end) + } + return set + } + + private fun List.toRanges(): List { + return this.map { Range(it.startLine1, it.endLine1, it.startLine2, it.endLine2) } + } + } +} \ No newline at end of file diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt index b117f7261577..df5c4224e8aa 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt @@ -16,18 +16,23 @@ package com.intellij.diff.comparison import com.intellij.diff.DiffTestCase +import com.intellij.diff.HeavyDiffTestCase import com.intellij.diff.fragments.DiffFragment import com.intellij.diff.fragments.LineFragment import com.intellij.diff.fragments.MergeLineFragment import com.intellij.diff.fragments.MergeWordFragment +import com.intellij.diff.tools.util.base.HighlightPolicy +import com.intellij.diff.tools.util.base.IgnorePolicy import com.intellij.diff.util.DiffUtil +import com.intellij.diff.util.Range import com.intellij.diff.util.ThreeSide import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.impl.DocumentImpl import com.intellij.openapi.util.Couple import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vcs.ex.createRanges -class ComparisonUtilAutoTest : DiffTestCase() { +class ComparisonUtilAutoTest : HeavyDiffTestCase() { val RUNS = 30 val MAX_LENGTH = 300 @@ -51,6 +56,10 @@ class ComparisonUtilAutoTest : DiffTestCase() { doTestLineTrimSquashed(System.currentTimeMillis(), RUNS, MAX_LENGTH) } + fun testExplicitBlocks() { + doTestExplicitBlocks(System.currentTimeMillis(), RUNS, MAX_LENGTH) + } + fun testMerge() { doTestMerge(System.currentTimeMillis(), RUNS, MAX_LENGTH) } @@ -131,6 +140,31 @@ class ComparisonUtilAutoTest : DiffTestCase() { } } + private fun doTestExplicitBlocks(seed: Long, runs: Int, maxLength: Int) { + val ignorePolicies = listOf(IgnorePolicy.DEFAULT, IgnorePolicy.TRIM_WHITESPACES, IgnorePolicy.IGNORE_WHITESPACES, IgnorePolicy.IGNORE_WHITESPACES_CHUNKS) + val highlightPolicies = listOf(HighlightPolicy.BY_LINE, HighlightPolicy.BY_WORD, HighlightPolicy.BY_WORD_SPLIT) + + doTest(seed, runs, maxLength) { text1, text2, debugData -> + for (highlightPolicy in highlightPolicies) { + for (ignorePolicy in ignorePolicies) { + debugData.put("HighlightPolicy", highlightPolicy) + debugData.put("IgnorePolicy", ignorePolicy) + + val sequence1 = text1.charsSequence + val sequence2 = text2.charsSequence + + val ranges = createRanges(sequence2, sequence1).map { Range(it.vcsLine1, it.vcsLine2, it.line1, it.line2) } + debugData.put("Ranges", ranges) + + val fragments = compareExplicitBlocks(sequence1, sequence2, ranges, highlightPolicy, ignorePolicy) + debugData.put("Fragments", fragments) + + checkResultLine(text1, text2, fragments, ignorePolicy.comparisonPolicy, !highlightPolicy.isShouldSquash) + } + } + } + } + private fun doTestMerge(seed: Long, runs: Int, maxLength: Int) { val policies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES) @@ -157,6 +191,16 @@ class ComparisonUtilAutoTest : DiffTestCase() { private fun doTest(seed: Long, runs: Int, maxLength: Int, policies: List, test: (Document, Document, ComparisonPolicy, DiffTestCase.DebugData) -> Unit) { + doTest(seed, runs, maxLength) { text1, text2, debugData -> + for (comparisonPolicy in policies) { + debugData.put("Policy", comparisonPolicy) + test(text1, text2, comparisonPolicy, debugData) + } + } + } + + private fun doTest(seed: Long, runs: Int, maxLength: Int, + test: (Document, Document, DiffTestCase.DebugData) -> Unit) { doAutoTest(seed, runs) { debugData -> debugData.put("MaxLength", maxLength) @@ -166,10 +210,7 @@ class ComparisonUtilAutoTest : DiffTestCase() { debugData.put("Text1", textToReadableFormat(text1.charsSequence)) debugData.put("Text2", textToReadableFormat(text2.charsSequence)) - for (comparisonPolicy in policies) { - debugData.put("Policy", comparisonPolicy) - test(text1, text2, comparisonPolicy, debugData) - } + test(text1, text2, debugData) } } diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt index d535981b97ef..8a3244a90846 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt @@ -17,7 +17,9 @@ package com.intellij.diff.comparison import com.intellij.diff.DiffTestCase import com.intellij.diff.fragments.LineFragment +import com.intellij.diff.tools.util.text.LineOffsetsUtil import com.intellij.diff.util.IntPair +import com.intellij.diff.util.Range import com.intellij.openapi.util.Couple import com.intellij.openapi.util.TextRange import java.util.* @@ -411,6 +413,89 @@ class IgnoreComparisonUtilTest : DiffTestCase() { .run() } + fun `test explicit blocks`() { + Test("X_a_Y_b_Z", "X_a 1 c_Y_b 1 c_Z", + " ", " +++ +++ ", + " ", " - ") + .ranged(Range(1, 2, 1, 2)) + .changedLinesNumber(1, 1) + .run() + + Test("X_a_Y_b_Z", "X_a 1 c_Y_b 1 c_Z", + " ", " ++++ +++ ", + " ", " ") + .ranged(Range(1, 2, 1, 2)) + .changedLinesNumber(0, 0) + .run() + + Test("X_a_Y_b_Z", "X_a 1 c_Y_b 1 c_Z", + " ", " + ", + " ", " --- ") + .ranged(Range(3, 4, 3, 4)) + .changedLinesNumber(1, 1) + .run() + + Test("X_a_Y_b_Z", "X_a 1 c_Y_b 1 c_Z", + " ", " + ", + " - ", " ---- ") + .ranged(Range(1, 2, 3, 4)) + .changedLinesNumber(1, 1) + .run() + + Test("X_a_Y_b_Z", "Y_b 1 c_Z", + " ", " + ", + " ", " --- ") + .ranged(Range(3, 4, 1, 2)) + .changedLinesNumber(1, 1) + .run() + + Test("X_a_Y_b_Z", "Y_c_d_b_Z", + " ", " ++++ ", + " ", " ") + .ranged(Range(3, 4, 1, 4)) + .changedLinesNumber(0, 0) + .run() + + Test("X_a_Y_Z", "Y_c_d_Z", + " ", " ++++ ", + " ", " ") + .ranged(Range(3, 3, 1, 3)) + .changedLinesNumber(0, 0) + .run() + + + Test("X_a_Y_Z", "Y_c_d_Z", + " ", " ", + " ", " ---- ") + .ranged(Range(3, 3, 1, 3)) + .changedLinesNumber(0, 2) + .run() + + Test("X_W 1 W_Y_W 2 W_Z", "X_W 3 W_B_W 4 W_Z", + " + + ", " + + ", + " -- ", " -- ") + .ranged(Range(2, 4, 2, 4)) + .changedLinesNumber(1, 1) + .noInnerChanges() + .run() + + Test("X_W 1 W_Y_W 2 W_Z", "X_W 3 W_B_W 4 W_Z", + " + + ", " + + ", + " -- ", " -- ") + .ranged(Range(1, 5, 1, 5)) + .changedLinesNumber(1, 1) + .noInnerChanges() + .run() + + Test("X_W 1 W_Y_W 2 W_Z", "X_W 3 W_B_W 4 W_Z", + " + + ", " + + ", + " ", " ") + .ranged(Range(1, 2, 3, 4)) + .changedLinesNumber(0, 0) + .noInnerChanges() + .run() + } + private inner class Test(val input1: String, val input2: String, ignored1: String, ignored2: String, result1: String, result2: String) { @@ -421,6 +506,7 @@ class IgnoreComparisonUtilTest : DiffTestCase() { private var inner = true private var changedLines: IntPair? = null + private var range: Range? = null fun noInnerChanges(): Test { inner = false @@ -432,6 +518,11 @@ class IgnoreComparisonUtilTest : DiffTestCase() { return this } + fun ranged(range: Range): Test { + this.range = range + return this + } + fun run() { assertEquals(input1.length, ignored1.length) assertEquals(input1.length, result1.length) @@ -444,7 +535,18 @@ class IgnoreComparisonUtilTest : DiffTestCase() { val ignoredRanges1 = parseIgnored(ignored1) val ignoredRanges2 = parseIgnored(ignored2) - val result = MANAGER.compareLinesWithIgnoredRanges(text1, text2, ignoredRanges1, ignoredRanges2, inner, INDICATOR) + val ignored1 = ComparisonManagerImpl.collectIgnoredRanges(ignoredRanges1) + val ignored2 = ComparisonManagerImpl.collectIgnoredRanges(ignoredRanges2) + + val lineOffsets1 = LineOffsetsUtil.create(text1) + val lineOffsets2 = LineOffsetsUtil.create(text2) + + val result = if (range != null) { + MANAGER.compareLinesWithIgnoredRanges(range!!, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, inner, INDICATOR) + } + else { + MANAGER.compareLinesWithIgnoredRanges(text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, inner, INDICATOR) + } val expected = Couple(parseExpected(result1), parseExpected(result2)) val actual = parseActual(result)