[file-history] move code for loading diff in background to GitLogDiffHandler

Reuse the code in all diff kinds. This way actions would not need to manage background execution themselves.
This commit is contained in:
Julia Beliaeva
2017-04-14 14:31:35 +03:00
parent 099e618d73
commit 15b98239ea
3 changed files with 104 additions and 73 deletions
@@ -16,7 +16,6 @@
package com.intellij.vcs.log;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,10 +23,9 @@ import org.jetbrains.annotations.Nullable;
public interface VcsLogDiffHandler {
void showDiff(@NotNull VirtualFile root,
@Nullable FilePath leftPath, @NotNull Hash leftHash,
@Nullable FilePath rightPath, @NotNull Hash rightHash) throws VcsException;
@Nullable FilePath rightPath, @NotNull Hash rightHash);
void showDiffWithLocal(@NotNull VirtualFile root,
@Nullable FilePath revisionPath,
@NotNull Hash hash, @NotNull FilePath localPath)
throws VcsException;
@NotNull Hash hash, @NotNull FilePath localPath);
}
@@ -117,24 +117,7 @@ public class CompareRevisionsFromHistoryAction extends AnAction implements DumbA
// so that it could return a single file path for each revision
VcsFullCommitDetails newestDetail = details.get(0);
VcsFullCommitDetails olderDetail = details.get(1);
ProgressIndicator indicator = ui.getLogData().getProgress().createProgressIndicator(true);
ProgressManager.getInstance()
.runProcessWithProgressAsynchronously(new Task.Backgroundable(project, "Comparing Revisions...", false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
notNull(handler).showDiff(root, ui.getPath(olderDetail), olderDetail.getId(), ui.getPath(newestDetail), newestDetail.getId());
}
catch (VcsException e1) {
VcsBalloonProblemNotifier.showOverVersionControlView(project, "Could not compare revisions " +
olderDetail.getId().asString() +
" and " +
newestDetail.getId().asString() +
"\n" +
e1.getMessage(), MessageType.ERROR);
}
}
}, indicator);
notNull(handler).showDiff(root, ui.getPath(olderDetail), olderDetail.getId(), ui.getPath(newestDetail), newestDetail.getId());
}
else if (details.size() == 1) {
VcsFullCommitDetails detail = notNull(ContainerUtil.getFirstItem(details));
@@ -23,15 +23,21 @@ import com.intellij.diff.contents.EmptyContent;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.requests.SimpleDiffRequest;
import com.intellij.diff.util.DiffUserDataKeysEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.history.VcsDiffUtil;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.WaitForProgressToShow;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogDiffHandler;
@@ -39,11 +45,11 @@ import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitRevisionNumber;
import git4idea.changes.GitChangeUtils;
import git4idea.util.GitFileUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
@@ -65,87 +71,131 @@ public class GitLogDiffHandler implements VcsLogDiffHandler {
@Nullable FilePath leftPath,
@NotNull Hash leftHash,
@Nullable FilePath rightPath,
@NotNull Hash rightHash) throws VcsException {
@NotNull Hash rightHash) {
if (leftPath == null && rightPath == null) return;
if (chooseNotNull(leftPath, rightPath).isDirectory()) {
showDiffForDirectory(root, chooseNotNull(leftPath, rightPath), leftHash, rightHash);
}
else {
try {
DiffContent leftDiffContent = createDiffContent(root, leftPath, leftHash);
DiffContent rightDiffContent = createDiffContent(root, rightPath, rightHash);
loadDiffAndShow(new ThrowableComputable<DiffRequest, VcsException>() {
@Override
public DiffRequest compute() throws VcsException {
DiffContent leftDiffContent = createDiffContent(root, leftPath, leftHash);
DiffContent rightDiffContent = createDiffContent(root, rightPath, rightHash);
DiffRequest request = new SimpleDiffRequest(getTitle(leftPath, rightPath),
leftDiffContent, rightDiffContent,
leftHash.asString(), rightHash.asString());
WaitForProgressToShow.runOrInvokeLaterAboveProgress(() -> DiffManager.getInstance().showDiff(myProject, request), null, myProject);
}
catch (IOException e) {
LOG.error(e);
}
return new SimpleDiffRequest(getTitle(leftPath, rightPath),
leftDiffContent, rightDiffContent,
leftHash.asString(), rightHash.asString());
}
},
request -> DiffManager.getInstance().showDiff(myProject, request),
"Calculating Diff for " + chooseNotNull(rightPath, leftPath).getName());
}
}
@Override
public void showDiffWithLocal(@NotNull VirtualFile root, @Nullable FilePath revisionPath, @NotNull Hash revisionHash,
@NotNull FilePath localPath)
throws VcsException {
@NotNull FilePath localPath) {
if (localPath.isDirectory()) {
showDiffForDirectory(root, localPath, revisionHash, null);
}
else {
try {
DiffContent leftDiffContent = createDiffContent(root, revisionPath, revisionHash);
loadDiffAndShow(new ThrowableComputable<DiffRequest, VcsException>() {
@Override
public DiffRequest compute() throws VcsException {
DiffContent leftDiffContent = createDiffContent(root, revisionPath, revisionHash);
VirtualFile file = localPath.getVirtualFile();
LOG.assertTrue(file != null);
DiffContent rightDiffContent = myDiffContentFactory.create(myProject, file);
VirtualFile file = localPath.getVirtualFile();
LOG.assertTrue(file != null);
DiffContent rightDiffContent = myDiffContentFactory.create(myProject, file);
DiffRequest request = new SimpleDiffRequest(getTitle(revisionPath, localPath),
leftDiffContent, rightDiffContent,
revisionHash.asString(), "(Local)");
WaitForProgressToShow.runOrInvokeLaterAboveProgress(() -> DiffManager.getInstance().showDiff(myProject, request), null, myProject);
}
catch (IOException e) {
LOG.error(e);
}
return new SimpleDiffRequest(getTitle(revisionPath, localPath),
leftDiffContent, rightDiffContent,
revisionHash.asString(), "(Local)");
}
},
request -> DiffManager.getInstance().showDiff(myProject, request), "Calculating Diff for " + localPath.getName());
}
}
private void showDiffForDirectory(@NotNull VirtualFile root,
@NotNull FilePath directoryPath,
@NotNull Hash leftRevision, @Nullable Hash rightRevision) throws VcsException {
Collection<Change> diff = GitChangeUtils.getDiff(myProject, root,
leftRevision.asString(), rightRevision == null ? null : rightRevision.asString(),
Collections.singleton(directoryPath));
WaitForProgressToShow.runOrInvokeLaterAboveProgress(() -> {
String dialogTitle = "Changes between " +
leftRevision.asString() +
" and " +
(rightRevision == null ? "current revision" : rightRevision.asString()) +
" in " +
getTitle(directoryPath, directoryPath);
VcsDiffUtil.showChangesDialog(myProject, dialogTitle,
ContainerUtil.newArrayList(diff));
},
null,
myProject);
@NotNull Hash leftRevision, @Nullable Hash rightRevision) {
loadDiffAndShow(() -> GitChangeUtils.getDiff(myProject, root,
leftRevision.asString(), rightRevision == null ? null : rightRevision.asString(),
Collections.singleton(directoryPath)),
(diff) -> {
String dialogTitle = "Changes between " +
leftRevision.asString() +
" and " +
(rightRevision == null ? "current revision" : rightRevision.asString()) +
" in " +
getTitle(directoryPath, directoryPath);
VcsDiffUtil.showChangesDialog(myProject, dialogTitle, ContainerUtil.newArrayList(diff));
}, "Calculating Diff for " + directoryPath.getName());
}
private <T> void loadDiffAndShow(@NotNull ThrowableComputable<T, VcsException> load,
@NotNull Consumer<T> show,
@NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
if (ApplicationManager.getApplication().isDispatchThread()) {
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, title + "...", false) {
@Nullable private T myResult;
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
myResult = load.compute();
}
catch (VcsException e) {
throw new RuntimeException(e);
}
}
@Override
public void onSuccess() {
if (myResult != null) {
show.consume(myResult);
}
}
@Override
public void onThrowable(@NotNull Throwable error) {
VcsBalloonProblemNotifier.showOverVersionControlView(myProject, title + " failed\n" +
error.getMessage(), MessageType.ERROR);
}
});
}
else {
try {
T result = load.compute();
ApplicationManager.getApplication().invokeLater(() -> show.consume(result));
}
catch (VcsException e) {
VcsBalloonProblemNotifier.showOverVersionControlView(myProject, title + " failed\n" +
e.getMessage(), MessageType.ERROR);
}
}
}
@NotNull
private DiffContent createDiffContent(@NotNull VirtualFile root,
@Nullable FilePath path,
@NotNull Hash hash) throws IOException, VcsException {
@NotNull Hash hash) throws VcsException {
DiffContent diffContent;
if (path == null) {
diffContent = new EmptyContent();
}
else {
byte[] content = GitFileUtils.getFileContent(myProject, root, hash.asString(), VcsFileUtil.relativePath(root, path));
diffContent = myDiffContentFactory.createFromBytes(myProject, content, path);
try {
byte[] content = GitFileUtils.getFileContent(myProject, root, hash.asString(), VcsFileUtil.relativePath(root, path));
diffContent = myDiffContentFactory.createFromBytes(myProject, content, path);
}
catch (IOException e) {
throw new VcsException(e);
}
}
diffContent.putUserData(DiffUserDataKeysEx.REVISION_INFO, new Pair<>(path, new GitRevisionNumber(hash.asString())));