From 013744871fe8626a987f9f17b7f24ff0474ffa35 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 5 Aug 2019 20:22:02 +0300 Subject: [PATCH] IDEA-204040 diff: support changelists and excluded changes in unified viewer - introduce tool for local changelists GitOrigin-RevId: cd1ae2d5dbaaf3b8642d2b6cc3f57af6f73331c3 --- .../tools/fragmented/UnifiedDiffChange.java | 22 +++ .../tools/fragmented/UnifiedDiffChangeUi.java | 4 + .../tools/fragmented/UnifiedDiffViewer.java | 41 +++--- .../fragmented/UnifiedFragmentBuilder.java | 40 +++--- .../com/intellij/diff/util/DiffDrawUtil.java | 30 +++- .../src/META-INF/VcsExtensions.xml | 3 +- .../diff/lst/LocalChangeListDiffTool.java | 70 ++++++--- .../actions/diff/lst/LocalTrackerDiffUtil.kt | 49 ++++++- .../lst/SimpleLocalChangeListDiffViewer.java | 51 +------ .../lst/UnifiedLocalChangeListDiffViewer.java | 135 ++++++++++++++++++ 10 files changed, 334 insertions(+), 111 deletions(-) create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/UnifiedLocalChangeListDiffViewer.java diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java index f0b38e8c21ce..e5dd5d236d49 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java @@ -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; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChangeUi.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChangeUi.java index ef9ca6ad9c1a..097355d8f359 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChangeUi.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChangeUi.java @@ -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())); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java index c30c783621bb..93c7ec2e119d 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java @@ -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 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 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); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilder.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilder.java index 6b1ecf107a23..1e290276b7b6 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilder.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilder.java @@ -25,8 +25,8 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -class UnifiedFragmentBuilder { - @NotNull private final List myFragments; +public class UnifiedFragmentBuilder { + @NotNull protected final List 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 myChangedLines = new ArrayList<>(); - UnifiedFragmentBuilder(@NotNull List fragments, + public UnifiedFragmentBuilder(@NotNull List 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; diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java index c526e1626f2f..8b3df6911cd8 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java @@ -299,21 +299,31 @@ public class DiffDrawUtil { @NotNull LineRange deleted, @NotNull LineRange inserted, @Nullable List innerFragments) { + return createUnifiedChunkHighlighters(editor, deleted, inserted, false, false, innerFragments); + } + + @NotNull + public static List createUnifiedChunkHighlighters(@NotNull Editor editor, + @NotNull LineRange deleted, + @NotNull LineRange inserted, + boolean excluded, + boolean skipped, + @Nullable List innerFragments) { boolean ignored = innerFragments != null; List 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 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 createHighlighter(@NotNull Editor editor, int startLine, int endLine, @NotNull TextDiffType type, boolean ignored) { diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index 302503655d41..ba4ec901d0e9 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -45,7 +45,8 @@ - + + diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalChangeListDiffTool.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalChangeListDiffTool.java index f4a1dd5c3df1..dabfd383dddb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalChangeListDiffTool.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalChangeListDiffTool.java @@ -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 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; + } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalTrackerDiffUtil.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalTrackerDiffUtil.kt index 258932a1208d..4493733a1cab 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalTrackerDiffUtil.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/LocalTrackerDiffUtil.kt @@ -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, fragments: List, fragmentsData: List): 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() + } + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java index e00c54f1ece2..db927a47e249 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java @@ -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 fragments, @NotNull List fragmentsData) { List 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); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/UnifiedLocalChangeListDiffViewer.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/UnifiedLocalChangeListDiffViewer.java new file mode 100644 index 000000000000..906cd12bd042 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/UnifiedLocalChangeListDiffViewer.java @@ -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 fragments, + @NotNull List 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 myFragmentsData; + + MyUnifiedFragmentBuilder(@NotNull List fragments, + @NotNull List 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); + } + } +}