merge: do not re-check if conflict can be resolved every time

* store this information in MergeConflictType
This commit is contained in:
Aleksey Pivovarov
2017-03-06 16:50:39 +03:00
parent 33b8e04870
commit 929afafc64
3 changed files with 70 additions and 51 deletions
@@ -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<CharSequence> 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<CharSequence> 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
@@ -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<ThreeSide> emptiness,
@NotNull Equality<ThreeSide> equality) {
@NotNull Equality<ThreeSide> 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> 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<? extends CharSequence> sequences,
@NotNull List<LineOffsets> lineOffsets) {
List<? extends CharSequence> 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<? extends CharSequence> 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,
@@ -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;
}