mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[shelf]: implement show diff and show diff with local from shelvedView
* for new and deleted files get content directly from patch/local file; * for modified files: - try to detect base if base found show diff local or base with patch applied on base; - if no base detected then show diff with local and patch applied to local (maybe somehow);
This commit is contained in:
@@ -147,6 +147,9 @@
|
||||
<action id="ShelvedChanges.Restore" class="com.intellij.openapi.vcs.changes.shelf.RestoreShelvedChange"/>
|
||||
<action id="ShelvedChanges.Diff" class="com.intellij.openapi.vcs.changes.shelf.DiffShelvedChangesAction"
|
||||
icon="AllIcons.Actions.Diff" use-shortcut-of="Diff.ShowDiff"/>
|
||||
<action id="ShelvedChanges.DiffWithLocal" class="com.intellij.openapi.vcs.changes.shelf.DiffShelvedChangesWithLocalAction"
|
||||
text="Compare with Local" description="Compare shelved version with current" use-shortcut-of="Vcs.ShowDiffWithLocal"
|
||||
icon="AllIcons.Actions.DiffWithCurrent"/>
|
||||
<action id="ChangesView.CreatePatchFromChanges" class="com.intellij.openapi.vcs.changes.actions.CreatePatchFromChangesAction"
|
||||
icon="AllIcons.Vcs.Patch"/>
|
||||
<action id="ShelvedChanges.ImportPatches" class="com.intellij.openapi.vcs.changes.shelf.ImportIntoShelfAction"/>
|
||||
|
||||
+30
-3
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.vcs.changes.patch;
|
||||
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.diff.impl.patch.PatchHunk;
|
||||
import com.intellij.openapi.diff.impl.patch.TextFilePatch;
|
||||
import com.intellij.openapi.diff.impl.patch.apply.GenericPatchApplier;
|
||||
@@ -34,15 +35,22 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.chooseNotNull;
|
||||
|
||||
public class ApplyPatchForBaseRevisionTexts {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ApplyPatchForBaseRevisionTexts.class);
|
||||
|
||||
private final CharSequence myLocal;
|
||||
private CharSequence myBase;
|
||||
private String myPatched;
|
||||
private boolean myIsAppliedSomehow;
|
||||
private final List<String> myWarnings;
|
||||
private boolean myBaseRevisionLoaded;
|
||||
|
||||
@NotNull
|
||||
@CalledInAny
|
||||
public static ApplyPatchForBaseRevisionTexts create(final Project project, final VirtualFile file, final FilePath pathBeforeRename,
|
||||
public static ApplyPatchForBaseRevisionTexts create(final Project project, @NotNull final VirtualFile file, final FilePath pathBeforeRename,
|
||||
final TextFilePatch patch, @Nullable final CharSequence baseContents) {
|
||||
assert ! patch.isNewFile();
|
||||
final String beforeVersionId = patch.getBeforeVersionId();
|
||||
@@ -61,7 +69,7 @@ public class ApplyPatchForBaseRevisionTexts {
|
||||
private ApplyPatchForBaseRevisionTexts(final DefaultPatchBaseVersionProvider provider,
|
||||
final FilePath pathBeforeRename,
|
||||
final TextFilePatch patch,
|
||||
final VirtualFile file,
|
||||
@NotNull final VirtualFile file,
|
||||
@Nullable CharSequence baseContents) {
|
||||
myWarnings = new ArrayList<>();
|
||||
myLocal = getLocalFileContent(file);
|
||||
@@ -70,8 +78,13 @@ public class ApplyPatchForBaseRevisionTexts {
|
||||
|
||||
if (baseContents != null) {
|
||||
myBase = StringUtil.convertLineSeparators(baseContents.toString());
|
||||
myBaseRevisionLoaded = true;
|
||||
final GenericPatchApplier applier = new GenericPatchApplier(myBase, hunks);
|
||||
if (!applier.execute()) {
|
||||
myIsAppliedSomehow = true;
|
||||
LOG.warn(
|
||||
String.format("Patch for %s has wrong base and can't be applied properly",
|
||||
chooseNotNull(patch.getBeforeName(), patch.getAfterName())));
|
||||
applier.trySolveSomehow();
|
||||
}
|
||||
setPatched(applier.getAfter());
|
||||
@@ -86,6 +99,7 @@ public class ApplyPatchForBaseRevisionTexts {
|
||||
return true;
|
||||
}
|
||||
myBase = text;
|
||||
myBaseRevisionLoaded = true;
|
||||
setPatched(applier.getAfter());
|
||||
return false;
|
||||
}, myWarnings);
|
||||
@@ -97,7 +111,8 @@ public class ApplyPatchForBaseRevisionTexts {
|
||||
}
|
||||
|
||||
final GenericPatchApplier applier = new GenericPatchApplier(myLocal, hunks);
|
||||
if (! applier.execute()) {
|
||||
if (!applier.execute()) {
|
||||
myIsAppliedSomehow = true;
|
||||
applier.trySolveSomehow();
|
||||
}
|
||||
setPatched(applier.getAfter());
|
||||
@@ -121,6 +136,10 @@ public class ApplyPatchForBaseRevisionTexts {
|
||||
public CharSequence getBase() {
|
||||
return myBase;
|
||||
}
|
||||
|
||||
public void clearBase() {
|
||||
myBase = null;
|
||||
}
|
||||
|
||||
private void setPatched(final String text) {
|
||||
myPatched = StringUtil.convertLineSeparators(text);
|
||||
@@ -129,4 +148,12 @@ public class ApplyPatchForBaseRevisionTexts {
|
||||
public String getPatched() {
|
||||
return myPatched;
|
||||
}
|
||||
|
||||
public boolean isAppliedSomehow() {
|
||||
return myIsAppliedSomehow;
|
||||
}
|
||||
|
||||
public boolean isBaseRevisionLoaded() {
|
||||
return myBaseRevisionLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
+83
-23
@@ -15,14 +15,19 @@
|
||||
*/
|
||||
package com.intellij.openapi.vcs.changes.shelf;
|
||||
|
||||
import com.intellij.diff.DiffContentFactory;
|
||||
import com.intellij.diff.DiffDialogHints;
|
||||
import com.intellij.diff.DiffManager;
|
||||
import com.intellij.diff.actions.impl.GoToChangePopupBuilder;
|
||||
import com.intellij.diff.chains.DiffRequestChain;
|
||||
import com.intellij.diff.chains.DiffRequestProducer;
|
||||
import com.intellij.diff.chains.DiffRequestProducerException;
|
||||
import com.intellij.diff.contents.DiffContent;
|
||||
import com.intellij.diff.requests.DiffRequest;
|
||||
import com.intellij.diff.requests.SimpleDiffRequest;
|
||||
import com.intellij.diff.requests.UnknownFileTypeDiffRequest;
|
||||
import com.intellij.diff.tools.util.DiffNotifications;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
@@ -47,10 +52,8 @@ import com.intellij.openapi.vcs.changes.CommitContext;
|
||||
import com.intellij.openapi.vcs.changes.FilePathsHelper;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ChangeGoToChangePopupAction;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchForBaseRevisionTexts;
|
||||
import com.intellij.openapi.vcs.changes.patch.PatchDiffRequestFactory;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -61,9 +64,18 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.vcs.changes.patch.PatchDiffRequestFactory.createConflictDiffRequest;
|
||||
import static com.intellij.openapi.vcs.changes.patch.PatchDiffRequestFactory.createDiffRequest;
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
import static com.intellij.util.ObjectUtils.chooseNotNull;
|
||||
|
||||
public class DiffShelvedChangesAction extends AnAction implements DumbAware {
|
||||
|
||||
private static final String DIFF_WITH_BASE_ERROR = "Base content not found or not applicable.";
|
||||
public static final String SHELVED_VERSION = "Shelved Version";
|
||||
public static final String BASE_VERSION = "Base Version";
|
||||
public static final String CURRENT_VERSION = "Current Version";
|
||||
|
||||
public void update(final AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(isEnabled(e.getDataContext()));
|
||||
}
|
||||
@@ -80,19 +92,23 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
public static void showShelvedChangesDiff(final DataContext dc) {
|
||||
showShelvedChangesDiff(dc, false);
|
||||
}
|
||||
|
||||
public static void showShelvedChangesDiff(final DataContext dc, boolean withLocal) {
|
||||
final Project project = CommonDataKeys.PROJECT.getData(dc);
|
||||
if (project == null) return;
|
||||
if (ChangeListManager.getInstance(project).isFreezedWithNotification(null)) return;
|
||||
|
||||
List<ShelvedChangeList> changeLists = ShelvedChangesViewManager.getShelvedLists(dc);
|
||||
ShelvedChangeList changeList = ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(changeLists));
|
||||
ShelvedChangeList changeList = assertNotNull(ContainerUtil.getFirstItem(changeLists));
|
||||
|
||||
final List<ShelvedChange> textChanges = changeList.getChanges(project);
|
||||
final List<ShelvedBinaryFile> binaryChanges = changeList.getBinaryFiles();
|
||||
|
||||
final List<MyDiffRequestProducer> diffRequestProducers = new ArrayList<>();
|
||||
|
||||
processTextChanges(project, textChanges, diffRequestProducers);
|
||||
processTextChanges(project, textChanges, diffRequestProducers, withLocal);
|
||||
processBinaryFiles(project, binaryChanges, diffRequestProducers);
|
||||
|
||||
Collections.sort(diffRequestProducers, ChangeDiffRequestComparator.getInstance());
|
||||
@@ -141,7 +157,7 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware {
|
||||
public DiffRequest process(@NotNull UserDataHolder context, @NotNull ProgressIndicator indicator)
|
||||
throws DiffRequestProducerException, ProcessCanceledException {
|
||||
Change change = shelvedChange.createChange(project);
|
||||
return PatchDiffRequestFactory.createDiffRequest(project, change, getName(), context, indicator);
|
||||
return createDiffRequest(project, change, getName(), context, indicator);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -149,7 +165,8 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware {
|
||||
|
||||
private static void processTextChanges(@NotNull final Project project,
|
||||
@NotNull List<ShelvedChange> changesFromFirstList,
|
||||
@NotNull List<MyDiffRequestProducer> diffRequestProducers) {
|
||||
@NotNull List<MyDiffRequestProducer> diffRequestProducers,
|
||||
boolean withLocal) {
|
||||
final String base = project.getBasePath();
|
||||
final ApplyPatchContext patchContext = new ApplyPatchContext(project.getBaseDir(), 0, false, false);
|
||||
final PatchesPreloader preloader = new PatchesPreloader(project);
|
||||
@@ -185,27 +202,70 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware {
|
||||
if (!isNewFile && file.getFileType() == UnknownFileType.INSTANCE) {
|
||||
return new UnknownFileTypeDiffRequest(file, getName());
|
||||
}
|
||||
if (isNewFile) return createDiffRequest(project, shelvedChange.getChange(project), getName(), context, indicator);
|
||||
|
||||
final CommitContext commitContext;
|
||||
final TextFilePatch patch;
|
||||
try {
|
||||
commitContext = new CommitContext();
|
||||
patch = preloader.getPatch(shelvedChange, commitContext);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
throw new DiffRequestProducerException("Can't show diff for '" + getName() + "'", e);
|
||||
}
|
||||
|
||||
if (shelvedChange.isConflictingChange(project)) {
|
||||
try {
|
||||
final CommitContext commitContext = new CommitContext();
|
||||
final TextFilePatch patch = preloader.getPatch(shelvedChange, commitContext);
|
||||
final FilePath pathBeforeRename = patchContext.getPathBeforeRename(file);
|
||||
if (patch.isDeletedFile()) {
|
||||
return createDiffRequestForDeleted(patch);
|
||||
}
|
||||
return createDiffRequestForModified(patch, commitContext, context, indicator);
|
||||
}
|
||||
|
||||
CharSequence baseContents = Extensions.findExtension(PatchEP.EP_NAME, project, BaseRevisionTextPatchEP.class)
|
||||
.provideContent(chooseNotNull(patch.getAfterName(), patch.getBeforeName()), commitContext);
|
||||
ApplyPatchForBaseRevisionTexts texts =
|
||||
ApplyPatchForBaseRevisionTexts.create(project, file, pathBeforeRename, patch, baseContents);
|
||||
return PatchDiffRequestFactory
|
||||
.createConflictDiffRequest(project, file, patch, "Shelved Version", texts, getName());
|
||||
}
|
||||
catch (VcsException e) {
|
||||
throw new DiffRequestProducerException("Can't show diff for '" + getName() + "'", e);
|
||||
}
|
||||
@NotNull
|
||||
private DiffRequest createDiffRequestForDeleted(@NotNull TextFilePatch patch) {
|
||||
assert file != null;
|
||||
DiffContentFactory contentFactory = DiffContentFactory.getInstance();
|
||||
DiffContent leftContent = withLocal
|
||||
? contentFactory.create(project, file)
|
||||
: contentFactory.create(project, patch.getSingleHunkPatchText());
|
||||
return new SimpleDiffRequest(getName(), leftContent,
|
||||
contentFactory.createEmpty(),
|
||||
withLocal ? CURRENT_VERSION : SHELVED_VERSION, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DiffRequest createDiffRequestForModified(@NotNull TextFilePatch patch,
|
||||
@NotNull CommitContext commitContext,
|
||||
@NotNull UserDataHolder context,
|
||||
@NotNull ProgressIndicator indicator) throws DiffRequestProducerException {
|
||||
assert file != null;
|
||||
CharSequence baseContents = Extensions.findExtension(PatchEP.EP_NAME, project, BaseRevisionTextPatchEP.class)
|
||||
.provideContent(chooseNotNull(patch.getAfterName(), patch.getBeforeName()), commitContext);
|
||||
ApplyPatchForBaseRevisionTexts texts =
|
||||
ApplyPatchForBaseRevisionTexts.create(project, file, patchContext.getPathBeforeRename(file), patch, baseContents);
|
||||
//found base
|
||||
if (texts.isBaseRevisionLoaded() && !texts.isAppliedSomehow()) {
|
||||
//normal diff
|
||||
DiffContentFactory contentFactory = DiffContentFactory.getInstance();
|
||||
DiffContent leftContent = withLocal
|
||||
? contentFactory.create(project, file)
|
||||
: contentFactory.create(project, texts.getBase().toString());
|
||||
return new SimpleDiffRequest(getName(), leftContent, contentFactory.create(project, texts.getPatched()),
|
||||
withLocal ? CURRENT_VERSION : BASE_VERSION, SHELVED_VERSION);
|
||||
}
|
||||
else {
|
||||
final Change change = shelvedChange.getChange(project);
|
||||
return PatchDiffRequestFactory.createDiffRequest(project, change, getName(), context, indicator);
|
||||
//try applying on local
|
||||
if (texts.isAppliedSomehow()) {
|
||||
texts.clearBase(); // wrong base should not be used even it exists
|
||||
}
|
||||
DiffRequest diffRequest = shelvedChange.isConflictingChange(project)
|
||||
? createConflictDiffRequest(project, file, patch, SHELVED_VERSION, texts, getName())
|
||||
: createDiffRequest(project, shelvedChange.getChange(project), getName(), context, indicator);
|
||||
if (!withLocal) {
|
||||
DiffUtil
|
||||
.addNotification(DiffNotifications.createNotification(DIFF_WITH_BASE_ERROR + " Showing difference with local version"),
|
||||
diffRequest);
|
||||
}
|
||||
return diffRequest;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.openapi.vcs.changes.shelf;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
|
||||
public class DiffShelvedChangesWithLocalAction extends DiffShelvedChangesAction {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
showShelvedChangesDiff(e.getDataContext(), true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user