mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-133270 git: allow to pass "detect code movements" options to blame
* try to reopen closed annotations on change (ex: after commit) * allow to disable "ignore whitespaces" option IDEA-183867
This commit is contained in:
@@ -25,7 +25,7 @@ import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import java.util.HashMap;
|
||||
import org.jetbrains.annotations.CalledInAwt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -195,9 +195,10 @@ public abstract class FileAnnotation {
|
||||
* If `this` is visible, hide it and show new one instead.
|
||||
* If `this` is not visible, do nothing.
|
||||
*
|
||||
* @param newFileAnnotation annotations to be shown
|
||||
* @param newFileAnnotation annotations to be shown or `null` to load annotations again
|
||||
*/
|
||||
public synchronized final void reload(@NotNull FileAnnotation newFileAnnotation) {
|
||||
@CalledInAwt
|
||||
public synchronized final void reload(@Nullable FileAnnotation newFileAnnotation) {
|
||||
if (myReloader != null) myReloader.consume(newFileAnnotation);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,12 @@ public class VcsHistoryCache {
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAnnotations() {
|
||||
synchronized (myLock) {
|
||||
myAnnotationCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CachedHistory {
|
||||
private final FilePath myPath;
|
||||
private final List<VcsFileRevision> myRevisions;
|
||||
|
||||
+1
-2
@@ -142,8 +142,7 @@ public class AnnotateDiffViewerAction {
|
||||
EventData data = collectEventData(e);
|
||||
assert data != null;
|
||||
|
||||
boolean annotationShown = data.annotator.isAnnotationShown();
|
||||
if (annotationShown) {
|
||||
if (!selected) {
|
||||
data.annotator.hideAnnotation();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.vcs.actions;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.Separator;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
@@ -142,9 +140,24 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
|
||||
});
|
||||
|
||||
fileAnnotation.setReloader(newFileAnnotation -> {
|
||||
if (project.isDisposed()) return;
|
||||
if (editor.getGutter().isAnnotationsShown()) {
|
||||
assert Comparing.equal(fileAnnotation.getFile(), newFileAnnotation.getFile());
|
||||
doAnnotate(editor, project, currentFile, newFileAnnotation, vcs, upToDateLineNumbers, false);
|
||||
if (newFileAnnotation != null) {
|
||||
assert Comparing.equal(fileAnnotation.getFile(), newFileAnnotation.getFile());
|
||||
doAnnotate(editor, project, currentFile, newFileAnnotation, vcs, upToDateLineNumbers, false);
|
||||
}
|
||||
else {
|
||||
DataContext dataContext = DataManager.getInstance().getDataContext(editor.getComponent());
|
||||
AnActionEvent event = AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, dataContext);
|
||||
Provider provider = getProvider(event);
|
||||
|
||||
if (provider != null && provider.isEnabled(event) && !provider.isSuspended(event)) {
|
||||
provider.perform(event, true);
|
||||
}
|
||||
else {
|
||||
editor.getGutter().closeAllAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+26
-19
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ZipperUpdater;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
@@ -39,7 +40,11 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.diagnostic.Logger.getInstance;
|
||||
|
||||
public class VcsAnnotationLocalChangesListenerImpl implements Disposable, VcsAnnotationLocalChangesListener {
|
||||
private static final Logger LOG = getInstance(VcsAnnotationLocalChangesListenerImpl.class);
|
||||
|
||||
private final ZipperUpdater myUpdater;
|
||||
private final MessageBusConnection myConnection;
|
||||
|
||||
@@ -132,11 +137,8 @@ public class VcsAnnotationLocalChangesListenerImpl implements Disposable, VcsAnn
|
||||
final VcsRevisionNumber number = fromDiffProvider(key);
|
||||
if (number == null) continue;
|
||||
final Collection<FileAnnotation> fileAnnotations = entry.getValue();
|
||||
for (FileAnnotation annotation : fileAnnotations) {
|
||||
if (annotation.isBaseRevisionChanged(number)) {
|
||||
annotation.close();
|
||||
}
|
||||
}
|
||||
List<FileAnnotation> copy = ContainerUtil.filter(fileAnnotations, it -> it.isBaseRevisionChanged(number));
|
||||
invalidateAnnotations(copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,11 +164,9 @@ public class VcsAnnotationLocalChangesListenerImpl implements Disposable, VcsAnn
|
||||
}
|
||||
if (number == null) return;
|
||||
|
||||
for (FileAnnotation annotation : annotations) {
|
||||
if (annotation.isBaseRevisionChanged(number)) {
|
||||
annotation.close();
|
||||
}
|
||||
}
|
||||
VcsRevisionNumber finalNumber = number;
|
||||
List<FileAnnotation> copy = ContainerUtil.filter(annotations, it -> it.isBaseRevisionChanged(finalNumber));
|
||||
invalidateAnnotations(copy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,18 +181,25 @@ public class VcsAnnotationLocalChangesListenerImpl implements Disposable, VcsAnn
|
||||
|
||||
private void closeForVcs(final Set<VcsKey> refresh) {
|
||||
if (refresh.isEmpty()) return;
|
||||
final Set<FileAnnotation> copy = new HashSet<>();
|
||||
synchronized (myLock) {
|
||||
for (FileAnnotation annotation : myFileAnnotationMap.values()) {
|
||||
final VcsKey key = annotation.getVcsKey();
|
||||
if (key != null && refresh.contains(key)) {
|
||||
copy.add(annotation);
|
||||
List<FileAnnotation> copy = ContainerUtil.filter(myFileAnnotationMap.values(), it -> {
|
||||
return it.getVcsKey() != null && refresh.contains(it.getVcsKey());
|
||||
});
|
||||
invalidateAnnotations(copy);
|
||||
}
|
||||
}
|
||||
|
||||
private static void invalidateAnnotations(@NotNull Collection<FileAnnotation> annotations) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
for (FileAnnotation annotation: annotations) {
|
||||
try {
|
||||
annotation.reload(null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (FileAnnotation annotation : copy) {
|
||||
annotation.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// annotations for already committed revisions should not register with this method - they are not subject to refresh
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
<vcsChangesViewRefresher implementation="git4idea.changes.GitChangesViewRefresher" />
|
||||
<pushSupport implementation="git4idea.push.GitPushSupport"/>
|
||||
<cherryPicker implementation="git4idea.cherrypick.GitCherryPicker"/>
|
||||
<vcsAnnotationGutterActionProvider implementation="git4idea.actions.GitToggleAnnotationOptionsActionProvider" />
|
||||
<vcsAnnotationGutterActionProvider implementation="git4idea.actions.GitShowCommitInLogAnnotationGutterActionProvider" />
|
||||
<statistics.projectUsagesCollector implementation="git4idea.GitStatisticsCollector"/>
|
||||
<statistics.projectUsagesCollector implementation="git4idea.GitUsagesTriggerCollector"/>
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// Copyright 2000-2018 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 git4idea.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.annotate.AnnotationGutterActionProvider;
|
||||
import com.intellij.openapi.vcs.annotate.FileAnnotation;
|
||||
import com.intellij.openapi.vcs.changes.VcsAnnotationRefresher;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.annotate.GitFileAnnotation;
|
||||
import git4idea.config.GitVcsApplicationSettings;
|
||||
import git4idea.config.GitVcsApplicationSettings.AnnotateDetectMovementsOption;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class GitToggleAnnotationOptionsActionProvider implements AnnotationGutterActionProvider {
|
||||
private static final GitVcsApplicationSettings SETTINGS = GitVcsApplicationSettings.getInstance();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnAction createAction(@NotNull final FileAnnotation annotation) {
|
||||
return new MyGroup(annotation);
|
||||
}
|
||||
|
||||
private static void resetAllAnnotations(@NotNull Project project) {
|
||||
ProjectLevelVcsManager.getInstance(project).getVcsHistoryCache().clearAnnotations();
|
||||
BackgroundTaskUtil.syncPublisher(project, VcsAnnotationRefresher.LOCAL_CHANGES_CHANGED).configurationChanged(GitVcs.getKey());
|
||||
}
|
||||
|
||||
private static class MyGroup extends ActionGroup {
|
||||
private final FileAnnotation myAnnotation;
|
||||
|
||||
public MyGroup(@NotNull FileAnnotation annotation) {
|
||||
super("Options", true);
|
||||
myAnnotation = annotation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnAction[] getChildren(@Nullable AnActionEvent e) {
|
||||
if (myAnnotation instanceof GitFileAnnotation) {
|
||||
return new AnAction[]{
|
||||
new ToggleIgnoreWhitespaces(myAnnotation.getProject()),
|
||||
new ToggleInnerMovementsWhitespaces(myAnnotation.getProject()),
|
||||
new ToggleOuterMovementsWhitespaces(myAnnotation.getProject()),
|
||||
};
|
||||
}
|
||||
return AnAction.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ToggleIgnoreWhitespaces extends ToggleAction implements DumbAware {
|
||||
@NotNull private final Project myProject;
|
||||
|
||||
public ToggleIgnoreWhitespaces(@NotNull Project project) {
|
||||
super("Ignore Whitespaces");
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return SETTINGS.isIgnoreWhitespaces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean enabled) {
|
||||
SETTINGS.setIgnoreWhitespaces(enabled);
|
||||
resetAllAnnotations(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ToggleInnerMovementsWhitespaces extends ToggleAction implements DumbAware {
|
||||
@NotNull private final Project myProject;
|
||||
|
||||
public ToggleInnerMovementsWhitespaces(@NotNull Project project) {
|
||||
super("Detect Movements Within File");
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return SETTINGS.getAnnotateDetectMovementsOption() == AnnotateDetectMovementsOption.INNER ||
|
||||
SETTINGS.getAnnotateDetectMovementsOption() == AnnotateDetectMovementsOption.OUTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean enabled) {
|
||||
if (enabled) {
|
||||
SETTINGS.setAnnotateDetectMovementsOption(AnnotateDetectMovementsOption.INNER);
|
||||
}
|
||||
else {
|
||||
SETTINGS.setAnnotateDetectMovementsOption(AnnotateDetectMovementsOption.NONE);
|
||||
}
|
||||
resetAllAnnotations(myProject);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ToggleOuterMovementsWhitespaces extends ToggleAction implements DumbAware {
|
||||
@NotNull private final Project myProject;
|
||||
|
||||
public ToggleOuterMovementsWhitespaces(@NotNull Project project) {
|
||||
super("Detect Movements Across Files");
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return SETTINGS.getAnnotateDetectMovementsOption() == AnnotateDetectMovementsOption.OUTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean enabled) {
|
||||
if (enabled) {
|
||||
SETTINGS.setAnnotateDetectMovementsOption(AnnotateDetectMovementsOption.OUTER);
|
||||
}
|
||||
else {
|
||||
SETTINGS.setAnnotateDetectMovementsOption(AnnotateDetectMovementsOption.INNER);
|
||||
}
|
||||
resetAllAnnotations(myProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,8 @@ import git4idea.annotate.GitFileAnnotation.LineInfo;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitLineHandler;
|
||||
import git4idea.config.GitVcsApplicationSettings;
|
||||
import git4idea.config.GitVcsApplicationSettings.AnnotateDetectMovementsOption;
|
||||
import git4idea.history.GitFileHistory;
|
||||
import git4idea.history.GitHistoryProvider;
|
||||
import git4idea.history.GitHistoryUtils;
|
||||
@@ -155,8 +157,20 @@ public class GitAnnotationProvider implements AnnotationProviderEx {
|
||||
VirtualFile root = GitUtil.getGitRoot(repositoryFilePath);
|
||||
GitLineHandler h = new GitLineHandler(myProject, root, GitCommand.BLAME);
|
||||
h.setStdoutSuppressed(true);
|
||||
h.addParameters("--porcelain", "-l", "-t", "-w");
|
||||
h.addParameters("--porcelain", "-l", "-t");
|
||||
h.addParameters("--encoding=UTF-8");
|
||||
|
||||
GitVcsApplicationSettings settings = GitVcsApplicationSettings.getInstance();
|
||||
if (settings.isIgnoreWhitespaces()) {
|
||||
h.addParameters("-w");
|
||||
}
|
||||
if (settings.getAnnotateDetectMovementsOption() == AnnotateDetectMovementsOption.INNER) {
|
||||
h.addParameters("-M");
|
||||
}
|
||||
else if (settings.getAnnotateDetectMovementsOption() == AnnotateDetectMovementsOption.OUTER) {
|
||||
h.addParameters("-C");
|
||||
}
|
||||
|
||||
if (revision == null) {
|
||||
h.addParameters("HEAD");
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package git4idea.annotate;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsKey;
|
||||
@@ -36,7 +37,6 @@ import git4idea.GitContentRevision;
|
||||
import git4idea.GitFileRevision;
|
||||
import git4idea.GitRevisionNumber;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -150,9 +150,17 @@ public class GitFileAnnotation extends FileAnnotation {
|
||||
fileRevision = myRevisions.get(myRevisionMap.get(revisionNumber));
|
||||
}
|
||||
|
||||
String path = null;
|
||||
if (!VcsUtil.getFilePath(myFile).equals(lineInfo.myFilePath)) {
|
||||
path = FileUtil.getLocationRelativeToUserHome(lineInfo.myFilePath.getPresentableUrl());
|
||||
}
|
||||
|
||||
String commitMessage = fileRevision != null ? fileRevision.getCommitMessage() : lineInfo.getSubject() + "\n...";
|
||||
return GitBundle.message("annotation.tool.tip", revisionNumber.asString(), lineInfo.getAuthor(),
|
||||
DateFormatUtil.formatDateTime(lineInfo.getAuthorDate()), commitMessage);
|
||||
return "commit " + revisionNumber.asString() +
|
||||
"\nAuthor: " + lineInfo.getAuthor() +
|
||||
"\nDate: " + DateFormatUtil.formatDateTime(lineInfo.getAuthorDate()) +
|
||||
(path != null ? "\nPath: " + path : "") +
|
||||
"\n\n" + commitMessage;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -29,6 +29,9 @@ public class GitVcsApplicationSettings implements PersistentStateComponent<GitVc
|
||||
public static class State {
|
||||
public String myPathToGit = null;
|
||||
public SshExecutable SSH_EXECUTABLE = null;
|
||||
|
||||
public boolean ANNOTATE_IGNORE_SPACES = true;
|
||||
public AnnotateDetectMovementsOption ANNOTATE_DETECT_INNER_MOVEMENTS = AnnotateDetectMovementsOption.NONE;
|
||||
}
|
||||
|
||||
public static GitVcsApplicationSettings getInstance() {
|
||||
@@ -73,4 +76,28 @@ public class GitVcsApplicationSettings implements PersistentStateComponent<GitVc
|
||||
SshExecutable getIdeaSsh() {
|
||||
return myState.SSH_EXECUTABLE;
|
||||
}
|
||||
|
||||
|
||||
public boolean isIgnoreWhitespaces() {
|
||||
return myState.ANNOTATE_IGNORE_SPACES;
|
||||
}
|
||||
|
||||
public void setIgnoreWhitespaces(boolean value) {
|
||||
myState.ANNOTATE_IGNORE_SPACES = value;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AnnotateDetectMovementsOption getAnnotateDetectMovementsOption() {
|
||||
return myState.ANNOTATE_DETECT_INNER_MOVEMENTS;
|
||||
}
|
||||
|
||||
public void setAnnotateDetectMovementsOption(@NotNull AnnotateDetectMovementsOption value) {
|
||||
myState.ANNOTATE_DETECT_INNER_MOVEMENTS = value;
|
||||
}
|
||||
|
||||
public enum AnnotateDetectMovementsOption {
|
||||
NONE,
|
||||
INNER,
|
||||
OUTER
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ addrefspec.node.tags=Tags
|
||||
addrefspec.reference.chooser.tooltip=Select remote branch and tag references
|
||||
addrefspec.title=Add Reference(s)
|
||||
annotate.action.name=Annotate
|
||||
annotation.tool.tip=commit {0}\nAuthor: {1}\nDate: {2}\n\n{3}
|
||||
changes.retrieving=Retrieving changes for revision {0}
|
||||
checking.out=Checkout {0}
|
||||
checkout.action.name=Checkout
|
||||
|
||||
Reference in New Issue
Block a user