IDEA-204040 diff: support changelists and excluded changes in unified viewer - introduce tool for local changelists

GitOrigin-RevId: cd1ae2d5dbaaf3b8642d2b6cc3f57af6f73331c3
This commit is contained in:
Aleksey Pivovarov
2019-08-12 18:05:04 +03:00
committed by intellij-monorepo-bot
parent 02880c9336
commit 013744871f
10 changed files with 334 additions and 111 deletions
@@ -30,15 +30,29 @@ public class UnifiedDiffChange {
@NotNull private final LineRange myInsertedRange;
@NotNull private final LineFragment myLineFragment;
private final boolean myIsExcluded;
private final boolean myIsSkipped;
public UnifiedDiffChange(int blockStart,
int insertedStart,
int blockEnd,
@NotNull LineFragment lineFragment) {
this(blockStart, insertedStart, blockEnd, lineFragment, false, false);
}
public UnifiedDiffChange(int blockStart,
int insertedStart,
int blockEnd,
@NotNull LineFragment lineFragment,
boolean isExcluded,
boolean isSkipped) {
myLine1 = blockStart;
myLine2 = blockEnd;
myDeletedRange = new LineRange(blockStart, insertedStart);
myInsertedRange = new LineRange(insertedStart, blockEnd);
myLineFragment = lineFragment;
myIsExcluded = isExcluded;
myIsSkipped = isSkipped;
}
public int getLine1() {
@@ -67,6 +81,14 @@ public class UnifiedDiffChange {
return myInsertedRange;
}
public boolean isExcluded() {
return myIsExcluded;
}
public boolean isSkipped() {
return myIsSkipped;
}
public void processChange(int oldLine1, int oldLine2, int shift) {
UpdatedLineRange newRange = DiffUtil.updateRangeOnModification(myLine1, myLine2, oldLine1, oldLine2, shift);
myLine1 = newRange.startLine;
@@ -54,6 +54,8 @@ public class UnifiedDiffChangeUi {
}
private void doInstallActionHighlighters() {
if (myChange.isSkipped()) return;
boolean leftEditable = myViewer.isEditable(Side.LEFT, false);
boolean rightEditable = myViewer.isEditable(Side.RIGHT, false);
@@ -70,6 +72,8 @@ public class UnifiedDiffChangeUi {
myHighlighters.addAll(DiffDrawUtil.createUnifiedChunkHighlighters(myEditor,
myChange.getDeletedRange(),
myChange.getInsertedRange(),
myChange.isExcluded(),
myChange.isSkipped(),
myChange.getLineFragment().getInnerFragments()));
}
@@ -27,7 +27,6 @@ import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diff.DiffBundle;
import com.intellij.openapi.diff.LineTokenizer;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
@@ -45,7 +44,6 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.Navigatable;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TIntFunction;
import org.jetbrains.annotations.*;
@@ -67,7 +65,7 @@ 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 final TwosideTextDiffProvider.NoIgnore myTextDiffProvider;
@NotNull protected Side myMasterSide = Side.RIGHT;
@@ -253,15 +251,20 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
}
catch (Throwable e) {
LOG.error(e);
return () -> {
clearDiffPresentation();
myPanel.setErrorContent();
};
return applyErrorNotification();
}
}
@NotNull
private Runnable computeDifferences(@NotNull ProgressIndicator indicator) {
protected Runnable applyErrorNotification() {
return () -> {
clearDiffPresentation();
myPanel.setErrorContent();
};
}
@NotNull
protected Runnable computeDifferences(@NotNull ProgressIndicator indicator) {
final Document document1 = getContent1().getDocument();
final Document document2 = getContent2().getDocument();
@@ -320,9 +323,9 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
}
@NotNull
private Runnable apply(@NotNull UnifiedFragmentBuilder builder,
@NotNull CharSequence[] texts,
@NotNull ProgressIndicator indicator) {
protected Runnable apply(@NotNull UnifiedFragmentBuilder builder,
@NotNull CharSequence[] texts,
@NotNull ProgressIndicator indicator) {
final DocumentContent content1 = getContent1();
final DocumentContent content2 = getContent2();
@@ -823,7 +826,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
@NotNull
@Override
protected JComponent getStatusPanel() {
protected StatusPanel getStatusPanel() {
return myStatusPanel;
}
@@ -1026,13 +1029,12 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
@Override
protected String getMessage() {
ChangedBlockData blockData = myModel.getData();
if (blockData == null) return null;
int changesCount = blockData.getDiffChanges().size();
if (changesCount == 0 && myModel.isContentsEqual() == ThreeState.NO) {
return DiffBundle.message("diff.all.differences.ignored.text");
}
return DiffBundle.message("diff.count.differences.status.text", changesCount);
List<UnifiedDiffChange> allChanges = blockData.getDiffChanges();
return DiffUtil.getStatusText(allChanges.size(),
ContainerUtil.count(allChanges, it -> it.isExcluded()),
myModel.isContentsEqual());
}
}
@@ -1104,7 +1106,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
List<UnifiedDiffChange> changes = myModel.getDiffChanges();
if (changes == null) return false;
UnifiedDiffChange targetChange = scrollToChangePolicy.select(changes);
UnifiedDiffChange targetChange = scrollToChangePolicy.select(ContainerUtil.filter(changes, it -> !it.isSkipped()));
if (targetChange == null) targetChange = scrollToChangePolicy.select(changes);
if (targetChange == null) return false;
DiffUtil.scrollEditor(myEditor, targetChange.getLine1(), false);
@@ -25,8 +25,8 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
class UnifiedFragmentBuilder {
@NotNull private final List<? extends LineFragment> myFragments;
public class UnifiedFragmentBuilder {
@NotNull protected final List<? extends LineFragment> myFragments;
@NotNull private final Document myDocument1;
@NotNull private final Document myDocument2;
@NotNull private final Side myMasterSide;
@@ -38,7 +38,7 @@ class UnifiedFragmentBuilder {
@NotNull private final LineNumberConvertor.Builder myConvertor2 = new LineNumberConvertor.Builder();
@NotNull private final List<LineRange> myChangedLines = new ArrayList<>();
UnifiedFragmentBuilder(@NotNull List<? extends LineFragment> fragments,
public UnifiedFragmentBuilder(@NotNull List<? extends LineFragment> fragments,
@NotNull Document document1,
@NotNull Document document2,
@NotNull Side masterSide) {
@@ -63,9 +63,10 @@ class UnifiedFragmentBuilder {
return this;
}
for (LineFragment fragment : myFragments) {
for (int i = 0; i < myFragments.size(); i++) {
LineFragment fragment = myFragments.get(i);
processEquals(fragment.getStartLine1() - 1, fragment.getStartLine2() - 1);
processChanged(fragment);
processChanged(fragment, i);
}
processEquals(getLineCount(myDocument1) - 1, getLineCount(myDocument2) - 1);
@@ -79,8 +80,7 @@ class UnifiedFragmentBuilder {
appendTextMaster(startLine1, startLine2, endLine1, endLine2);
}
@SuppressWarnings("UnnecessaryLocalVariable")
private void processChanged(@NotNull LineFragment fragment) {
private void processChanged(@NotNull LineFragment fragment, int fragmentIndex) {
int startLine1 = fragment.getStartLine1();
int endLine1 = fragment.getEndLine1() - 1;
int lines1 = endLine1 - startLine1;
@@ -95,7 +95,7 @@ class UnifiedFragmentBuilder {
if (lines1 >= 0) {
int startOffset1 = myDocument1.getLineStartOffset(startLine1);
int endOffset1 = myDocument1.getLineEndOffset(endLine1);
appendTextSide(Side.LEFT, startOffset1, endOffset1, lines1, lines2, startLine1, -1);
appendText(Side.LEFT, startOffset1, endOffset1, lines1, lines2, startLine1, -1);
}
int linesBetween = totalLines;
@@ -103,17 +103,29 @@ class UnifiedFragmentBuilder {
if (lines2 >= 0) {
int startOffset2 = myDocument2.getLineStartOffset(startLine2);
int endOffset2 = myDocument2.getLineEndOffset(endLine2);
appendTextSide(Side.RIGHT, startOffset2, endOffset2, lines2, lines2, -1, startLine2);
appendText(Side.RIGHT, startOffset2, endOffset2, lines2, lines2, -1, startLine2);
}
linesAfter = totalLines;
myChanges.add(new UnifiedDiffChange(linesBefore, linesBetween, linesAfter, fragment));
UnifiedDiffChange change = createDiffChange(linesBefore, linesBetween, linesAfter, fragmentIndex);
myChanges.add(change);
if (!change.isSkipped()) {
myChangedLines.add(new LineRange(linesBefore, linesAfter));
}
lastProcessedLine1 = endLine1;
lastProcessedLine2 = endLine2;
}
@NotNull
protected UnifiedDiffChange createDiffChange(int blockStart,
int insertedStart,
int blockEnd,
int fragmentIndex) {
return new UnifiedDiffChange(blockStart, insertedStart, blockEnd, myFragments.get(fragmentIndex));
}
private void appendTextMaster(int startLine1, int startLine2, int endLine1, int endLine2) {
// The slave-side line matching might be incomplete for non-fair line fragments (@see FairDiffIterable)
// If it ever became an issue, it could be fixed by explicit fair by-line comparing of "equal" regions
@@ -128,14 +140,6 @@ class UnifiedFragmentBuilder {
}
}
private void appendTextSide(@NotNull Side side, int offset1, int offset2, int lines1, int lines2, int startLine1, int startLine2) {
int linesBefore = totalLines;
appendText(side, offset1, offset2, lines1, lines2, startLine1, startLine2);
int linesAfter = totalLines;
if (linesBefore != linesAfter) myChangedLines.add(new LineRange(linesBefore, linesAfter));
}
private void appendText(@NotNull Side side, int offset1, int offset2, int lines1, int lines2, int startLine1, int startLine2) {
int lines = side.select(lines1, lines2);
boolean notEmpty = lines >= 0;
@@ -299,21 +299,31 @@ public class DiffDrawUtil {
@NotNull LineRange deleted,
@NotNull LineRange inserted,
@Nullable List<? extends DiffFragment> innerFragments) {
return createUnifiedChunkHighlighters(editor, deleted, inserted, false, false, innerFragments);
}
@NotNull
public static List<RangeHighlighter> createUnifiedChunkHighlighters(@NotNull Editor editor,
@NotNull LineRange deleted,
@NotNull LineRange inserted,
boolean excluded,
boolean skipped,
@Nullable List<? extends DiffFragment> innerFragments) {
boolean ignored = innerFragments != null;
List<RangeHighlighter> list = new ArrayList<>();
if (!inserted.isEmpty() && !deleted.isEmpty()) {
list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored));
list.addAll(createHighlighter(editor, inserted.start, inserted.end, TextDiffType.INSERTED, ignored));
list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored, skipped, excluded));
list.addAll(createHighlighter(editor, inserted.start, inserted.end, TextDiffType.INSERTED, ignored, skipped, excluded));
}
else if (!inserted.isEmpty()) {
list.addAll(createHighlighter(editor, inserted.start, inserted.end, TextDiffType.INSERTED, ignored));
list.addAll(createHighlighter(editor, inserted.start, inserted.end, TextDiffType.INSERTED, ignored, skipped, excluded));
}
else if (!deleted.isEmpty()) {
list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored));
list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored, skipped, excluded));
}
if (innerFragments != null) {
if (innerFragments != null && !skipped) {
int deletedStartOffset = editor.getDocument().getLineStartOffset(deleted.start);
int insertedStartOffset = editor.getDocument().getLineStartOffset(inserted.start);
@@ -331,6 +341,16 @@ public class DiffDrawUtil {
return list;
}
@NotNull
private static List<RangeHighlighter> createHighlighter(@NotNull Editor editor, int startLine, int endLine, @NotNull TextDiffType type,
boolean ignored, boolean excludedInEditor, boolean excludedInGutter) {
return new LineHighlighterBuilder(editor, startLine, endLine, type)
.withIgnored(ignored)
.withExcludedInEditor(excludedInEditor)
.withExcludedInGutter(excludedInGutter)
.done();
}
@NotNull
public static List<RangeHighlighter> createHighlighter(@NotNull Editor editor, int startLine, int endLine, @NotNull TextDiffType type,
boolean ignored) {
@@ -45,7 +45,8 @@
<diff.merge.MergeTool implementation="com.intellij.openapi.vcs.changes.patch.tool.ApplyPatchMergeTool"/>
<diff.DiffTool implementation="com.intellij.openapi.vcs.changes.patch.tool.ApplyPatchDiffTool"/>
<diff.DiffTool implementation="com.intellij.openapi.vcs.changes.patch.tool.PatchDiffTool"/>
<diff.impl.DiffToolSubstitutor implementation="com.intellij.openapi.vcs.changes.actions.diff.lst.LocalChangeListDiffTool"/>
<diff.impl.DiffToolSubstitutor implementation="com.intellij.openapi.vcs.changes.actions.diff.lst.LocalChangeListDiffTool$Simple"/>
<diff.impl.DiffToolSubstitutor implementation="com.intellij.openapi.vcs.changes.actions.diff.lst.LocalChangeListDiffTool$Unified"/>
<diff.actions.ShowDiffAction.ExtensionProvider implementation="com.intellij.openapi.vcs.changes.shelf.DiffShelvedChangesActionProvider"/>
<diff.actions.ShowDiffAction.ExtensionProvider implementation="com.intellij.openapi.vcs.update.ShowUpdatedDiffActionProvider"/>
@@ -6,40 +6,66 @@ import com.intellij.diff.DiffTool;
import com.intellij.diff.FrameDiffTool;
import com.intellij.diff.impl.DiffToolSubstitutor;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.tools.fragmented.UnifiedDiffTool;
import com.intellij.diff.tools.simple.SimpleDiffTool;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class LocalChangeListDiffTool implements FrameDiffTool, DiffToolSubstitutor {
public class LocalChangeListDiffTool {
public static final Key<Boolean> ALLOW_EXCLUDE_FROM_COMMIT = Key.create("Diff.LocalChangeListDiffTool.ALLOW_EXCLUDE_FROM_COMMIT");
@NotNull
@Override
public DiffViewer createComponent(@NotNull DiffContext context, @NotNull DiffRequest request) {
LocalChangeListDiffRequest localRequest = (LocalChangeListDiffRequest)request;
return new SimpleLocalChangeListDiffViewer(context, localRequest);
public static class Simple extends Base {
public Simple() {
super(SimpleDiffTool.INSTANCE);
}
@NotNull
@Override
public DiffViewer createComponent(@NotNull DiffContext context, @NotNull DiffRequest request) {
return new SimpleLocalChangeListDiffViewer(context, (LocalChangeListDiffRequest)request);
}
}
@Override
public boolean canShow(@NotNull DiffContext context, @NotNull DiffRequest request) {
if (!(request instanceof LocalChangeListDiffRequest)) return false;
LocalChangeListDiffRequest localRequest = (LocalChangeListDiffRequest)request;
return localRequest.getLineStatusTracker() instanceof PartialLocalLineStatusTracker;
public static class Unified extends Base {
public Unified() {
super(UnifiedDiffTool.INSTANCE);
}
@NotNull
@Override
public DiffViewer createComponent(@NotNull DiffContext context, @NotNull DiffRequest request) {
return new UnifiedLocalChangeListDiffViewer(context, (LocalChangeListDiffRequest)request);
}
}
@NotNull
@Override
public String getName() {
return SimpleDiffTool.INSTANCE.getName();
}
private static abstract class Base implements FrameDiffTool, DiffToolSubstitutor {
@NotNull private final FrameDiffTool myReplacement;
@Nullable
@Override
public DiffTool getReplacement(@NotNull DiffTool tool, @NotNull DiffContext context, @NotNull DiffRequest request) {
if (tool != SimpleDiffTool.INSTANCE) return null;
if (!canShow(context, request)) return null;
return this;
protected Base(@NotNull FrameDiffTool replacement) {
myReplacement = replacement;
}
@Override
public boolean canShow(@NotNull DiffContext context, @NotNull DiffRequest request) {
if (!(request instanceof LocalChangeListDiffRequest)) return false;
LocalChangeListDiffRequest localRequest = (LocalChangeListDiffRequest)request;
return localRequest.getLineStatusTracker() instanceof PartialLocalLineStatusTracker;
}
@NotNull
@Override
public String getName() {
return myReplacement.getName();
}
@Nullable
@Override
public DiffTool getReplacement(@NotNull DiffTool tool, @NotNull DiffContext context, @NotNull DiffRequest request) {
if (tool != myReplacement) return null;
if (!canShow(context, request)) return null;
return this;
}
}
}
@@ -2,6 +2,7 @@
package com.intellij.openapi.vcs.changes.actions.diff.lst
import com.intellij.diff.fragments.LineFragment
import com.intellij.diff.tools.util.base.DiffViewerBase
import com.intellij.diff.tools.util.text.TwosideTextDiffProvider
import com.intellij.diff.util.Range
import com.intellij.openapi.application.runReadAction
@@ -12,6 +13,7 @@ import com.intellij.openapi.vcs.ex.LineStatusTracker
import com.intellij.openapi.vcs.ex.LocalRange
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker
import com.intellij.openapi.vcs.ex.SimpleLocalLineStatusTracker
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager
object LocalTrackerDiffUtil {
@JvmStatic
@@ -72,13 +74,14 @@ object LocalTrackerDiffUtil {
val ranges = diffData.ranges
val isContentsEqual = ranges.isEmpty()
val texts = arrayOf(diffData.vcsText, diffData.localText)
if (!StringUtil.equals(diffData.vcsText, diffData.trackerVcsText)) {
return handler.error() // DiffRequest is out of date
}
if (textDiffProvider.isHighlightingDisabled) {
return handler.done(isContentsEqual, emptyList(), emptyList())
return handler.done(isContentsEqual, texts, emptyList(), emptyList())
}
@@ -99,11 +102,12 @@ object LocalTrackerDiffUtil {
repeat(rangeFragments.size) { fragmentsData.add(fragmentData) }
}
return handler.done(isContentsEqual, fragments, fragmentsData)
return handler.done(isContentsEqual, texts, fragments, fragmentsData)
}
interface LocalTrackerDiffHandler {
fun done(isContentsEqual: Boolean,
texts: Array<CharSequence>,
fragments: List<LineFragment>,
fragmentsData: List<LineFragmentData>): Runnable
@@ -130,4 +134,45 @@ object LocalTrackerDiffUtil {
val localText: CharSequence,
val vcsText: CharSequence,
val trackerVcsText: CharSequence)
@JvmStatic
fun installTrackerListener(viewer: DiffViewerBase, localRequest: LocalChangeListDiffRequest) {
val trackerListener = MyTrackerListener(viewer)
val lstmListener = MyLineStatusTrackerManagerListener(viewer, localRequest, trackerListener)
LineStatusTrackerManager.getInstanceImpl(localRequest.project).addTrackerListener(lstmListener, viewer)
val tracker = localRequest.lineStatusTracker as? PartialLocalLineStatusTracker
if (tracker != null) tracker.addListener(trackerListener, viewer)
}
private class MyTrackerListener(private val viewer: DiffViewerBase)
: PartialLocalLineStatusTracker.ListenerAdapter() {
override fun onBecomingValid(tracker: PartialLocalLineStatusTracker) {
viewer.scheduleRediff()
}
override fun onChangeListMarkerChange(tracker: PartialLocalLineStatusTracker) {
viewer.scheduleRediff()
}
override fun onExcludedFromCommitChange(tracker: PartialLocalLineStatusTracker) {
viewer.scheduleRediff()
}
}
private class MyLineStatusTrackerManagerListener(private val viewer: DiffViewerBase,
private val localRequest: LocalChangeListDiffRequest,
private val trackerListener: PartialLocalLineStatusTracker.Listener)
: LineStatusTrackerManager.ListenerAdapter() {
override fun onTrackerAdded(tracker: LineStatusTracker<*>) {
if (tracker is PartialLocalLineStatusTracker && tracker.virtualFile == localRequest.virtualFile) {
tracker.addListener(trackerListener, viewer)
viewer.scheduleRediff()
}
}
}
}
@@ -29,8 +29,10 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.ex.*;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
import com.intellij.openapi.vcs.ex.ExclusionState;
import com.intellij.openapi.vcs.ex.LocalRange;
import com.intellij.openapi.vcs.ex.MoveChangesLineStatusAction;
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker;
import com.intellij.ui.InplaceButton;
import com.intellij.ui.scale.JBUIScale;
import com.intellij.util.ObjectUtils;
@@ -63,15 +65,9 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer {
myChangelistId = localRequest.getChangelistId();
myChangelistName = localRequest.getChangelistName();
MyTrackerListener trackerListener = new MyTrackerListener();
MyLineStatusTrackerManagerListener lstmListener = new MyLineStatusTrackerManagerListener(trackerListener);
myAllowExcludeChangesFromCommit = DiffUtil.isUserDataFlagSet(LocalChangeListDiffTool.ALLOW_EXCLUDE_FROM_COMMIT, context);
LineStatusTrackerManager.getInstanceImpl(getProject()).addTrackerListener(lstmListener, this);
PartialLocalLineStatusTracker tracker = getPartialTracker();
if (tracker != null) tracker.addListener(trackerListener, this);
myAllowExcludeChangesFromCommit = Boolean.TRUE.equals(context.getUserData(LocalChangeListDiffTool.ALLOW_EXCLUDE_FROM_COMMIT));
LocalTrackerDiffUtil.installTrackerListener(this, myLocalRequest);
}
@NotNull
@@ -146,6 +142,7 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer {
@NotNull
@Override
public Runnable done(boolean isContentsEqual,
@NotNull CharSequence[] texts,
@NotNull List<? extends LineFragment> fragments,
@NotNull List<LocalTrackerDiffUtil.LineFragmentData> fragmentsData) {
List<SimpleDiffChange> changes = new ArrayList<>();
@@ -289,40 +286,6 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer {
}
private class MyTrackerListener extends PartialLocalLineStatusTracker.ListenerAdapter {
@Override
public void onBecomingValid(@NotNull PartialLocalLineStatusTracker tracker) {
scheduleRediff();
}
@Override
public void onChangeListMarkerChange(@NotNull PartialLocalLineStatusTracker tracker) {
scheduleRediff();
}
@Override
public void onExcludedFromCommitChange(@NotNull PartialLocalLineStatusTracker tracker) {
scheduleRediff();
}
}
private class MyLineStatusTrackerManagerListener extends LineStatusTrackerManager.ListenerAdapter {
@NotNull private final PartialLocalLineStatusTracker.Listener myListener;
MyLineStatusTrackerManagerListener(@NotNull PartialLocalLineStatusTracker.Listener trackerListener) {
myListener = trackerListener;
}
@Override
public void onTrackerAdded(@NotNull LineStatusTracker<?> tracker) {
if (tracker instanceof PartialLocalLineStatusTracker &&
tracker.getVirtualFile().equals(myLocalRequest.getVirtualFile())) {
((PartialLocalLineStatusTracker)tracker).addListener(myListener, SimpleLocalChangeListDiffViewer.this);
scheduleRediff();
}
}
}
private class MoveSelectedChangesToAnotherChangelistAction extends MySelectedChangesActionBase {
MoveSelectedChangesToAnotherChangelistAction() {
super(false);
@@ -0,0 +1,135 @@
// Copyright 2000-2019 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.openapi.vcs.changes.actions.diff.lst;
import com.intellij.diff.DiffContext;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.tools.fragmented.UnifiedDiffChange;
import com.intellij.diff.tools.fragmented.UnifiedDiffViewer;
import com.intellij.diff.tools.fragmented.UnifiedFragmentBuilder;
import com.intellij.diff.util.DiffUtil;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class UnifiedLocalChangeListDiffViewer extends UnifiedDiffViewer {
@NotNull private final LocalChangeListDiffRequest myLocalRequest;
private final boolean myAllowExcludeChangesFromCommit;
public UnifiedLocalChangeListDiffViewer(@NotNull DiffContext context,
@NotNull LocalChangeListDiffRequest localRequest) {
super(context, localRequest.getRequest());
myLocalRequest = localRequest;
myAllowExcludeChangesFromCommit = DiffUtil.isUserDataFlagSet(LocalChangeListDiffTool.ALLOW_EXCLUDE_FROM_COMMIT, context);
LocalTrackerDiffUtil.installTrackerListener(this, myLocalRequest);
}
@NotNull
private Runnable superComputeDifferences(@NotNull ProgressIndicator indicator) {
return super.computeDifferences(indicator);
}
@NotNull
@Override
protected Runnable computeDifferences(@NotNull ProgressIndicator indicator) {
Document document1 = getContent1().getDocument();
Document document2 = getContent2().getDocument();
return LocalTrackerDiffUtil.computeDifferences(
myLocalRequest.getLineStatusTracker(),
document1,
document2,
myLocalRequest.getChangelistId(),
myTextDiffProvider,
indicator,
new MyLocalTrackerDiffHandler(document1, document2, indicator));
}
private class MyLocalTrackerDiffHandler implements LocalTrackerDiffUtil.LocalTrackerDiffHandler {
@NotNull private final Document myDocument1;
@NotNull private final Document myDocument2;
@NotNull private final ProgressIndicator myIndicator;
private MyLocalTrackerDiffHandler(@NotNull Document document1,
@NotNull Document document2,
@NotNull ProgressIndicator indicator) {
myDocument1 = document1;
myDocument2 = document2;
myIndicator = indicator;
}
@NotNull
@Override
public Runnable done(boolean isContentsEqual,
@NotNull CharSequence[] texts,
@NotNull List<? extends LineFragment> fragments,
@NotNull List<LocalTrackerDiffUtil.LineFragmentData> fragmentsData) {
UnifiedFragmentBuilder builder = ReadAction.compute(() -> {
myIndicator.checkCanceled();
return new MyUnifiedFragmentBuilder(fragments, fragmentsData, myDocument1, myDocument2).exec();
});
return apply(builder, texts, myIndicator);
}
@NotNull
@Override
public Runnable retryLater() {
scheduleRediff();
throw new ProcessCanceledException();
}
@NotNull
@Override
public Runnable fallback() {
return superComputeDifferences(myIndicator);
}
@NotNull
@Override
public Runnable fallbackWithProgress() {
Runnable callback = superComputeDifferences(myIndicator);
return () -> {
callback.run();
getStatusPanel().setBusy(true);
};
}
@NotNull
@Override
public Runnable error() {
return applyErrorNotification();
}
}
private class MyUnifiedFragmentBuilder extends UnifiedFragmentBuilder {
@NotNull private final List<LocalTrackerDiffUtil.LineFragmentData> myFragmentsData;
MyUnifiedFragmentBuilder(@NotNull List<? extends LineFragment> fragments,
@NotNull List<LocalTrackerDiffUtil.LineFragmentData> fragmentsData,
@NotNull Document document1,
@NotNull Document document2) {
super(fragments, document1, document2, myMasterSide);
myFragmentsData = fragmentsData;
}
@NotNull
@Override
protected UnifiedDiffChange createDiffChange(int blockStart,
int insertedStart,
int blockEnd,
int fragmentIndex) {
LineFragment fragment = myFragments.get(fragmentIndex);
LocalTrackerDiffUtil.LineFragmentData data = myFragmentsData.get(fragmentIndex);
boolean isSkipped = data.isSkipped();
boolean isExcluded = data.isExcluded(myAllowExcludeChangesFromCommit);
return new UnifiedDiffChange(blockStart, insertedStart, blockEnd, fragment, isExcluded, isSkipped);
}
}
}