diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java index 7a17322825d0..3464fd32040b 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java @@ -781,25 +781,6 @@ public class TextMergeViewer implements MergeTool.MergeViewer { } } - @Nullable - private CharSequence tryResolveConflictedChangeUsingInnerDifferences(@NotNull TextMergeChange change) { - if (!change.isConflict()) return null; - if (change.isResolved(Side.LEFT) || change.isResolved(Side.RIGHT)) return null; - - MergeLineFragment changeFragment = change.getFragment(); - if (changeFragment.getStartLine(ThreeSide.LEFT) == changeFragment.getEndLine(ThreeSide.LEFT)) return null; - if (changeFragment.getStartLine(ThreeSide.BASE) == changeFragment.getEndLine(ThreeSide.BASE)) return null; - if (changeFragment.getStartLine(ThreeSide.RIGHT) == changeFragment.getEndLine(ThreeSide.RIGHT)) return null; - - if (isChangeRangeModified(change)) return null; - - List texts = ThreeSide.map(side -> { - return DiffUtil.getLinesContent(getEditor(side).getDocument(), change.getStartLine(side), change.getEndLine(side)); - }); - - return ComparisonMergeUtil.tryResolveConflict(texts.get(0), texts.get(1), texts.get(2)); - } - private boolean isChangeRangeModified(@NotNull TextMergeChange change) { MergeLineFragment changeFragment = change.getFragment(); int baseStartLine = changeFragment.getStartLine(ThreeSide.BASE); @@ -817,12 +798,24 @@ public class TextMergeViewer implements MergeTool.MergeViewer { } public boolean canResolveConflictedChange(@NotNull TextMergeChange change) { - return tryResolveConflictedChangeUsingInnerDifferences(change) != null; + return change.isConflict() && + change.getType().canBeResolved() && + !change.isResolved(Side.LEFT) && !change.isResolved(Side.RIGHT) && + !isChangeRangeModified(change); } public void resolveConflictedChange(@NotNull TextMergeChange change) { - CharSequence newContent = tryResolveConflictedChangeUsingInnerDifferences(change); - if (newContent == null) return; + if (!canResolveConflictedChange(change)) return; + + List texts = ThreeSide.map(side -> { + return DiffUtil.getLinesContent(getEditor(side).getDocument(), change.getStartLine(side), change.getEndLine(side)); + }); + + CharSequence newContent = ComparisonMergeUtil.tryResolveConflict(texts.get(0), texts.get(1), texts.get(2)); + if (newContent == null) { + LOG.warn(String.format("Can't resolve conflicting change:\n'%s'\n'%s'\n'%s'\n", texts.get(0), texts.get(1), texts.get(2))); + return; + } String[] newContentLines = LineTokenizer.tokenize(newContent, false); myModel.replaceChange(change.getIndex(), Arrays.asList(newContentLines)); @@ -878,19 +871,16 @@ public class TextMergeViewer implements MergeTool.MergeViewer { // private boolean hasNonConflictedChanges(@NotNull ThreeSide side) { - if (ContainerUtil.exists(getAllChanges(), change -> !change.isResolved() && - !change.isConflict() && - change.isChange(side))) { - return true; - } - - if (side == ThreeSide.BASE) { - if (ContainerUtil.exists(getAllChanges(), change -> canResolveConflictedChange(change))) { - return true; + return ContainerUtil.exists(getAllChanges(), change -> { + if (change.isConflict()) { + return side == ThreeSide.BASE && + canResolveConflictedChange(change); } - } - - return false; + else { + return !change.isResolved() && + change.isChange(side); + } + }); } private void applyNonConflictedChanges(@NotNull ThreeSide side) { @@ -1163,9 +1153,12 @@ public class TextMergeViewer implements MergeTool.MergeViewer { @Override protected boolean isEnabled(@NotNull TextMergeChange change) { - if (change.isResolved()) return false; - if (change.isConflict()) return canResolveConflictedChange(change); - return true; + if (change.isConflict()) { + return canResolveConflictedChange(change); + } + else { + return !change.isResolved(); + } } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index da1f8a0e06ac..18c5915c1a7e 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -20,10 +20,7 @@ import com.intellij.diff.DiffContext; import com.intellij.diff.DiffDialogHints; import com.intellij.diff.DiffTool; import com.intellij.diff.SuppressiveDiffTool; -import com.intellij.diff.comparison.ByWord; -import com.intellij.diff.comparison.ComparisonManager; -import com.intellij.diff.comparison.ComparisonPolicy; -import com.intellij.diff.comparison.ComparisonUtil; +import com.intellij.diff.comparison.*; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DiffPsiFileSupport; import com.intellij.diff.contents.DocumentContent; @@ -1027,7 +1024,8 @@ public class DiffUtil { @NotNull public static MergeConflictType getMergeType(@NotNull Condition emptiness, - @NotNull Equality equality) { + @NotNull Equality equality, + @NotNull BooleanGetter conflictResolver) { boolean isLeftEmpty = emptiness.value(ThreeSide.LEFT); boolean isBaseEmpty = emptiness.value(ThreeSide.BASE); boolean isRightEmpty = emptiness.value(ThreeSide.RIGHT); @@ -1042,12 +1040,17 @@ public class DiffUtil { } else { // =-= boolean equalModifications = equality.equals(ThreeSide.LEFT, ThreeSide.RIGHT); - return new MergeConflictType(equalModifications ? TextDiffType.INSERTED : TextDiffType.CONFLICT); + if (equalModifications) { + return new MergeConflictType(TextDiffType.INSERTED, true, true); + } + else { + return new MergeConflictType(TextDiffType.CONFLICT, true, true, false); + } } } else { if (isLeftEmpty && isRightEmpty) { // -=- - return new MergeConflictType(TextDiffType.DELETED); + return new MergeConflictType(TextDiffType.DELETED, true, true); } else { // -==, ==-, === boolean unchangedLeft = equality.equals(ThreeSide.BASE, ThreeSide.LEFT); @@ -1058,7 +1061,13 @@ public class DiffUtil { if (unchangedRight) return new MergeConflictType(isLeftEmpty ? TextDiffType.DELETED : TextDiffType.MODIFIED, true, false); boolean equalModifications = equality.equals(ThreeSide.LEFT, ThreeSide.RIGHT); - return new MergeConflictType(equalModifications ? TextDiffType.MODIFIED : TextDiffType.CONFLICT); + if (equalModifications) { + return new MergeConflictType(TextDiffType.MODIFIED, true, true); + } + else { + boolean canBeResolved = !isLeftEmpty && !isRightEmpty && conflictResolver.get(); + return new MergeConflictType(TextDiffType.CONFLICT, true, true, canBeResolved); + } } } } @@ -1069,7 +1078,17 @@ public class DiffUtil { @NotNull List lineOffsets, @NotNull ComparisonPolicy policy) { return getMergeType((side) -> isLineMergeIntervalEmpty(fragment, side), - (side1, side2) -> compareLineMergeContents(fragment, sequences, lineOffsets, policy, side1, side2)); + (side1, side2) -> compareLineMergeContents(fragment, sequences, lineOffsets, policy, side1, side2), + () -> canResolveLineConflict(fragment, sequences, lineOffsets)); + } + + private static boolean canResolveLineConflict(@NotNull MergeLineFragment fragment, + @NotNull List sequences, + @NotNull List lineOffsets) { + List contents = ThreeSide.map(side -> { + return getLinesContent(side.select(sequences), side.select(lineOffsets), fragment.getStartLine(side), fragment.getEndLine(side)); + }); + return ComparisonMergeUtil.tryResolveConflict(contents.get(0), contents.get(1), contents.get(2)) != null; } private static boolean compareLineMergeContents(@NotNull MergeLineFragment fragment, @@ -1111,7 +1130,8 @@ public class DiffUtil { @NotNull List texts, @NotNull ComparisonPolicy policy) { return getMergeType((side) -> isWordMergeIntervalEmpty(fragment, side), - (side1, side2) -> compareWordMergeContents(fragment, texts, policy, side1, side2)); + (side1, side2) -> compareWordMergeContents(fragment, texts, policy, side1, side2), + BooleanGetter.FALSE); } private static boolean compareWordMergeContents(@NotNull MergeWordFragment fragment, diff --git a/platform/diff-impl/src/com/intellij/diff/util/MergeConflictType.java b/platform/diff-impl/src/com/intellij/diff/util/MergeConflictType.java index 69771bc894db..2996e9429654 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/MergeConflictType.java +++ b/platform/diff-impl/src/com/intellij/diff/util/MergeConflictType.java @@ -21,15 +21,17 @@ public class MergeConflictType { @NotNull private final TextDiffType myType; private final boolean myLeftChange; private final boolean myRightChange; - - public MergeConflictType(@NotNull TextDiffType type) { - this(type, true, true); - } + private final boolean myCanBeResolved; public MergeConflictType(@NotNull TextDiffType type, boolean leftChange, boolean rightChange) { + this(type, leftChange, rightChange, true); + } + + public MergeConflictType(@NotNull TextDiffType type, boolean leftChange, boolean rightChange, boolean canBeResolved) { myType = type; myLeftChange = leftChange; myRightChange = rightChange; + myCanBeResolved = canBeResolved; } @NotNull @@ -37,6 +39,10 @@ public class MergeConflictType { return myType; } + public boolean canBeResolved() { + return myCanBeResolved; + } + public boolean isChange(@NotNull Side side) { return side.isLeft() ? myLeftChange : myRightChange; }