diff: extract diff computation logic

This commit is contained in:
Aleksey Pivovarov
2017-02-02 18:21:33 +03:00
committed by Aleksey Pivovarov
parent 6e68c055a8
commit b0f96c60a4
16 changed files with 632 additions and 415 deletions
@@ -29,13 +29,15 @@ import com.intellij.diff.contents.DocumentContent;
import com.intellij.diff.fragments.MergeLineFragment;
import com.intellij.diff.requests.ContentDiffRequest;
import com.intellij.diff.requests.SimpleDiffRequest;
import com.intellij.diff.tools.util.text.MergeInnerDifferences;
import com.intellij.diff.tools.simple.ThreesideTextDiffViewerEx;
import com.intellij.diff.tools.util.DiffNotifications;
import com.intellij.diff.tools.util.KeyboardModifierListener;
import com.intellij.diff.tools.util.base.HighlightPolicy;
import com.intellij.diff.tools.util.base.IgnorePolicy;
import com.intellij.diff.tools.util.base.TextDiffViewerUtil;
import com.intellij.diff.tools.util.text.LineOffsets;
import com.intellij.diff.tools.util.text.MergeInnerDifferences;
import com.intellij.diff.tools.util.text.TextDiffProviderBase;
import com.intellij.diff.util.*;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
@@ -180,6 +182,8 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
@NotNull private final MyInnerDiffWorker myInnerDiffWorker;
@NotNull private final MyLineStatusTracker myLineStatusTracker;
@NotNull private final TextDiffProviderBase myTextDiffProvider;
// all changes - both applied and unapplied ones
@NotNull private final List<TextMergeChange> myAllMergeChanges = new ArrayList<>();
@@ -197,6 +201,11 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
myLineStatusTracker = new MyLineStatusTracker(getProject(), getEditor().getDocument());
myTextDiffProvider = new TextDiffProviderBase(getTextSettings(),
myInnerDiffWorker::onSettingsChanged,
new IgnorePolicy[]{IgnorePolicy.DEFAULT},
new HighlightPolicy[]{HighlightPolicy.BY_LINE, HighlightPolicy.BY_WORD});
DiffUtil.registerAction(new ApplySelectedChangesAction(Side.LEFT, true), myPanel);
DiffUtil.registerAction(new ApplySelectedChangesAction(Side.RIGHT, true), myPanel);
DiffUtil.registerAction(new IgnoreSelectedChangesSideAction(Side.LEFT, true), myPanel);
@@ -225,7 +234,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
protected List<AnAction> createToolbarActions() {
List<AnAction> group = new ArrayList<>();
group.add(new MyHighlightPolicySettingAction());
group.addAll(myTextDiffProvider.getToolbarActions());
group.add(new MyToggleAutoScrollAction());
group.add(myEditorSettingsAction);
@@ -271,6 +280,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
protected List<AnAction> createPopupActions() {
List<AnAction> group = new ArrayList<>();
group.addAll(myTextDiffProvider.getPopupActions());
group.add(Separator.getInstance());
group.add(new MyToggleAutoScrollAction());
@@ -503,7 +513,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
@CalledInAwt
public void onSettingsChanged() {
boolean enabled = getHighlightPolicy() == HighlightPolicy.BY_WORD;
boolean enabled = myTextDiffProvider.getHighlightPolicy() == HighlightPolicy.BY_WORD;
if (myEnabled == enabled) return;
myEnabled = enabled;
@@ -632,14 +642,6 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
}
}
@NotNull
private HighlightPolicy getHighlightPolicy() {
HighlightPolicy policy = getTextSettings().getHighlightPolicy();
if (policy == HighlightPolicy.BY_WORD_SPLIT) return HighlightPolicy.BY_WORD;
if (policy == HighlightPolicy.DO_NOT_HIGHLIGHT) return HighlightPolicy.BY_LINE;
return policy;
}
//
// Getters
//
@@ -893,29 +895,6 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
if (firstConflict != null) doScrollToChange(firstConflict, true);
}
private class MyHighlightPolicySettingAction extends TextDiffViewerUtil.HighlightPolicySettingAction {
public MyHighlightPolicySettingAction() {
super(getTextSettings());
}
@NotNull
@Override
protected HighlightPolicy getCurrentSetting() {
return getHighlightPolicy();
}
@NotNull
@Override
protected List<HighlightPolicy> getAvailableSettings() {
return ContainerUtil.list(HighlightPolicy.BY_LINE, HighlightPolicy.BY_WORD);
}
@Override
protected void onSettingsChanged() {
myInnerDiffWorker.onSettingsChanged();
}
}
private abstract class ApplySelectedChangesActionBase extends AnAction implements DumbAware {
private final boolean myShortcut;
@@ -1410,21 +1389,21 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
@NotNull public final List<CharSequence> text;
public InnerChunkData(@NotNull TextMergeChange change, @NotNull List<Document> documents) {
text = ThreeSide.map(side -> {
if (!change.isChange(side) || change.isResolved(side)) return null;
return getChunkContent(change, documents, side);
});
text = getChunks(change, documents);
}
@Nullable
@CalledWithReadLock
private static CharSequence getChunkContent(@NotNull TextMergeChange change,
@NotNull List<Document> documents,
@NotNull ThreeSide side) {
int startLine = change.getStartLine(side);
int endLine = change.getEndLine(side);
if (startLine == endLine) return null;
return DiffUtil.getLinesContent(side.select(documents), startLine, endLine);
@NotNull
private static List<CharSequence> getChunks(@NotNull TextMergeChange change,
@NotNull List<Document> documents) {
return ThreeSide.map(side -> {
if (!change.isChange(side) || change.isResolved(side)) return null;
int startLine = change.getStartLine(side);
int endLine = change.getEndLine(side);
if (startLine == endLine) return null;
return DiffUtil.getLinesContent(side.select(documents), startLine, endLine);
});
}
}
}
@@ -26,9 +26,12 @@ import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.requests.ContentDiffRequest;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.tools.util.*;
import com.intellij.diff.tools.util.base.*;
import com.intellij.diff.tools.util.base.InitialScrollPositionSupport;
import com.intellij.diff.tools.util.base.ListenerDiffViewerBase;
import com.intellij.diff.tools.util.base.TextDiffSettingsHolder.TextDiffSettings;
import com.intellij.diff.tools.util.base.TextDiffViewerUtil;
import com.intellij.diff.tools.util.side.TwosideTextDiffViewer;
import com.intellij.diff.tools.util.text.TwosideTextDiffProvider;
import com.intellij.diff.util.*;
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
import com.intellij.icons.AllIcons;
@@ -77,6 +80,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
@NotNull private final MyInitialScrollHelper myInitialScrollHelper = new MyInitialScrollHelper();
@NotNull private final MyFoldingModel myFoldingModel;
@NotNull private final TwosideTextDiffProvider.NoIgnore myTextDiffProvider;
@NotNull protected Side myMasterSide = Side.RIGHT;
@Nullable private ChangedBlockData myChangedBlockData;
@@ -117,6 +122,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
myEditorSettingsAction = new SetEditorSettingsAction(getTextSettings(), getEditors());
myEditorSettingsAction.applyDefaults();
myTextDiffProvider = DiffUtil.createNoIgnoreTextDiffProvider(getRequest(), getTextSettings(), this::rediff);
new MyOpenInEditorWithMouseAction().install(getEditors());
TextDiffViewerUtil.checkDifferentDocuments(myRequest);
@@ -184,9 +191,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
public List<AnAction> createToolbarActions() {
List<AnAction> group = new ArrayList<>();
// TODO: allow to choose myMasterSide
group.add(new MyIgnorePolicySettingAction());
group.add(new MyHighlightPolicySettingAction());
group.addAll(myTextDiffProvider.getToolbarActions());
group.add(new MyToggleExpandByDefaultAction());
group.add(new MyReadOnlyLockAction());
group.add(myEditorSettingsAction);
@@ -203,11 +208,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
public List<AnAction> createPopupActions() {
List<AnAction> group = new ArrayList<>();
group.add(Separator.getInstance());
group.add(new MyIgnorePolicySettingAction().getPopupGroup());
group.add(Separator.getInstance());
group.add(new MyHighlightPolicySettingAction().getPopupGroup());
group.add(Separator.getInstance());
group.addAll(myTextDiffProvider.getPopupActions());
group.add(new MyToggleExpandByDefaultAction());
group.add(Separator.getInstance());
@@ -260,7 +261,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
return new CharSequence[]{document1.getImmutableCharSequence(), document2.getImmutableCharSequence()};
});
final List<LineFragment> fragments = DiffUtil.compare(myRequest, texts[0], texts[1], getDiffConfig(), indicator);
final List<LineFragment> fragments = myTextDiffProvider.compare(texts[0], texts[1], indicator);
final DocumentContent content1 = getContent1();
final DocumentContent content2 = getContent2();
@@ -788,18 +789,6 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
return TextDiffViewerUtil.getFoldingModelSettings(myContext);
}
@NotNull
private DiffUtil.DiffConfig getDiffConfig() {
return new DiffUtil.DiffConfig(getTextSettings().getIgnorePolicy(), getHighlightPolicy());
}
@NotNull
private HighlightPolicy getHighlightPolicy() {
HighlightPolicy policy = getTextSettings().getHighlightPolicy();
if (policy == HighlightPolicy.DO_NOT_HIGHLIGHT) return HighlightPolicy.BY_LINE;
return policy;
}
//
// Getters
//
@@ -995,42 +984,6 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
}
}
private class MyHighlightPolicySettingAction extends TextDiffViewerUtil.HighlightPolicySettingAction {
public MyHighlightPolicySettingAction() {
super(getTextSettings());
}
@NotNull
@Override
protected HighlightPolicy getCurrentSetting() {
return getHighlightPolicy();
}
@NotNull
@Override
protected List<HighlightPolicy> getAvailableSettings() {
ArrayList<HighlightPolicy> settings = ContainerUtil.newArrayList(HighlightPolicy.values());
settings.remove(HighlightPolicy.DO_NOT_HIGHLIGHT);
return settings;
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
private class MyIgnorePolicySettingAction extends TextDiffViewerUtil.IgnorePolicySettingAction {
public MyIgnorePolicySettingAction() {
super(getTextSettings());
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
private class MyReadOnlyLockAction extends TextDiffViewerUtil.ReadOnlyLockAction {
public MyReadOnlyLockAction() {
super(getContext());
@@ -23,9 +23,9 @@ import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.requests.ContentDiffRequest;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.tools.util.*;
import com.intellij.diff.tools.util.base.HighlightPolicy;
import com.intellij.diff.tools.util.base.TextDiffViewerUtil;
import com.intellij.diff.tools.util.side.TwosideTextDiffViewer;
import com.intellij.diff.tools.util.text.TwosideTextDiffProvider;
import com.intellij.diff.util.*;
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
import com.intellij.openapi.Disposable;
@@ -68,6 +68,8 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
@NotNull private final MyInitialScrollHelper myInitialScrollHelper = new MyInitialScrollHelper();
@NotNull private final ModifierProvider myModifierProvider;
@NotNull private final TwosideTextDiffProvider myTextDiffProvider;
public SimpleDiffViewer(@NotNull DiffContext context, @NotNull DiffRequest request) {
super(context, (ContentDiffRequest)request);
@@ -78,6 +80,8 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
myModifierProvider = new ModifierProvider();
myTextDiffProvider = DiffUtil.createTextDiffProvider(getRequest(), getTextSettings(), this::rediff);
DiffUtil.registerAction(new ReplaceSelectedChangesAction(Side.LEFT, true), myPanel);
DiffUtil.registerAction(new AppendSelectedChangesAction(Side.LEFT, true), myPanel);
DiffUtil.registerAction(new ReplaceSelectedChangesAction(Side.RIGHT, true), myPanel);
@@ -105,8 +109,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
protected List<AnAction> createToolbarActions() {
List<AnAction> group = new ArrayList<>();
group.add(new MyIgnorePolicySettingAction());
group.add(new MyHighlightPolicySettingAction());
group.addAll(myTextDiffProvider.getToolbarActions());
group.add(new MyToggleExpandByDefaultAction());
group.add(new MyToggleAutoScrollAction());
group.add(new MyReadOnlyLockAction());
@@ -123,11 +126,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
protected List<AnAction> createPopupActions() {
List<AnAction> group = new ArrayList<>();
group.add(Separator.getInstance());
group.add(new MyIgnorePolicySettingAction().getPopupGroup());
group.add(Separator.getInstance());
group.add(new MyHighlightPolicySettingAction().getPopupGroup());
group.add(Separator.getInstance());
group.addAll(myTextDiffProvider.getPopupActions());
group.add(new MyToggleAutoScrollAction());
group.add(new MyToggleExpandByDefaultAction());
@@ -197,10 +196,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
return new CharSequence[]{document1.getImmutableCharSequence(), document2.getImmutableCharSequence()};
});
List<LineFragment> lineFragments = null;
if (getHighlightPolicy().isShouldCompare()) {
lineFragments = DiffUtil.compare(myRequest, texts[0], texts[1], getDiffConfig(), indicator);
}
List<LineFragment> lineFragments = myTextDiffProvider.compare(texts[0], texts[1], indicator);
boolean isContentsEqual = (lineFragments == null || lineFragments.isEmpty()) &&
StringUtil.equals(texts[0], texts[1]);
@@ -267,16 +263,6 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
destroyChangedBlocks();
}
@NotNull
private DiffUtil.DiffConfig getDiffConfig() {
return new DiffUtil.DiffConfig(getTextSettings().getIgnorePolicy(), getHighlightPolicy());
}
@NotNull
private HighlightPolicy getHighlightPolicy() {
return getTextSettings().getHighlightPolicy();
}
//
// Impl
//
@@ -662,28 +648,6 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
myDiffChanges.remove(change);
}
private class MyHighlightPolicySettingAction extends TextDiffViewerUtil.HighlightPolicySettingAction {
public MyHighlightPolicySettingAction() {
super(getTextSettings());
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
private class MyIgnorePolicySettingAction extends TextDiffViewerUtil.IgnorePolicySettingAction {
public MyIgnorePolicySettingAction() {
super(getTextSettings());
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
private class MyToggleExpandByDefaultAction extends TextDiffViewerUtil.ToggleExpandByDefaultAction {
public MyToggleExpandByDefaultAction() {
super(getTextSettings());
@@ -808,7 +772,9 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
@Nullable
@Override
protected String getMessage() {
if (getHighlightPolicy() == HighlightPolicy.DO_NOT_HIGHLIGHT) return DiffBundle.message("diff.highlighting.disabled.text");
if (myTextDiffProvider.isHighlightingDisabled()) {
return DiffBundle.message("diff.highlighting.disabled.text");
}
int changesCount = myDiffChanges.size() + myInvalidDiffChanges.size();
if (changesCount == 0 && !myIsContentsEqual) {
return DiffBundle.message("diff.all.differences.ignored.text");
@@ -24,6 +24,7 @@ import com.intellij.diff.tools.util.DiffDataKeys;
import com.intellij.diff.tools.util.base.HighlightPolicy;
import com.intellij.diff.tools.util.base.TextDiffViewerUtil;
import com.intellij.diff.tools.util.side.OnesideTextDiffViewer;
import com.intellij.diff.tools.util.text.TextDiffProvider;
import com.intellij.diff.util.DiffDrawUtil;
import com.intellij.diff.util.DiffUtil;
import com.intellij.diff.util.LineRange;
@@ -48,10 +49,14 @@ import static com.intellij.diff.util.DiffUtil.getLineCount;
public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer {
@NotNull private final MyInitialScrollHelper myInitialScrollHelper = new MyInitialScrollHelper();
@NotNull private final TextDiffProvider myTextDiffProvider;
@NotNull private final List<RangeHighlighter> myHighlighters = new ArrayList<>();
public SimpleOnesideDiffViewer(@NotNull DiffContext context, @NotNull DiffRequest request) {
super(context, (ContentDiffRequest)request);
myTextDiffProvider = DiffUtil.createTextDiffProvider(getRequest(), getTextSettings(), this::rediff);
}
@Override
@@ -69,8 +74,7 @@ public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer {
protected List<AnAction> createToolbarActions() {
List<AnAction> group = new ArrayList<>();
group.add(new MyIgnorePolicySettingAction());
group.add(new MyHighlightPolicySettingAction());
group.addAll(myTextDiffProvider.getToolbarActions());
group.add(new MyReadOnlyLockAction());
group.add(myEditorSettingsAction);
@@ -85,11 +89,7 @@ public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer {
protected List<AnAction> createPopupActions() {
List<AnAction> group = new ArrayList<>();
group.add(Separator.getInstance());
group.add(new MyIgnorePolicySettingAction().getPopupGroup());
group.add(Separator.getInstance());
group.add(new MyHighlightPolicySettingAction().getPopupGroup());
group.addAll(myTextDiffProvider.getPopupActions());
group.add(Separator.getInstance());
group.addAll(super.createPopupActions());
@@ -183,32 +183,6 @@ public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer {
}
}
//
// Modification operations
//
private class MyHighlightPolicySettingAction extends TextDiffViewerUtil.HighlightPolicySettingAction {
public MyHighlightPolicySettingAction() {
super(getTextSettings());
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
private class MyIgnorePolicySettingAction extends TextDiffViewerUtil.IgnorePolicySettingAction {
public MyIgnorePolicySettingAction() {
super(getTextSettings());
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
//
// Helpers
//
@@ -16,24 +16,18 @@
package com.intellij.diff.tools.simple;
import com.intellij.diff.DiffContext;
import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.comparison.DiffTooBigException;
import com.intellij.diff.contents.DocumentContent;
import com.intellij.diff.fragments.MergeLineFragment;
import com.intellij.diff.requests.ContentDiffRequest;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.tools.util.DiffNotifications;
import com.intellij.diff.tools.util.base.HighlightPolicy;
import com.intellij.diff.tools.util.base.IgnorePolicy;
import com.intellij.diff.tools.util.base.TextDiffViewerUtil;
import com.intellij.diff.tools.util.side.ThreesideTextDiffViewer;
import com.intellij.diff.tools.util.text.LineOffsets;
import com.intellij.diff.tools.util.text.FineMergeLineFragment;
import com.intellij.diff.tools.util.text.MergeInnerDifferences;
import com.intellij.diff.tools.util.text.SimpleThreesideTextDiffProvider;
import com.intellij.diff.util.*;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.Separator;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.event.DocumentEvent;
@@ -42,17 +36,20 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
@NotNull private final SimpleThreesideTextDiffProvider myTextDiffProvider;
@NotNull private final List<SimpleThreesideDiffChange> myDiffChanges = new ArrayList<>();
@NotNull private final List<SimpleThreesideDiffChange> myInvalidDiffChanges = new ArrayList<>();
public SimpleThreesideDiffViewer(@NotNull DiffContext context, @NotNull DiffRequest request) {
super(context, (ContentDiffRequest)request);
myTextDiffProvider = new SimpleThreesideTextDiffProvider(getTextSettings(), this::rediff);
}
@NotNull
@@ -60,8 +57,7 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
protected List<AnAction> createToolbarActions() {
List<AnAction> group = new ArrayList<>();
group.add(new MyIgnorePolicySettingAction());
group.add(new MyHighlightPolicySettingAction());
group.addAll(myTextDiffProvider.getToolbarActions());
group.add(new MyToggleExpandByDefaultAction());
group.add(new MyToggleAutoScrollAction());
group.add(new MyEditorReadOnlyLockAction());
@@ -83,11 +79,7 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
protected List<AnAction> createPopupActions() {
List<AnAction> group = new ArrayList<>();
group.add(Separator.getInstance());
group.add(new MyIgnorePolicySettingAction().getPopupGroup());
//group.add(Separator.getInstance());
//group.add(new MyHighlightPolicySettingAction().getPopupGroup());
group.add(Separator.getInstance());
group.addAll(myTextDiffProvider.getPopupActions());
group.add(new MyToggleAutoScrollAction());
group.add(new MyToggleExpandByDefaultAction());
@@ -114,42 +106,14 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
try {
indicator.checkCanceled();
List<? extends DocumentContent> contents = getContents();
List<CharSequence> sequences = ReadAction.compute(() -> {
indicator.checkCanceled();
return ContainerUtil.map(contents, content -> content.getDocument().getImmutableCharSequence());
});
List<LineOffsets> lineOffsets = ContainerUtil.map(sequences, LineOffsets::create);
final ComparisonPolicy comparisonPolicy = getIgnorePolicy().getComparisonPolicy();
ComparisonManager manager = ComparisonManager.getInstance();
List<MergeLineFragment> lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2),
comparisonPolicy, indicator);
List<MergeConflictType> conflictTypes = ContainerUtil.map(lineFragments, fragment -> {
return DiffUtil.getLineMergeType(fragment, sequences, lineOffsets, comparisonPolicy);
List<CharSequence> sequences = ContainerUtil.map(getContents(), content -> {
return content.getDocument().getImmutableCharSequence();
});
List<MergeInnerDifferences> innerFragments = null;
if (getHighlightPolicy().isFineFragments()) {
innerFragments = new ArrayList<>(lineFragments.size());
List<FineMergeLineFragment> lineFragments = myTextDiffProvider.compare(sequences.get(0), sequences.get(1), sequences.get(2),
indicator);
for (int i = 0; i < lineFragments.size(); i++) {
final MergeLineFragment fragment = lineFragments.get(i);
final MergeConflictType conflictType = conflictTypes.get(i);
indicator.checkCanceled();
List<CharSequence> chunks = ThreeSide.map(side -> {
if (!conflictType.isChange(side)) return null;
return getChunkContent(fragment, sequences, lineOffsets, side);
});
innerFragments.add(DiffUtil.compareThreesideInner(chunks, comparisonPolicy, indicator));
}
}
return apply(lineFragments, conflictTypes, innerFragments);
return apply(lineFragments);
}
catch (DiffTooBigException e) {
return applyNotification(DiffNotifications.createDiffTooBig());
@@ -163,30 +127,16 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
}
}
@Nullable
private static CharSequence getChunkContent(@NotNull MergeLineFragment fragment,
@NotNull List<CharSequence> sequences,
@NotNull List<LineOffsets> lineOffsets,
@NotNull ThreeSide side) {
int startLine = fragment.getStartLine(side);
int endLine = fragment.getEndLine(side);
if (startLine == endLine) return null;
return DiffUtil.getLinesContent(side.select(sequences), side.select(lineOffsets), startLine, endLine);
}
@NotNull
private Runnable apply(@NotNull final List<MergeLineFragment> fragments,
@NotNull final List<MergeConflictType> conflictTypes,
@Nullable final List<MergeInnerDifferences> innerDifferences) {
private Runnable apply(@NotNull final List<FineMergeLineFragment> fragments) {
return () -> {
myFoldingModel.updateContext(myRequest, getFoldingModelSettings());
clearDiffPresentation();
resetChangeCounters();
for (int i = 0; i < fragments.size(); i++) {
MergeLineFragment fragment = fragments.get(i);
MergeConflictType conflictType = conflictTypes.get(i);
MergeInnerDifferences innerFragments = innerDifferences != null ? innerDifferences.get(i) : null;
for (FineMergeLineFragment fragment : fragments) {
MergeConflictType conflictType = fragment.getConflictType();
MergeInnerDifferences innerFragments = fragment.getInnerFragments();
SimpleThreesideDiffChange change = new SimpleThreesideDiffChange(fragment, conflictType, innerFragments, this);
myDiffChanges.add(change);
@@ -250,21 +200,6 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
}
}
@NotNull
private IgnorePolicy getIgnorePolicy() {
IgnorePolicy policy = getTextSettings().getIgnorePolicy();
if (policy == IgnorePolicy.IGNORE_WHITESPACES_CHUNKS) return IgnorePolicy.IGNORE_WHITESPACES;
return policy;
}
@NotNull
private HighlightPolicy getHighlightPolicy() {
HighlightPolicy policy = getTextSettings().getHighlightPolicy();
if (policy == HighlightPolicy.BY_WORD_SPLIT) return HighlightPolicy.BY_WORD;
if (policy == HighlightPolicy.DO_NOT_HIGHLIGHT) return HighlightPolicy.BY_LINE;
return policy;
}
//
// Getters
//
@@ -294,54 +229,6 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
// Actions
//
private class MyIgnorePolicySettingAction extends TextDiffViewerUtil.IgnorePolicySettingAction {
public MyIgnorePolicySettingAction() {
super(getTextSettings());
}
@NotNull
@Override
protected IgnorePolicy getCurrentSetting() {
return getIgnorePolicy();
}
@NotNull
@Override
protected List<IgnorePolicy> getAvailableSettings() {
ArrayList<IgnorePolicy> settings = ContainerUtil.newArrayList(IgnorePolicy.values());
settings.remove(IgnorePolicy.IGNORE_WHITESPACES_CHUNKS);
return settings;
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
private class MyHighlightPolicySettingAction extends TextDiffViewerUtil.HighlightPolicySettingAction {
public MyHighlightPolicySettingAction() {
super(getTextSettings());
}
@NotNull
@Override
protected HighlightPolicy getCurrentSetting() {
return getHighlightPolicy();
}
@NotNull
@Override
protected List<HighlightPolicy> getAvailableSettings() {
return ContainerUtil.list(HighlightPolicy.BY_LINE, HighlightPolicy.BY_WORD);
}
@Override
protected void onSettingsChanged() {
rediff();
}
}
protected class MyEditorReadOnlyLockAction extends TextDiffViewerUtil.EditorReadOnlyLockAction {
public MyEditorReadOnlyLockAction() {
super(getContext(), getEditableEditors());
@@ -446,7 +446,7 @@ public abstract class ThreesideTextDiffViewerEx extends ThreesideTextDiffViewer
assert editors.length == 3;
}
public void install(@Nullable List<MergeLineFragment> fragments,
public void install(@Nullable List<? extends MergeLineFragment> fragments,
@NotNull UserDataHolder context,
@NotNull FoldingModelSupport.Settings settings) {
Iterator<int[]> it = map(fragments, fragment -> new int[]{
@@ -39,6 +39,7 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.ToggleActionButton;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EditorPopupHandler;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
@@ -51,6 +52,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.intellij.util.containers.ContainerUtil.list;
public class TextDiffViewerUtil {
private static final Logger LOG = Logger.getInstance(TextDiffViewerUtil.class);
@@ -162,136 +165,185 @@ public class TextDiffViewerUtil {
// Actions
//
// TODO: pretty icons ?
public static abstract class ComboBoxSettingAction<T> extends ComboBoxAction implements DumbAware {
private DefaultActionGroup myChildren;
private DefaultActionGroup myActions;
@Override
public void update(AnActionEvent e) {
Presentation presentation = e.getPresentation();
presentation.setText(getText(getCurrentSetting()));
}
@NotNull
public DefaultActionGroup getPopupGroup() {
initChildren();
return myChildren;
presentation.setText(getText(getValue()));
}
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
initChildren();
return myChildren;
return getActions();
}
private void initChildren() {
if (myChildren == null) {
myChildren = new DefaultActionGroup();
for (T setting : getAvailableSettings()) {
myChildren.add(new MyAction(setting));
@NotNull
public DefaultActionGroup getActions() {
if (myActions == null) {
myActions = new DefaultActionGroup();
for (T setting : getAvailableOptions()) {
myActions.add(new MyAction(setting));
}
}
return myActions;
}
@NotNull
protected abstract List<T> getAvailableSettings();
protected abstract List<T> getAvailableOptions();
@NotNull
protected abstract String getText(@NotNull T setting);
protected abstract T getValue();
protected abstract void setValue(@NotNull T option);
@NotNull
protected abstract T getCurrentSetting();
protected abstract void applySetting(@NotNull T setting, @NotNull AnActionEvent e);
protected abstract String getText(@NotNull T option);
private class MyAction extends AnAction implements DumbAware {
@NotNull private final T mySetting;
@NotNull private final T myOption;
public MyAction(@NotNull T setting) {
super(getText(setting));
mySetting = setting;
public MyAction(@NotNull T option) {
super(getText(option));
myOption = option;
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
applySetting(mySetting, e);
setValue(myOption);
}
}
}
public static abstract class HighlightPolicySettingAction extends ComboBoxSettingAction<HighlightPolicy> {
@NotNull protected final TextDiffSettings mySettings;
private static abstract class EnumPolicySettingAction<T extends Enum> extends TextDiffViewerUtil.ComboBoxSettingAction<T> {
@NotNull private final T[] myPolicies;
public HighlightPolicySettingAction(@NotNull TextDiffSettings settings) {
mySettings = settings;
public EnumPolicySettingAction(@NotNull T[] policies) {
assert policies.length > 0;
myPolicies = policies;
}
@Override
protected void applySetting(@NotNull HighlightPolicy setting, @NotNull AnActionEvent e) {
if (getCurrentSetting() == setting) return;
UsageTrigger.trigger("diff.TextDiffSettings.HighlightPolicy." + setting.name());
mySettings.setHighlightPolicy(setting);
update(e);
onSettingsChanged();
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabledAndVisible(myPolicies.length > 1);
}
@NotNull
@Override
protected HighlightPolicy getCurrentSetting() {
protected List<T> getAvailableOptions() {
//noinspection unchecked
return ContainerUtil.sorted(Arrays.asList(myPolicies));
}
@NotNull
@Override
public T getValue() {
T value = getStoredValue();
if (ArrayUtil.contains(value, myPolicies)) return value;
List<T> substitutes = getValueSubstitutes(value);
for (T substitute : substitutes) {
if (ArrayUtil.contains(substitute, myPolicies)) return substitute;
}
return myPolicies[0];
}
@NotNull
protected abstract T getStoredValue();
@NotNull
protected abstract List<T> getValueSubstitutes(@NotNull T value);
}
public static class HighlightPolicySettingAction extends EnumPolicySettingAction<HighlightPolicy> {
@NotNull protected final TextDiffSettings mySettings;
@NotNull private final Runnable myRediffRunnable;
public HighlightPolicySettingAction(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff,
@NotNull HighlightPolicy... policies) {
super(policies);
mySettings = settings;
myRediffRunnable = rediff;
}
@Override
protected void setValue(@NotNull HighlightPolicy option) {
if (getValue() == option) return;
UsageTrigger.trigger("diff.TextDiffSettings.HighlightPolicy." + option.name());
mySettings.setHighlightPolicy(option);
myRediffRunnable.run();
}
@NotNull
@Override
protected HighlightPolicy getStoredValue() {
return mySettings.getHighlightPolicy();
}
@NotNull
@Override
protected String getText(@NotNull HighlightPolicy setting) {
return setting.getText();
protected List<HighlightPolicy> getValueSubstitutes(@NotNull HighlightPolicy value) {
if (value == HighlightPolicy.BY_WORD_SPLIT) {
return list(HighlightPolicy.BY_WORD);
}
if (value == HighlightPolicy.DO_NOT_HIGHLIGHT) {
return list(HighlightPolicy.BY_LINE);
}
return list(HighlightPolicy.BY_WORD);
}
@NotNull
@Override
protected List<HighlightPolicy> getAvailableSettings() {
return Arrays.asList(HighlightPolicy.values());
protected String getText(@NotNull HighlightPolicy option) {
return option.getText();
}
protected abstract void onSettingsChanged();
}
public static abstract class IgnorePolicySettingAction extends ComboBoxSettingAction<IgnorePolicy> {
public static class IgnorePolicySettingAction extends EnumPolicySettingAction<IgnorePolicy> {
@NotNull protected final TextDiffSettings mySettings;
@NotNull private final Runnable myRediffRunnable;
public IgnorePolicySettingAction(@NotNull TextDiffSettings settings) {
public IgnorePolicySettingAction(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff,
@NotNull IgnorePolicy... policies) {
super(policies);
mySettings = settings;
myRediffRunnable = rediff;
}
@Override
protected void applySetting(@NotNull IgnorePolicy setting, @NotNull AnActionEvent e) {
if (getCurrentSetting() == setting) return;
UsageTrigger.trigger("diff.TextDiffSettings.IgnorePolicy." + setting.name());
mySettings.setIgnorePolicy(setting);
update(e);
onSettingsChanged();
protected void setValue(@NotNull IgnorePolicy option) {
if (getValue() == option) return;
UsageTrigger.trigger("diff.TextDiffSettings.IgnorePolicy." + option.name());
mySettings.setIgnorePolicy(option);
myRediffRunnable.run();
}
@NotNull
@Override
protected IgnorePolicy getCurrentSetting() {
protected IgnorePolicy getStoredValue() {
return mySettings.getIgnorePolicy();
}
@NotNull
@Override
protected String getText(@NotNull IgnorePolicy setting) {
return setting.getText();
protected List<IgnorePolicy> getValueSubstitutes(@NotNull IgnorePolicy value) {
if (value == IgnorePolicy.IGNORE_WHITESPACES_CHUNKS) {
return list(IgnorePolicy.IGNORE_WHITESPACES);
}
return list(IgnorePolicy.DEFAULT);
}
@NotNull
@Override
protected List<IgnorePolicy> getAvailableSettings() {
return Arrays.asList(IgnorePolicy.values());
protected String getText(@NotNull IgnorePolicy option) {
return option.getText();
}
protected abstract void onSettingsChanged();
}
public static class ToggleAutoScrollAction extends ToggleActionButton implements DumbAware {
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
import com.intellij.diff.fragments.MergeLineFragment;
import com.intellij.diff.util.MergeConflictType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface FineMergeLineFragment extends MergeLineFragment {
@Nullable
MergeInnerDifferences getInnerFragments();
@NotNull
MergeConflictType getConflictType();
}
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
import com.intellij.diff.fragments.MergeLineFragment;
import com.intellij.diff.fragments.MergeLineFragmentImpl;
import com.intellij.diff.util.MergeConflictType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FineMergeLineFragmentImpl extends MergeLineFragmentImpl implements FineMergeLineFragment {
@NotNull private final MergeConflictType myConflictType;
@Nullable private final MergeInnerDifferences myInnerDifferences;
public FineMergeLineFragmentImpl(@NotNull MergeLineFragment fragment,
@NotNull MergeConflictType conflictType,
@Nullable MergeInnerDifferences innerDifferences) {
super(fragment);
myConflictType = conflictType;
myInnerDifferences = innerDifferences;
}
@NotNull
@Override
public MergeConflictType getConflictType() {
return myConflictType;
}
@Nullable
@Override
public MergeInnerDifferences getInnerFragments() {
return myInnerDifferences;
}
}
@@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
public class MergeInnerDifferences {
public final class MergeInnerDifferences {
@Nullable private final List<TextRange> myLeft;
@Nullable private final List<TextRange> myBase;
@Nullable private final List<TextRange> myRight;
@@ -33,6 +33,9 @@ public class MergeInnerDifferences {
myRight = right;
}
/**
* NB: ranges might overlap and might be not in order
*/
@Nullable
public List<TextRange> get(@NotNull ThreeSide side) {
return side.select(myLeft, myBase, myRight);
@@ -0,0 +1,108 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonPolicy;
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.TextDiffSettings;
import com.intellij.diff.util.DiffUserDataKeysEx;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.intellij.diff.tools.util.base.HighlightPolicy.*;
import static com.intellij.diff.tools.util.base.IgnorePolicy.*;
public class SimpleTextDiffProvider extends TextDiffProviderBase implements TwosideTextDiffProvider {
private static final DiffUserDataKeysEx.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 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 DiffUserDataKeysEx.DiffComputer myDiffComputer;
public SimpleTextDiffProvider(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff) {
this(settings, rediff, DEFAULT_COMPUTER);
}
public SimpleTextDiffProvider(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff,
@NotNull DiffUserDataKeysEx.DiffComputer diffComputer) {
this(settings, rediff, diffComputer, IGNORE_POLICIES, HIGHLIGHT_POLICIES);
}
private SimpleTextDiffProvider(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff,
@NotNull DiffUserDataKeysEx.DiffComputer diffComputer,
@NotNull IgnorePolicy[] ignorePolicies,
@NotNull HighlightPolicy[] highlightPolicies) {
super(settings, rediff, ignorePolicies, highlightPolicies);
myDiffComputer = diffComputer;
}
@Nullable
@Override
public List<LineFragment> compare(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ProgressIndicator indicator) {
IgnorePolicy ignorePolicy = getIgnorePolicy();
HighlightPolicy highlightPolicy = getHighlightPolicy();
if (!highlightPolicy.isShouldCompare()) return null;
ComparisonPolicy policy = ignorePolicy.getComparisonPolicy();
boolean innerFragments = highlightPolicy.isFineFragments();
boolean squashFragments = highlightPolicy.isShouldSquash();
boolean trimFragments = ignorePolicy.isShouldTrimChunks();
indicator.checkCanceled();
List<LineFragment> fragments = myDiffComputer.compute(text1, text2, policy, innerFragments, indicator);
indicator.checkCanceled();
return ComparisonManager.getInstance().processBlocks(fragments, text1, text2,
policy, squashFragments, trimFragments);
}
public static class NoIgnore extends SimpleTextDiffProvider implements TwosideTextDiffProvider.NoIgnore {
public NoIgnore(@NotNull TextDiffSettings settings, @NotNull Runnable rediff) {
this(settings, rediff, DEFAULT_COMPUTER);
}
public NoIgnore(@NotNull TextDiffSettings settings, @NotNull Runnable rediff, @NotNull DiffUserDataKeysEx.DiffComputer diffComputer) {
super(settings, rediff, diffComputer, IGNORE_POLICIES, ArrayUtil.remove(HIGHLIGHT_POLICIES, DO_NOT_HIGHLIGHT));
}
@NotNull
@Override
public List<LineFragment> compare(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ProgressIndicator indicator) {
//noinspection ConstantConditions
return super.compare(text1, text2, indicator);
}
}
}
@@ -0,0 +1,98 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.fragments.MergeLineFragment;
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.MergeConflictType;
import com.intellij.diff.util.ThreeSide;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.diff.tools.util.base.HighlightPolicy.BY_LINE;
import static com.intellij.diff.tools.util.base.HighlightPolicy.BY_WORD;
import static com.intellij.diff.tools.util.base.IgnorePolicy.*;
public class SimpleThreesideTextDiffProvider extends TextDiffProviderBase {
private static final IgnorePolicy[] IGNORE_POLICIES = {DEFAULT, TRIM_WHITESPACES, IGNORE_WHITESPACES};
private static final HighlightPolicy[] HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD};
public SimpleThreesideTextDiffProvider(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff) {
super(settings, rediff, IGNORE_POLICIES, HIGHLIGHT_POLICIES);
}
@NotNull
public List<FineMergeLineFragment> compare(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull CharSequence text3,
@NotNull ProgressIndicator indicator) {
IgnorePolicy ignorePolicy = getIgnorePolicy();
HighlightPolicy highlightPolicy = getHighlightPolicy();
ComparisonPolicy comparisonPolicy = ignorePolicy.getComparisonPolicy();
List<CharSequence> sequences = ContainerUtil.list(text1, text2, text3);
List<LineOffsets> lineOffsets = ContainerUtil.map(sequences, LineOffsets::create);
indicator.checkCanceled();
List<MergeLineFragment> lineFragments = ComparisonManager.getInstance().compareLines(text1, text2, text3, comparisonPolicy, indicator);
indicator.checkCanceled();
List<FineMergeLineFragment> result = new ArrayList<>(lineFragments.size());
for (MergeLineFragment fragment : lineFragments) {
MergeConflictType conflictType = DiffUtil.getLineMergeType(fragment, sequences, lineOffsets, comparisonPolicy);
MergeInnerDifferences innerDifferences;
if (highlightPolicy.isFineFragments()) {
List<CharSequence> chunks = getChunks(fragment, sequences, lineOffsets, conflictType);
innerDifferences = DiffUtil.compareThreesideInner(chunks, comparisonPolicy, indicator);
}
else {
innerDifferences = null;
}
result.add(new FineMergeLineFragmentImpl(fragment, conflictType, innerDifferences));
}
return result;
}
@NotNull
private static List<CharSequence> getChunks(@NotNull MergeLineFragment fragment,
@NotNull List<CharSequence> sequences,
@NotNull List<LineOffsets> lineOffsets,
@NotNull MergeConflictType conflictType) {
return ThreeSide.map(side -> {
if (!conflictType.isChange(side)) return null;
int startLine = fragment.getStartLine(side);
int endLine = fragment.getEndLine(side);
if (startLine == endLine) return null;
return DiffUtil.getLinesContent(side.select(sequences), side.select(lineOffsets), startLine, endLine);
});
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
import com.intellij.openapi.actionSystem.AnAction;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public interface TextDiffProvider {
@NotNull
List<AnAction> getToolbarActions();
@NotNull
List<AnAction> getPopupActions();
}
@@ -0,0 +1,72 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
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.tools.util.base.TextDiffViewerUtil.HighlightPolicySettingAction;
import com.intellij.diff.tools.util.base.TextDiffViewerUtil.IgnorePolicySettingAction;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.Separator;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import static com.intellij.util.containers.ContainerUtil.list;
public class TextDiffProviderBase implements TextDiffProvider {
private final IgnorePolicySettingAction myIgnorePolicySettingAction;
private final HighlightPolicySettingAction myHighlightPolicySettingAction;
public TextDiffProviderBase(@NotNull TextDiffSettings settings,
@NotNull Runnable rediff,
@NotNull IgnorePolicy[] ignorePolicies,
@NotNull HighlightPolicy[] highlightPolicies) {
myIgnorePolicySettingAction = new IgnorePolicySettingAction(settings, rediff, ignorePolicies);
myHighlightPolicySettingAction = new HighlightPolicySettingAction(settings, rediff, highlightPolicies);
}
@NotNull
@Override
public List<AnAction> getToolbarActions() {
return list(myIgnorePolicySettingAction, myHighlightPolicySettingAction);
}
@NotNull
@Override
public List<AnAction> getPopupActions() {
return list(Separator.getInstance(),
myIgnorePolicySettingAction.getActions(),
Separator.getInstance(),
myHighlightPolicySettingAction.getActions(),
Separator.getInstance());
}
@NotNull
public IgnorePolicy getIgnorePolicy() {
return myIgnorePolicySettingAction.getValue();
}
@NotNull
public HighlightPolicy getHighlightPolicy() {
return myHighlightPolicySettingAction.getValue();
}
public boolean isHighlightingDisabled() {
return myHighlightPolicySettingAction.getValue() == HighlightPolicy.DO_NOT_HIGHLIGHT;
}
}
@@ -0,0 +1,43 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.tools.util.text;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface TwosideTextDiffProvider extends TextDiffProvider {
@Nullable
List<LineFragment> compare(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ProgressIndicator indicator);
default boolean isHighlightingDisabled() {
return false;
}
interface NoIgnore extends TwosideTextDiffProvider {
@NotNull
@Override
List<LineFragment> compare(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ProgressIndicator indicator);
}
}
@@ -34,11 +34,12 @@ import com.intellij.diff.fragments.MergeWordFragment;
import com.intellij.diff.impl.DiffSettingsHolder.DiffSettings;
import com.intellij.diff.requests.ContentDiffRequest;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.tools.util.text.MergeInnerDifferences;
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.tools.util.base.TextDiffViewerUtil;
import com.intellij.diff.tools.util.text.LineOffsets;
import com.intellij.diff.tools.util.text.MergeInnerDifferences;
import com.intellij.diff.tools.util.text.SimpleTextDiffProvider;
import com.intellij.diff.tools.util.text.TwosideTextDiffProvider;
import com.intellij.icons.AllIcons;
import com.intellij.lang.Language;
import com.intellij.openapi.Disposable;
@@ -599,31 +600,25 @@ public class DiffUtil {
//
@NotNull
public static List<LineFragment> compare(@NotNull DiffRequest request,
@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull DiffConfig config,
@NotNull ProgressIndicator indicator) {
indicator.checkCanceled();
public static TwosideTextDiffProvider createTextDiffProvider(@NotNull ContentDiffRequest request,
@NotNull TextDiffSettings settings,
@NotNull Runnable rediff) {
DiffUserDataKeysEx.DiffComputer diffComputer = request.getUserData(DiffUserDataKeysEx.CUSTOM_DIFF_COMPUTER);
List<LineFragment> fragments;
if (diffComputer != null) {
fragments = diffComputer.compute(text1, text2, config.policy, config.innerFragments, indicator);
}
else {
if (config.innerFragments) {
fragments = ComparisonManager.getInstance().compareLinesInner(text1, text2, config.policy, indicator);
}
else {
fragments = ComparisonManager.getInstance().compareLines(text1, text2, config.policy, indicator);
}
return new SimpleTextDiffProvider(settings, rediff, diffComputer);
}
return new SimpleTextDiffProvider(settings, rediff);
}
indicator.checkCanceled();
return ComparisonManager.getInstance().processBlocks(fragments, text1, text2,
config.policy, config.squashFragments, config.trimFragments);
@NotNull
public static TwosideTextDiffProvider.NoIgnore createNoIgnoreTextDiffProvider(@NotNull ContentDiffRequest request,
@NotNull TextDiffSettings settings,
@NotNull Runnable rediff) {
DiffUserDataKeysEx.DiffComputer diffComputer = request.getUserData(DiffUserDataKeysEx.CUSTOM_DIFF_COMPUTER);
if (diffComputer != null) {
return new SimpleTextDiffProvider.NoIgnore(settings, rediff, diffComputer);
}
return new SimpleTextDiffProvider.NoIgnore(settings, rediff);
}
@Nullable
@@ -1392,24 +1387,6 @@ public class DiffUtil {
// Helpers
//
public static class DiffConfig {
@NotNull public final ComparisonPolicy policy;
public final boolean innerFragments;
public final boolean squashFragments;
public final boolean trimFragments;
public DiffConfig(@NotNull ComparisonPolicy policy, boolean innerFragments, boolean squashFragments, boolean trimFragments) {
this.policy = policy;
this.innerFragments = innerFragments;
this.squashFragments = squashFragments;
this.trimFragments = trimFragments;
}
public DiffConfig(@NotNull IgnorePolicy ignorePolicy, @NotNull HighlightPolicy highlightPolicy) {
this(ignorePolicy.getComparisonPolicy(), highlightPolicy.isFineFragments(), highlightPolicy.isShouldSquash(),
ignorePolicy.isShouldTrimChunks());
}
}
private static class SyncHeightComponent extends JPanel {
@NotNull private final List<JComponent> myComponents;