IDEA-212693 vcs: show navigatable links in annotations popup
authorAleksey Pivovarov <AMPivovarov@gmail.com>
Mon, 8 Jul 2019 15:41:24 +0000 (18:41 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Mon, 29 Jul 2019 15:49:22 +0000 (18:49 +0300)
GitOrigin-RevId: 37b2b1c079bc75b0ba908034e0311cb702496472

platform/vcs-impl/src/git4idea/annotate/AnnotationTooltipBuilder.java [new file with mode: 0644]
plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java
plugins/hg4idea/resources/org/zmlx/hg4idea/HgVcsMessages.properties
plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotation.java
plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/BaseSvnFileAnnotation.java

diff --git a/platform/vcs-impl/src/git4idea/annotate/AnnotationTooltipBuilder.java b/platform/vcs-impl/src/git4idea/annotate/AnnotationTooltipBuilder.java
new file mode 100644 (file)
index 0000000..45a6853
--- /dev/null
@@ -0,0 +1,90 @@
+// 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 git4idea.annotate;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import com.intellij.util.containers.Convertor;
+import com.intellij.vcsUtil.VcsUtil;
+import com.intellij.xml.util.XmlStringUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class AnnotationTooltipBuilder {
+  @NotNull private final Project myProject;
+  private final boolean myAsHtml;
+
+  private final StringBuilder sb = new StringBuilder();
+
+  public AnnotationTooltipBuilder(@NotNull Project project, boolean asHtml) {
+    myProject = project;
+    myAsHtml = asHtml;
+  }
+
+  private void append(@NotNull String text) {
+    sb.append(myAsHtml ? XmlStringUtil.escapeString(text) : text);
+  }
+
+  private void appendRaw(@NotNull String text) {
+    sb.append(text);
+  }
+
+  public void appendRevisionLine(@NotNull VcsRevisionNumber revisionNumber,
+                                 @Nullable Convertor<? super VcsRevisionNumber, String> linkBuilder) {
+    appendNewline();
+    append("commit ");
+
+    String link = myAsHtml && linkBuilder != null ? linkBuilder.convert(revisionNumber) : null;
+    if (link != null) {
+      appendRaw(link);
+    }
+    else {
+      append(revisionNumber.asString());
+    }
+  }
+
+  public void appendLine(@NotNull String content) {
+    appendNewline();
+    append(content);
+  }
+
+  public void appendCommitMessageBlock(@NotNull String message) {
+    append("\n\n");
+    appendTextWithLinks(message);
+  }
+
+  public void appendTextWithLinks(@NotNull String message) {
+    if (myAsHtml) {
+      appendRaw(IssueLinkHtmlRenderer.formatTextWithLinks(myProject, message));
+    }
+    else {
+      append(VcsUtil.trimCommitMessageToSaneSize(message));
+    }
+  }
+
+  private void appendNewline() {
+    if (sb.length() != 0) append("\n");
+  }
+
+  @Override
+  public String toString() {
+    return sb.toString();
+  }
+
+  @NotNull
+  public static String buildSimpleTooltip(@NotNull Project project,
+                                          boolean asHtml,
+                                          @NotNull String prefix,
+                                          @NotNull String revision,
+                                          @Nullable String commitMessage) {
+    AnnotationTooltipBuilder builder = new AnnotationTooltipBuilder(project, asHtml);
+    builder.append(prefix);
+    builder.append(" ");
+    builder.append(revision);
+    if (commitMessage != null) {
+      builder.append(": ");
+      builder.appendTextWithLinks(commitMessage);
+    }
+    return builder.toString();
+  }
+}
index 2f8d9c286301cfe06274d058cba3d86726222077..cf7b8cb80c7f8d6b26ac3bd55c72032b9ff39ddb 100644 (file)
@@ -26,7 +26,6 @@ import com.intellij.openapi.vcs.annotate.FileAnnotation;
 import com.intellij.openapi.vcs.annotate.LineAnnotationAspect;
 import com.intellij.openapi.vcs.annotate.LineAnnotationAspectAdapter;
 import com.intellij.openapi.vcs.changes.ContentRevision;
-import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
 import com.intellij.openapi.vcs.history.VcsFileRevision;
 import com.intellij.openapi.vcs.history.VcsRevisionNumber;
 import com.intellij.openapi.vcs.impl.AbstractVcsHelperImpl;
@@ -35,7 +34,6 @@ import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.text.DateFormatUtil;
 import com.intellij.vcs.log.VcsUser;
 import com.intellij.vcsUtil.VcsUtil;
-import com.intellij.xml.util.XmlStringUtil;
 import git4idea.GitContentRevision;
 import git4idea.GitFileRevision;
 import git4idea.GitRevisionNumber;
@@ -168,40 +166,23 @@ public class GitFileAnnotation extends FileAnnotation {
     LineInfo lineInfo = getLineInfo(lineNumber);
     if (lineInfo == null) return null;
 
-    StringBuilder sb = new StringBuilder();
+    AnnotationTooltipBuilder atb = new AnnotationTooltipBuilder(myProject, asHtml);
     GitRevisionNumber revisionNumber = lineInfo.getRevisionNumber();
 
-    String revisionLink = asHtml ? GitCommitTooltipLinkHandler.createLink(revisionNumber.asString(), revisionNumber) : null;
-    if (revisionLink != null) {
-      sb.append("commit ").append(revisionLink);
-    }
-    else {
-      appendLine(sb, asHtml, "commit " + revisionNumber.asString());
-    }
-
-    appendLine(sb, asHtml, "Author: " + lineInfo.getAuthor());
-    appendLine(sb, asHtml, "Date: " + DateFormatUtil.formatDateTime(lineInfo.getAuthorDate()));
+    atb.appendRevisionLine(revisionNumber, it -> GitCommitTooltipLinkHandler.createLink(it.asString(), it));
+    atb.appendLine("Author: " + lineInfo.getAuthor());
+    atb.appendLine("Date: " + DateFormatUtil.formatDateTime(lineInfo.getAuthorDate()));
 
     if (!myFilePath.equals(lineInfo.myFilePath)) {
       String path = FileUtil.getLocationRelativeToUserHome(lineInfo.myFilePath.getPresentableUrl());
-      appendLine(sb, asHtml, "Path: " + path);
+      atb.appendLine("Path: " + path);
     }
 
     String commitMessage = getCommitMessage(revisionNumber);
     if (commitMessage == null) commitMessage = lineInfo.getSubject() + "\n...";
-    if (asHtml) {
-      sb.append("\n\n").append(IssueLinkHtmlRenderer.formatTextWithLinks(myProject, commitMessage));
-    }
-    else {
-      sb.append("\n\n").append(VcsUtil.trimCommitMessageToSaneSize(commitMessage));
-    }
-
-    return sb.toString();
-  }
+    atb.appendCommitMessageBlock(commitMessage);
 
-  private static void appendLine(@NotNull StringBuilder sb, boolean asHtml, @NotNull String content) {
-    if (sb.length() != 0) sb.append('\n');
-    sb.append(asHtml ? XmlStringUtil.escapeString(content) : content);
+    return atb.toString();
   }
 
   @Nullable
index b3b3b65e710c9ac85f38d682b8fc4805f0b50bbd..4d467e9823be84726210de6b26a67e2a98aa13a6 100644 (file)
@@ -136,7 +136,6 @@ hg4idea.exception.file.not.under.hg=The file {0} is not under Mercurial.
 
 hg4idea.changelist.column.branch=Branch
 
-hg4idea.annotation.tool.tip=commit {0}\nAuthor: {1}\nDate: {2}\n\n{3}
 hg4idea.push.asNewBranch=push as &new remote branch
 hg4idea.push.bookmark=Book&mark
 
index e3ad3b5aad88ff13d1766dd4d90ba579c08c7fde..45f28edd3af71b627144fc58fff97594b0bffde2 100644 (file)
@@ -18,17 +18,21 @@ package org.zmlx.hg4idea.provider.annotate;
 
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vcs.VcsKey;
-import com.intellij.openapi.vcs.annotate.*;
+import com.intellij.openapi.vcs.annotate.FileAnnotation;
+import com.intellij.openapi.vcs.annotate.LineAnnotationAspect;
+import com.intellij.openapi.vcs.annotate.LineAnnotationAspectAdapter;
+import com.intellij.openapi.vcs.annotate.ShowAllAffectedGenericAction;
 import com.intellij.openapi.vcs.history.VcsFileRevision;
 import com.intellij.openapi.vcs.history.VcsRevisionNumber;
 import com.intellij.openapi.vfs.LocalFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.containers.ContainerUtil;
+import git4idea.annotate.AnnotationTooltipBuilder;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.zmlx.hg4idea.HgFile;
 import org.zmlx.hg4idea.HgFileRevision;
 import org.zmlx.hg4idea.HgVcs;
-import org.zmlx.hg4idea.HgVcsMessages;
 
 import java.util.Date;
 import java.util.LinkedList;
@@ -80,9 +84,20 @@ public class HgAnnotation extends FileAnnotation {
     };
   }
 
-  @Override
   @Nullable
+  @Override
   public String getToolTip(int lineNumber) {
+    return getToolTip(lineNumber, false);
+  }
+
+  @Nullable
+  @Override
+  public String getHtmlToolTip(int lineNumber) {
+    return getToolTip(lineNumber, true);
+  }
+
+  @Nullable
+  private String getToolTip(int lineNumber, boolean asHtml) {
     if ( myLines.size() <= lineNumber || lineNumber < 0 ) {
       return null;
     }
@@ -91,14 +106,16 @@ public class HgAnnotation extends FileAnnotation {
       return null;
     }
 
-    for (HgFileRevision revision : myFileRevisions) {
-      if (revision.getRevisionNumber().equals(info.getVcsRevisionNumber())) {
-        return HgVcsMessages.message("hg4idea.annotation.tool.tip", revision.getRevisionNumber().asString(),
-                                      revision.getAuthor(), revision.getRevisionDate(), revision.getCommitMessage());
-      }
-    }
+    HgFileRevision revision = ContainerUtil.find(myFileRevisions, it -> it.getRevisionNumber().equals(info.getVcsRevisionNumber()));
+    if (revision == null) return null;
 
-    return null;
+    AnnotationTooltipBuilder atb = new AnnotationTooltipBuilder(myProject, asHtml);
+    atb.appendRevisionLine(revision.getRevisionNumber(), null);
+    atb.appendLine("Author: " + revision.getAuthor());
+    atb.appendLine("Date: " + revision.getRevisionDate());
+    String message = revision.getCommitMessage();
+    if (message != null) atb.appendCommitMessageBlock(message);
+    return atb.toString();
   }
 
   @Override
index c6929da8b95faaca4077d88fc929586a5c1532cb..58bcbf092713cf9c3376a8e7da5d664cf687e024 100644 (file)
@@ -7,6 +7,7 @@ import com.intellij.openapi.vcs.history.VcsFileRevision;
 import com.intellij.openapi.vcs.history.VcsRevisionNumber;
 import com.intellij.util.text.DateFormatUtil;
 import com.intellij.xml.util.XmlStringUtil;
+import git4idea.annotate.AnnotationTooltipBuilder;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.idea.svn.SvnBundle;
@@ -113,18 +114,30 @@ public abstract class BaseSvnFileAnnotation extends FileAnnotation {
     return new LineAnnotationAspect[]{REVISION_ASPECT, DATE_ASPECT, AUTHOR_ASPECT};
   }
 
+  @Nullable
+  @Override
+  public String getToolTip(int lineNumber) {
+    return getToolTip(lineNumber, false);
+  }
+
+  @Nullable
   @Override
-  public String getToolTip(final int lineNumber) {
+  public String getHtmlToolTip(int lineNumber) {
+    return getToolTip(lineNumber, true);
+  }
+
+  @Nullable
+  private String getToolTip(int lineNumber, boolean asHtml) {
     final CommitInfo info = myInfos.getOrNull(lineNumber);
-    if (info == null) return "";
+    if (info == null) return null;
 
     SvnFileRevision revision = myRevisionMap.get(info.getRevisionNumber());
-    if (revision != null) {
-      String prefix = myInfos.getAnnotationSource(lineNumber).showMerged() ? "Merge source revision" : "Revision";
+    if (revision == null) return null;
 
-      return prefix + " " + info.getRevisionNumber() + ": " + revision.getCommitMessage();
-    }
-    return "";
+    String prefix = myInfos.getAnnotationSource(lineNumber).showMerged() ? "Merge source revision" : "Revision";
+    return AnnotationTooltipBuilder.buildSimpleTooltip(getProject(), asHtml, prefix,
+                                                       String.valueOf(info.getRevisionNumber()),
+                                                       revision.getCommitMessage());
   }
 
   @Override