diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryPanel.java index 7f704ac3b9ac..ee68c478b618 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/history/FileHistoryPanel.java @@ -30,8 +30,10 @@ import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.data.VcsLogData; import com.intellij.vcs.log.impl.CommonUiProperties; import com.intellij.vcs.log.util.VcsLogUtil; +import com.intellij.vcs.log.impl.VcsProjectLog; import com.intellij.vcs.log.ui.VcsLogActionPlaces; import com.intellij.vcs.log.ui.VcsLogInternalDataKeys; +import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.frame.DetailsPanel; import com.intellij.vcs.log.ui.table.VcsLogGraphTable; import com.intellij.vcs.log.util.VcsLogUiUtil; @@ -76,7 +78,15 @@ public class FileHistoryPanel extends JPanel implements DataProvider, Disposable myGraphTable.setCompactReferencesView(true); myGraphTable.setShowTagNames(false); - myDetailsPanel = new DetailsPanel(logData, myUi.getColorManager(), this); + myDetailsPanel = new DetailsPanel(logData, myUi.getColorManager(), this) { + @Override + protected void navigate(@NotNull String hash) { + VcsLogUiImpl mainLogUi = VcsProjectLog.getInstance(logData.getProject()).getMainLogUi(); + if (mainLogUi != null) { + mainLogUi.getVcsLog().jumpToReference(hash); + } + } + }; myDetailsPanel.setBorder(IdeBorderFactory.createBorder(SideBorder.LEFT)); myDetailsSplitter = new OnePixelSplitter(true, "vcs.log.history.details.splitter.proportion", 0.7f); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/CommitPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/CommitPanel.java index 3f14b3361c28..f4ab068971b5 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/CommitPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/CommitPanel.java @@ -19,14 +19,15 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer; import com.intellij.openapi.vcs.ui.FontUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.BrowserHyperlinkListener; import com.intellij.ui.ColorUtil; import com.intellij.ui.JBColor; import com.intellij.ui.UI; import com.intellij.ui.components.JBPanel; import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.*; @@ -51,14 +52,18 @@ import javax.swing.text.html.StyleSheet; import java.awt.*; import java.util.Collection; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer.formatTextWithLinks; import static com.intellij.openapi.vcs.history.VcsHistoryUtil.getCommitDetailsFont; public class CommitPanel extends JBPanel { public static final int BOTTOM_BORDER = 2; private static final int REFERENCES_BORDER = 12; private static final int TOP_BORDER = 4; + private static final Pattern HASH_PATTERN = Pattern.compile("[0-9a-f]{7,40}", Pattern.CASE_INSENSITIVE); @NotNull private final VcsLogData myLogData; @@ -68,12 +73,14 @@ public class CommitPanel extends JBPanel { @NotNull private final BranchesPanel myContainingBranchesPanel; @NotNull private final RootPanel myRootPanel; @NotNull private final VcsLogColorManager myColorManager; + @NotNull private final Consumer myNavigate; @Nullable private VcsFullCommitDetails myCommit; - public CommitPanel(@NotNull VcsLogData logData, @NotNull VcsLogColorManager colorManager) { + public CommitPanel(@NotNull VcsLogData logData, @NotNull VcsLogColorManager colorManager, @NotNull Consumer navigate) { myLogData = logData; myColorManager = colorManager; + myNavigate = navigate; setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false)); setOpaque(false); @@ -181,7 +188,8 @@ public class CommitPanel extends JBPanel { return " on " + DateFormatUtil.formatDate(time) + " at " + DateFormatUtil.formatTime(time); } - private static class DataPanel extends HtmlPanel { + private class DataPanel extends HtmlPanel { + private static final String GO_TO_HASH = "go-to-hash:"; @NotNull private final Project myProject; @Nullable private String myMainText; @@ -200,6 +208,15 @@ public class CommitPanel extends JBPanel { update(); } + @Override + public void hyperlinkUpdate(@NotNull HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED && e.getDescription().startsWith(GO_TO_HASH)) { + myNavigate.consume(e.getDescription().substring(GO_TO_HASH.length())); + } else { + BrowserHyperlinkListener.INSTANCE.hyperlinkUpdate(e); + } + } + void setData(@Nullable VcsFullCommitDetails commit) { if (commit == null) { myMainText = null; @@ -222,12 +239,12 @@ public class CommitPanel extends JBPanel { } @NotNull - private static String getHtmlWithFonts(@NotNull String input) { + private String getHtmlWithFonts(@NotNull String input) { return getHtmlWithFonts(input, getCommitDetailsFont().getStyle()); } @NotNull - private static String getHtmlWithFonts(@NotNull String input, int style) { + private String getHtmlWithFonts(@NotNull String input, int style) { return FontUtil.getHtmlWithFonts(input, style, getCommitDetailsFont()); } @@ -255,13 +272,13 @@ public class CommitPanel extends JBPanel { String subject = separator > 0 ? fullMessage.substring(0, separator) : fullMessage; String description = fullMessage.substring(subject.length()); return "" + - getHtmlWithFonts(escapeMultipleSpaces(IssueLinkHtmlRenderer.formatTextWithLinks(myProject, subject)), Font.BOLD) + + getHtmlWithFonts(escapeMultipleSpaces(formatTextWithLinks(myProject, subject, this::replaceHashes)), Font.BOLD) + "" + - getHtmlWithFonts(escapeMultipleSpaces(IssueLinkHtmlRenderer.formatTextWithLinks(myProject, description))); + getHtmlWithFonts(escapeMultipleSpaces(formatTextWithLinks(myProject, description, this::replaceHashes))); } @NotNull - private static String escapeMultipleSpaces(@NotNull String text) { + private String escapeMultipleSpaces(@NotNull String text) { StringBuilder result = new StringBuilder(); for (int i = 0; i < text.length(); i++) { if (text.charAt(i) == ' ') { @@ -280,7 +297,7 @@ public class CommitPanel extends JBPanel { } @NotNull - private static String getAuthorText(@NotNull VcsFullCommitDetails commit, int offset) { + private String getAuthorText(@NotNull VcsFullCommitDetails commit, int offset) { long authorTime = commit.getAuthorTime(); long commitTime = commit.getCommitTime(); @@ -302,7 +319,7 @@ public class CommitPanel extends JBPanel { } @NotNull - private static String getCommitterText(@Nullable VcsUser committer, @NotNull String commitTimeText, int offset) { + private String getCommitterText(@Nullable VcsUser committer, @NotNull String commitTimeText, int offset) { String alignment = "
" + StringUtil.repeat(" ", offset); String gray = ColorUtil.toHex(JBColor.GRAY); @@ -320,13 +337,13 @@ public class CommitPanel extends JBPanel { } @NotNull - private static String getAuthorName(@NotNull VcsUser user) { + private String getAuthorName(@NotNull VcsUser user) { String username = VcsUserUtil.getShortPresentation(user); return user.getEmail().isEmpty() ? username : username + getEmailText(user); } @NotNull - private static String getEmailText(@NotNull VcsUser user) { + private String getEmailText(@NotNull VcsUser user) { return " <" + user.getEmail() + ">"; } @@ -334,6 +351,20 @@ public class CommitPanel extends JBPanel { public Color getBackground() { return getCommitDetailsBackground(); } + + @NotNull + private String replaceHashes(@NotNull String s) { + Matcher matcher = HASH_PATTERN.matcher(s); + StringBuffer result = new StringBuffer(); + + while (matcher.find()) { + String hash = matcher.group(); + matcher.appendReplacement(result, "" + hash + ""); + } + matcher.appendTail(result); + + return result.toString(); + } } private static class BranchesPanel extends HtmlPanel { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 04969a40f309..ae9927051979 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -125,6 +125,9 @@ public class DetailsPanel extends JPanel implements EditorColorsListener { } } + protected void navigate(@NotNull String hash) { + } + private void rebuildCommitPanels(int[] selection) { myEmptyText.setText(""); @@ -137,7 +140,7 @@ public class DetailsPanel extends JPanel implements EditorColorsListener { if (i > 0) { myMainContentPanel.add(new SeparatorComponent(0, OnePixelDivider.BACKGROUND, null)); } - myMainContentPanel.add(new CommitPanel(myLogData, myColorManager)); + myMainContentPanel.add(new CommitPanel(myLogData, myColorManager, this::navigate)); } // clear superfluous items diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index 2fd5312ceb68..675c5a3c25f5 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -89,7 +89,12 @@ public class MainFrame extends JPanel implements DataProvider, Disposable { myGraphTable.setCompactReferencesView(myUiProperties.get(MainVcsLogUiProperties.COMPACT_REFERENCES_VIEW)); myGraphTable.setShowTagNames(myUiProperties.get(MainVcsLogUiProperties.SHOW_TAG_NAMES)); PopupHandler.installPopupHandler(myGraphTable, VcsLogActionPlaces.POPUP_ACTION_GROUP, VcsLogActionPlaces.VCS_LOG_TABLE_PLACE); - myDetailsPanel = new DetailsPanel(logData, ui.getColorManager(), this); + myDetailsPanel = new DetailsPanel(logData, ui.getColorManager(), this) { + @Override + protected void navigate(@NotNull String hash) { + myLog.jumpToReference(hash); + } + }; myChangesBrowser = new VcsLogChangesBrowser(project, myUiProperties, (commitId) -> { int index = myLogData.getCommitIndex(commitId.getHash(), commitId.getRoot());