diff: do not merge words while ignoring ranges

This commit is contained in:
Aleksey Pivovarov
2017-03-09 15:09:20 +03:00
committed by Aleksey Pivovarov
parent 3514cf3cdf
commit 059d4d1d41
2 changed files with 63 additions and 13 deletions
@@ -16,6 +16,7 @@
package com.intellij.diff.comparison;
import com.intellij.diff.comparison.iterables.DiffIterable;
import com.intellij.diff.comparison.iterables.DiffIterableUtil;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.fragments.*;
import com.intellij.diff.util.DiffUtil;
@@ -38,6 +39,7 @@ import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import static com.intellij.diff.comparison.iterables.DiffIterableUtil.fair;
import static java.util.Collections.singletonList;
public class ComparisonManagerImpl extends ComparisonManager {
@@ -461,9 +463,11 @@ public class ComparisonManagerImpl extends ComparisonManager {
List<CharSequence> lineTexts1 = ContainerUtil.map(lines1, line -> line.getNotIgnoredContent(ignored1));
List<CharSequence> lineTexts2 = ContainerUtil.map(lines2, line -> line.getNotIgnoredContent(ignored2));
FairDiffIterable iterable = ByLine.compare(lineTexts1, lineTexts2, ComparisonPolicy.DEFAULT, indicator);
List<LineFragment> lineFragments = convertIntoLineFragments(lines1, lines2, iterable);
FairDiffIterable correctedIterable = correctIgnoredRangesSecondStep(iterable, lines1, lines2, ignored1, ignored2);
List<LineFragment> lineFragments = convertIntoLineFragments(lines1, lines2, correctedIterable);
if (innerFragments) {
lineFragments = createInnerFragments(lineFragments, text1, text2, ComparisonPolicy.DEFAULT, indicator);
@@ -483,6 +487,26 @@ public class ComparisonManagerImpl extends ComparisonManager {
return set;
}
@NotNull
private static FairDiffIterable correctIgnoredRangesSecondStep(@NotNull FairDiffIterable iterable,
@NotNull List<Line> lines1,
@NotNull List<Line> lines2,
@NotNull BitSet ignored1,
@NotNull BitSet ignored2) {
DiffIterableUtil.ChangeBuilder builder = new DiffIterableUtil.ChangeBuilder(lines1.size(), lines2.size());
for (Range range : iterable.iterateUnchanged()) {
int count = range.end1 - range.start1;
for (int i = 0; i < count; i++) {
int index1 = range.start1 + i;
int index2 = range.start2 + i;
if (areIgnoredEqualLines(lines1.get(index1), lines2.get(index2), ignored1, ignored2)) {
builder.markEqual(index1, index2);
}
}
}
return fair(builder.finish());
}
@Nullable
private static LineFragment trimIgnoredChanges(@NotNull LineFragment fragment,
@NotNull List<Line> lines1,
@@ -542,7 +566,7 @@ public class ComparisonManagerImpl extends ComparisonManager {
}
private static boolean isIgnoredLine(@NotNull Line line, @NotNull BitSet ignored) {
return trimIgnoredRange(line.getOffset1(), line.getOffset2(), ignored, 0).isEmpty();
return isIgnoredRange(ignored, line.getOffset1(), line.getOffset2());
}
private static boolean areIgnoredEqualLines(@NotNull Line line1, @NotNull Line line2,
@@ -551,13 +575,36 @@ public class ComparisonManagerImpl extends ComparisonManager {
int end1 = line1.getOffset2();
int start2 = line2.getOffset1();
int end2 = line2.getOffset2();
Range range = TrimUtil.trimExpandText(line1.getOriginalText(), line2.getOriginalText(),
start1, start2, end1, end2,
ignored1, ignored2);
return range.isEmpty();
if (!range.isEmpty()) return false;
List<ByWord.InlineChunk> words1 = getNonIgnoredWords(line1, ignored1);
List<ByWord.InlineChunk> words2 = getNonIgnoredWords(line2, ignored2);
if (words1.size() != words2.size()) return false;
for (int i = 0; i < words1.size(); i++) {
CharSequence word1 = getWordContent(line1, words1.get(i));
CharSequence word2 = getWordContent(line2, words2.get(i));
if (!StringUtil.equals(word1, word2)) return false;
}
return true;
}
@NotNull
private static List<ByWord.InlineChunk> getNonIgnoredWords(@NotNull Line line, @NotNull BitSet ignored) {
int offset = line.getOffset1();
List<ByWord.InlineChunk> innerChunks = ByWord.getInlineChunks(line.getContent());
return ContainerUtil.filter(innerChunks, it -> it instanceof ByWord.WordChunk &&
!isIgnoredRange(ignored, offset + it.getOffset1(), offset + it.getOffset2()));
}
@NotNull
private static CharSequence getWordContent(@NotNull Line line, @NotNull ByWord.InlineChunk word) {
return line.getContent().subSequence(word.getOffset1(), word.getOffset2());
}
@NotNull
private static TextRange trimIgnoredRange(int start, int end, @NotNull BitSet ignored, int offset) {
@@ -565,6 +612,9 @@ public class ComparisonManagerImpl extends ComparisonManager {
return new TextRange(intPair.val1 - offset, intPair.val2 - offset);
}
private static boolean isIgnoredRange(@NotNull BitSet ignored, int start, int end) {
return ignored.nextClearBit(start) >= end;
}
private static class Line {
@NotNull private final CharSequence myChars;
@@ -309,8 +309,8 @@ class IgnoreComparisonUtilTest : DiffTestCase() {
Test("X Y", "XY",
" + ", " ",
" ", " ")
.changedLinesNumber(0, 0)
"---", "--")
.changedLinesNumber(1, 1)
.run()
}
@@ -337,17 +337,17 @@ class IgnoreComparisonUtilTest : DiffTestCase() {
" - ", " - ")
.changedLinesNumber(2, 1)
.run()
Test("int X = 0;", "intX = 0;",
" + + + ", " + + ",
"----- ", "---- ")
.changedLinesNumber(1, 1)
.run()
}
fun `test Java bad samples`() {
//TODO
Test("int X = 0;", "intX = 0;",
" + + + ", " + + ",
" ", " ")
.changedLinesNumber(0, 0)
.run()
Test("System.out.println (\"Hello world\");", "System.out.println(\"Hello world\");",
" . + . ", " . . ",
" - . - . ", " . . ")