mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
diff: extract LST-managed diff computation logic
GitOrigin-RevId: e4b2003e7bf7cbbd7c919e1dfff5a93b2d3331c0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
72458eea71
commit
55b8eada71
@@ -185,28 +185,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
|
||||
@NotNull
|
||||
protected Runnable performRediff(@NotNull final ProgressIndicator indicator) {
|
||||
try {
|
||||
indicator.checkCanceled();
|
||||
|
||||
final Document document1 = getContent1().getDocument();
|
||||
final Document document2 = getContent2().getDocument();
|
||||
|
||||
CharSequence[] texts = ReadAction.compute(() -> new CharSequence[]{document1.getImmutableCharSequence(), document2.getImmutableCharSequence()});
|
||||
|
||||
List<LineFragment> lineFragments = myTextDiffProvider.compare(texts[0], texts[1], indicator);
|
||||
|
||||
boolean isContentsEqual = (lineFragments == null || lineFragments.isEmpty()) &&
|
||||
StringUtil.equals(texts[0], texts[1]);
|
||||
|
||||
if (lineFragments == null) {
|
||||
return apply(null, isContentsEqual);
|
||||
}
|
||||
else {
|
||||
List<SimpleDiffChange> changes = new ArrayList<>();
|
||||
for (LineFragment fragment : lineFragments) {
|
||||
changes.add(new SimpleDiffChange(changes.size(), fragment));
|
||||
}
|
||||
return apply(changes, isContentsEqual);
|
||||
}
|
||||
return computeDifferences(indicator);
|
||||
}
|
||||
catch (DiffTooBigException e) {
|
||||
return applyNotification(DiffNotifications.createDiffTooBig());
|
||||
@@ -220,6 +199,33 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Runnable computeDifferences(@NotNull ProgressIndicator indicator) {
|
||||
indicator.checkCanceled();
|
||||
|
||||
final Document document1 = getContent1().getDocument();
|
||||
final Document document2 = getContent2().getDocument();
|
||||
|
||||
CharSequence[] texts =
|
||||
ReadAction.compute(() -> new CharSequence[]{document1.getImmutableCharSequence(), document2.getImmutableCharSequence()});
|
||||
|
||||
List<LineFragment> lineFragments = myTextDiffProvider.compare(texts[0], texts[1], indicator);
|
||||
|
||||
boolean isContentsEqual = (lineFragments == null || lineFragments.isEmpty()) &&
|
||||
StringUtil.equals(texts[0], texts[1]);
|
||||
|
||||
if (lineFragments == null) {
|
||||
return apply(null, isContentsEqual);
|
||||
}
|
||||
else {
|
||||
List<SimpleDiffChange> changes = new ArrayList<>();
|
||||
for (LineFragment fragment : lineFragments) {
|
||||
changes.add(new SimpleDiffChange(changes.size(), fragment));
|
||||
}
|
||||
return apply(changes, isContentsEqual);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Runnable apply(@Nullable List<SimpleDiffChange> changes,
|
||||
boolean isContentsEqual) {
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
// 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.fragments.LineFragment
|
||||
import com.intellij.diff.tools.util.text.TwosideTextDiffProvider
|
||||
import com.intellij.diff.util.Range
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
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
|
||||
|
||||
object LocalTrackerDiffUtil {
|
||||
@JvmStatic
|
||||
fun computeDifferences(tracker: LineStatusTracker<*>?,
|
||||
document1: Document,
|
||||
document2: Document,
|
||||
changelistId: String,
|
||||
textDiffProvider: TwosideTextDiffProvider,
|
||||
indicator: ProgressIndicator,
|
||||
handler: LocalTrackerDiffHandler): Runnable {
|
||||
if (tracker is SimpleLocalLineStatusTracker) {
|
||||
// partial changes are disabled for file (ex: it is marked as "unmodified")
|
||||
return handler.fallback()
|
||||
}
|
||||
|
||||
val partialTracker = tracker as? PartialLocalLineStatusTracker
|
||||
if (partialTracker == null || document2 != tracker.document) {
|
||||
return handler.error() // DiffRequest is out of date
|
||||
}
|
||||
|
||||
indicator.checkCanceled()
|
||||
val data = runReadAction {
|
||||
partialTracker.readLock {
|
||||
val isReleased = partialTracker.isReleased
|
||||
val isOperational = partialTracker.isOperational()
|
||||
val affectedChangelistIds = partialTracker.getAffectedChangeListsIds()
|
||||
|
||||
if (!isOperational) {
|
||||
TrackerData(isReleased, affectedChangelistIds, null)
|
||||
}
|
||||
else {
|
||||
val ranges = partialTracker.getRanges()
|
||||
|
||||
val localText = document2.immutableCharSequence
|
||||
val vcsText = document1.immutableCharSequence
|
||||
val trackerVcsText = partialTracker.vcsDocument.immutableCharSequence
|
||||
|
||||
val diffData = TrackerDiffData(ranges, localText, vcsText, trackerVcsText)
|
||||
TrackerData(isReleased, affectedChangelistIds, diffData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.isReleased) {
|
||||
return handler.error() // DiffRequest is out of date
|
||||
}
|
||||
|
||||
val diffData = data.diffData
|
||||
if (diffData?.ranges == null) {
|
||||
if (data.affectedChangelist.size == 1 && data.affectedChangelist.contains(changelistId)) {
|
||||
// tracker is waiting for initialisation
|
||||
// there are only one changelist, so it's safe to fallback to default logic
|
||||
return handler.fallbackWithProgress()
|
||||
}
|
||||
|
||||
return handler.retryLater()
|
||||
}
|
||||
|
||||
val ranges = diffData.ranges
|
||||
val isContentsEqual = ranges.isEmpty()
|
||||
|
||||
if (!StringUtil.equals(diffData.vcsText, diffData.trackerVcsText)) {
|
||||
return handler.error() // DiffRequest is out of date
|
||||
}
|
||||
|
||||
if (textDiffProvider.isHighlightingDisabled) {
|
||||
return handler.done(isContentsEqual, emptyList(), emptyList())
|
||||
}
|
||||
|
||||
|
||||
val linesRanges = ranges.map { range -> Range(range.vcsLine1, range.vcsLine2, range.line1, range.line2) }
|
||||
|
||||
val newFragments = textDiffProvider.compare(diffData.vcsText, diffData.localText, linesRanges, indicator)!!
|
||||
|
||||
val fragments = mutableListOf<LineFragment>()
|
||||
val fragmentsData = mutableListOf<LineFragmentData>()
|
||||
|
||||
for (i in ranges.indices) {
|
||||
val localRange = ranges[i]
|
||||
val rangeFragments = newFragments[i]
|
||||
|
||||
fragments.addAll(rangeFragments)
|
||||
|
||||
val fragmentData = LineFragmentData(localRange.isExcludedFromCommit, localRange.changelistId)
|
||||
repeat(rangeFragments.size) { fragmentsData.add(fragmentData) }
|
||||
}
|
||||
|
||||
return handler.done(isContentsEqual, fragments, fragmentsData)
|
||||
}
|
||||
|
||||
interface LocalTrackerDiffHandler {
|
||||
fun done(isContentsEqual: Boolean,
|
||||
fragments: List<LineFragment>,
|
||||
fragmentsData: List<LineFragmentData>): Runnable
|
||||
|
||||
fun retryLater(): Runnable
|
||||
fun fallback(): Runnable
|
||||
fun fallbackWithProgress(): Runnable
|
||||
fun error(): Runnable
|
||||
}
|
||||
|
||||
data class LineFragmentData(val isExcluded: Boolean,
|
||||
val changelistId: String)
|
||||
|
||||
private data class TrackerData(val isReleased: Boolean,
|
||||
val affectedChangelist: List<String>,
|
||||
val diffData: TrackerDiffData?)
|
||||
|
||||
private data class TrackerDiffData(val ranges: List<LocalRange>?,
|
||||
val localText: CharSequence,
|
||||
val vcsText: CharSequence,
|
||||
val trackerVcsText: CharSequence)
|
||||
}
|
||||
+66
-134
@@ -2,7 +2,6 @@
|
||||
package com.intellij.openapi.vcs.changes.actions.diff.lst;
|
||||
|
||||
import com.intellij.diff.DiffContext;
|
||||
import com.intellij.diff.comparison.DiffTooBigException;
|
||||
import com.intellij.diff.fragments.LineFragment;
|
||||
import com.intellij.diff.tools.simple.SimpleDiffChange;
|
||||
import com.intellij.diff.tools.simple.SimpleDiffChangeUi;
|
||||
@@ -10,7 +9,6 @@ import com.intellij.diff.tools.simple.SimpleDiffViewer;
|
||||
import com.intellij.diff.tools.util.DiffNotifications;
|
||||
import com.intellij.diff.util.DiffGutterRenderer;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.diff.util.Range;
|
||||
import com.intellij.diff.util.Side;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.idea.ActionsBundle;
|
||||
@@ -21,7 +19,6 @@ import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
@@ -50,8 +47,6 @@ import java.awt.event.ComponentEvent;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.notNull;
|
||||
|
||||
public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer {
|
||||
@NotNull private final LocalChangeListDiffRequest myLocalRequest;
|
||||
@NotNull private final String myChangelistId;
|
||||
@@ -122,117 +117,85 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer {
|
||||
return super.createUi(change);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected Runnable performRediff(@NotNull final ProgressIndicator indicator) {
|
||||
LineStatusTracker tracker = myLocalRequest.getLineStatusTracker();
|
||||
if (tracker instanceof SimpleLocalLineStatusTracker) {
|
||||
// partial changes are disabled for file (ex: it is marked as "unmodified")
|
||||
return super.performRediff(indicator);
|
||||
}
|
||||
|
||||
PartialLocalLineStatusTracker partialTracker = ObjectUtils.tryCast(tracker, PartialLocalLineStatusTracker.class);
|
||||
if (partialTracker == null || getContent2().getDocument() != tracker.getDocument()) {
|
||||
return applyNotification(DiffNotifications.createError()); // DiffRequest is out of date
|
||||
}
|
||||
|
||||
try {
|
||||
indicator.checkCanceled();
|
||||
|
||||
TrackerData data = ReadAction.compute(() -> partialTracker.readLock(() -> {
|
||||
boolean isReleased = partialTracker.isReleased();
|
||||
boolean isOperational = partialTracker.isOperational();
|
||||
List<String> affectedChangelistIds = partialTracker.getAffectedChangeListsIds();
|
||||
|
||||
if (!isOperational) {
|
||||
return new TrackerData(isReleased, affectedChangelistIds, null);
|
||||
}
|
||||
|
||||
List<LocalRange> ranges = partialTracker.getRanges();
|
||||
|
||||
CharSequence localText = getContent2().getDocument().getImmutableCharSequence();
|
||||
CharSequence vcsText = getContent1().getDocument().getImmutableCharSequence();
|
||||
CharSequence trackerVcsText = partialTracker.getVcsDocument().getImmutableCharSequence();
|
||||
|
||||
TrackerDiffData diffData = new TrackerDiffData(ranges, localText, vcsText, trackerVcsText);
|
||||
return new TrackerData(isReleased, affectedChangelistIds, diffData);
|
||||
}));
|
||||
|
||||
|
||||
if (data.isReleased) {
|
||||
return applyNotification(DiffNotifications.createError()); // DiffRequest is out of date
|
||||
}
|
||||
|
||||
TrackerDiffData diffData = data.diffData;
|
||||
|
||||
if (diffData == null || diffData.ranges == null) {
|
||||
if (data.affectedChangelist.size() == 1 &&
|
||||
data.affectedChangelist.contains(myChangelistId)) {
|
||||
// tracker is waiting for initialisation
|
||||
// there are only one changelist, so it's safe to fallback to default logic
|
||||
Runnable callback = super.performRediff(indicator);
|
||||
return () -> {
|
||||
callback.run();
|
||||
getStatusPanel().setBusy(true);
|
||||
};
|
||||
}
|
||||
|
||||
scheduleRediff();
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
|
||||
return performRediffUsingPartialTracker(diffData.ranges, diffData.localText, diffData.vcsText, diffData.trackerVcsText, indicator);
|
||||
}
|
||||
catch (DiffTooBigException e) {
|
||||
return applyNotification(DiffNotifications.createDiffTooBig());
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
return applyNotification(DiffNotifications.createError());
|
||||
}
|
||||
private Runnable superComputeDifferences(@NotNull ProgressIndicator indicator) {
|
||||
return super.computeDifferences(indicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
private Runnable performRediffUsingPartialTracker(@NotNull List<LocalRange> ranges,
|
||||
@NotNull CharSequence localText,
|
||||
@NotNull CharSequence vcsText,
|
||||
@NotNull CharSequence trackerVcsText,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
if (!StringUtil.equals(trackerVcsText, vcsText)) {
|
||||
return applyNotification(DiffNotifications.createError()); // DiffRequest is out of date
|
||||
protected Runnable computeDifferences(@NotNull ProgressIndicator indicator) {
|
||||
return LocalTrackerDiffUtil.computeDifferences(
|
||||
myLocalRequest.getLineStatusTracker(),
|
||||
getContent1().getDocument(),
|
||||
getContent2().getDocument(),
|
||||
myChangelistId,
|
||||
myTextDiffProvider,
|
||||
indicator,
|
||||
new MyLocalTrackerDiffHandler(indicator)
|
||||
);
|
||||
}
|
||||
|
||||
private class MyLocalTrackerDiffHandler implements LocalTrackerDiffUtil.LocalTrackerDiffHandler {
|
||||
@NotNull private final ProgressIndicator myIndicator;
|
||||
|
||||
private MyLocalTrackerDiffHandler(@NotNull ProgressIndicator indicator) {
|
||||
myIndicator = indicator;
|
||||
}
|
||||
|
||||
if (myTextDiffProvider.isHighlightingDisabled()) {
|
||||
return apply(null, ranges.isEmpty());
|
||||
}
|
||||
@NotNull
|
||||
@Override
|
||||
public Runnable done(boolean isContentsEqual,
|
||||
@NotNull List<? extends LineFragment> fragments,
|
||||
@NotNull List<LocalTrackerDiffUtil.LineFragmentData> fragmentsData) {
|
||||
List<SimpleDiffChange> changes = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < fragments.size(); i++) {
|
||||
LineFragment fragment = fragments.get(i);
|
||||
LocalTrackerDiffUtil.LineFragmentData data = fragmentsData.get(i);
|
||||
|
||||
List<Range> linesRanges = ContainerUtil.map(ranges, range -> new Range(range.getVcsLine1(), range.getVcsLine2(), range.getLine1(), range.getLine2()));
|
||||
boolean isExcludedFromCommit = data.isExcluded();
|
||||
boolean isFromActiveChangelist = data.getChangelistId().equals(myChangelistId);
|
||||
boolean isSkipped = !isFromActiveChangelist;
|
||||
boolean isExcluded = !isFromActiveChangelist ||
|
||||
(myAllowExcludeChangesFromCommit && isExcludedFromCommit);
|
||||
|
||||
List<List<LineFragment>> newFragments = notNull(myTextDiffProvider.compare(vcsText, localText, linesRanges, indicator));
|
||||
|
||||
boolean isContentsEqual = ranges.isEmpty();
|
||||
List<SimpleDiffChange> changes = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < ranges.size(); i++) {
|
||||
LocalRange localRange = ranges.get(i);
|
||||
List<LineFragment> rangeFragments = newFragments.get(i);
|
||||
|
||||
boolean isExcludedFromCommit = localRange.isExcludedFromCommit();
|
||||
boolean isFromActiveChangelist = localRange.getChangelistId().equals(myChangelistId);
|
||||
boolean isSkipped = !isFromActiveChangelist;
|
||||
boolean isExcluded = !isFromActiveChangelist || (myAllowExcludeChangesFromCommit && isExcludedFromCommit);
|
||||
|
||||
for (LineFragment fragment : rangeFragments) {
|
||||
changes.add(new MySimpleDiffChange(changes.size(), fragment, isExcluded, isSkipped,
|
||||
localRange.getChangelistId(), isFromActiveChangelist, isExcludedFromCommit));
|
||||
data.getChangelistId(), isFromActiveChangelist,
|
||||
isExcludedFromCommit));
|
||||
}
|
||||
|
||||
return apply(changes, isContentsEqual);
|
||||
}
|
||||
|
||||
return apply(changes, isContentsEqual);
|
||||
@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 applyNotification(DiffNotifications.createError());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -606,35 +569,4 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TrackerData {
|
||||
private final boolean isReleased;
|
||||
@NotNull public final List<String> affectedChangelist;
|
||||
@Nullable public final TrackerDiffData diffData;
|
||||
|
||||
TrackerData(boolean isReleased,
|
||||
@NotNull List<String> affectedChangelist,
|
||||
@Nullable TrackerDiffData diffData) {
|
||||
this.isReleased = isReleased;
|
||||
this.affectedChangelist = affectedChangelist;
|
||||
this.diffData = diffData;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TrackerDiffData {
|
||||
@Nullable public final List<LocalRange> ranges;
|
||||
@NotNull public final CharSequence localText;
|
||||
@NotNull public final CharSequence vcsText;
|
||||
@NotNull public final CharSequence trackerVcsText;
|
||||
|
||||
TrackerDiffData(@Nullable List<LocalRange> ranges,
|
||||
@NotNull CharSequence localText,
|
||||
@NotNull CharSequence vcsText,
|
||||
@NotNull CharSequence trackerVcsText) {
|
||||
this.ranges = ranges;
|
||||
this.localText = localText;
|
||||
this.vcsText = vcsText;
|
||||
this.trackerVcsText = trackerVcsText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user