IDEA-267354 git: show 'Merge' action on hover in Local Changes
authorAleksey Pivovarov <AMPivovarov@gmail.com>
Tue, 27 Apr 2021 20:35:27 +0000 (23:35 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Wed, 5 May 2021 15:27:41 +0000 (15:27 +0000)
GitOrigin-RevId: 5a5f1a9153cecc9080561967ba5f8268c004f588

platform/vcs-impl/resources/META-INF/VcsExtensionPoints.xml
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewNodeAction.java [new file with mode: 0644]
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewPanel.kt
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java
plugins/git4idea/resources/META-INF/plugin.xml
plugins/git4idea/resources/messages/GitBundle.properties
plugins/git4idea/src/git4idea/merge/GitChangesViewNodeAction.kt [new file with mode: 0644]

index 76bb7293d138fac7010cecd5d11f8766dfaeb51d..015d74d796bc979a29a464b26a893ced2062185d 100644 (file)
                     interface="com.intellij.openapi.vcs.changes.ChangesViewModifier"
                     area="IDEA_PROJECT"
                     dynamic="true"/>
+    <extensionPoint name="vcs.changes.changesViewNodeAction"
+                    interface="com.intellij.openapi.vcs.changes.ChangesViewNodeAction"
+                    area="IDEA_PROJECT"
+                    dynamic="true"/>
     <extensionPoint name="editChangelistSupport"
                     interface="com.intellij.openapi.vcs.changes.ui.EditChangelistSupport"
                     area="IDEA_PROJECT"/>
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewNodeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesViewNodeAction.java
new file mode 100644 (file)
index 0000000..9411ae8
--- /dev/null
@@ -0,0 +1,17 @@
+// 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 com.intellij.openapi.vcs.changes;
+
+import com.intellij.openapi.extensions.ProjectExtensionPointName;
+import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode;
+import com.intellij.openapi.vcs.changes.ui.HoverIcon;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@ApiStatus.Experimental
+public interface ChangesViewNodeAction {
+  ProjectExtensionPointName<ChangesViewNodeAction> EP_NAME = new ProjectExtensionPointName<>("com.intellij.vcs.changes.changesViewNodeAction");
+
+  @Nullable
+  HoverIcon createNodeHoverIcon(@NotNull ChangesBrowserNode<?> node);
+}
index 21b79c426954c270f28d61a64cf51c860b8511ad..be1c177c7a78a52721028d7fcdcf69cdaf5f832f 100644 (file)
@@ -8,7 +8,9 @@ import com.intellij.openapi.actionSystem.ActionPlaces.CHANGES_VIEW_TOOLBAR
 import com.intellij.openapi.actionSystem.ActionToolbar
 import com.intellij.openapi.actionSystem.DefaultActionGroup
 import com.intellij.openapi.project.Project
+import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode
 import com.intellij.openapi.vcs.changes.ui.ChangesListView
+import com.intellij.openapi.vcs.changes.ui.HoverIcon
 import com.intellij.ui.IdeBorderFactory.createBorder
 import com.intellij.ui.JBColor
 import com.intellij.ui.ScrollPaneFactory.createScrollPane
@@ -25,7 +27,7 @@ import javax.swing.SwingConstants
 import kotlin.properties.Delegates.observable
 
 class ChangesViewPanel(project: Project) : BorderLayoutPanel() {
-  val changesView: ChangesListView = ChangesListView(project, false).apply {
+  val changesView: ChangesListView = MyChangesListView(project).apply {
     treeExpander = object : DefaultTreeExpander(this) {
       override fun collapseAll(tree: JTree, keepSelectionLevel: Int) {
         super.collapseAll(tree, 2)
@@ -83,4 +85,10 @@ class ChangesViewPanel(project: Project) : BorderLayoutPanel() {
       addToLeft(toolbar.component)
     }
   }
+
+  private class MyChangesListView(project: Project) : ChangesListView(project, false) {
+    override fun getHoverIcon(node: ChangesBrowserNode<*>): HoverIcon? {
+      return ChangesViewNodeAction.EP_NAME.computeSafeIfAny(project) { it.createNodeHoverIcon(node) }
+    }
+  }
 }
index 2a5ff90be38deda28c0ec487a46f590b0164a125..04d00e6572131299c0262fc0af2b2de2e01a2bd1 100644 (file)
@@ -40,7 +40,7 @@ import static com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode.*;
 import static com.intellij.vcs.commit.ChangesViewCommitPanelKt.subtreeRootObject;
 
 // TODO: Check if we could extend DnDAwareTree here instead of directly implementing DnDAware
-public class ChangesListView extends ChangesTree implements DataProvider, DnDAware {
+public class ChangesListView extends HoverChangesTree implements DataProvider, DnDAware {
   @NonNls public static final String HELP_ID = "ideaInterface.changes";
   @NonNls public static final DataKey<ChangesListView> DATA_KEY = DataKey.create("ChangeListView");
   @NonNls public static final DataKey<Iterable<FilePath>> UNVERSIONED_FILE_PATHS_DATA_KEY = DataKey.create("ChangeListView.UnversionedFiles");
@@ -75,6 +75,12 @@ public class ChangesListView extends ChangesTree implements DataProvider, DnDAwa
     return false;
   }
 
+  @Nullable
+  @Override
+  public HoverIcon getHoverIcon(@NotNull ChangesBrowserNode<?> node) {
+    return null;
+  }
+
   @Override
   public DefaultTreeModel getModel() {
     return (DefaultTreeModel)super.getModel();
index 52574f26124743bdb8969e189b805b0337f5299e..825a68db093375748420f4c14f37beeea4c4382a 100644 (file)
                         preloaderClassName="git4idea.index.GitStageContentPreloader"
                         displayNameSupplierClassName="git4idea.index.GitStageDisplayNameSupplier"
                         isInCommitToolWindow="true"/>
+    <vcs.changes.changesViewNodeAction implementation="git4idea.merge.GitChangesViewNodeAction"/>
     <projectService serviceImplementation="git4idea.index.ui.GitStageUiSettingsImpl"/>
 
     <projectService serviceImplementation="git4idea.index.GitStageTracker"/>
index 7184450f3dae1dc21abbec4c82ac3251be40175b..1d2d32cafe8786ae302761fc707c9b9ab3ec24b8 100644 (file)
@@ -809,6 +809,7 @@ stage.vfs.editor.tab.tooltip=Staged Version of ''{0}''
 stage.vfs.editor.notification.text=This is a staged version of ''{0}''
 stage.vfs.editor.notification.link=Open local version
 stage.diff.local.content.exception.message=Cannot get local file: ''{0}''
+changes.view.merge.action.text=Merge
 
 action.Git.Show.Stage.text=Commit...
 action.Git.Stage.Add.All.text=Stage All
diff --git a/plugins/git4idea/src/git4idea/merge/GitChangesViewNodeAction.kt b/plugins/git4idea/src/git4idea/merge/GitChangesViewNodeAction.kt
new file mode 100644 (file)
index 0000000..e5a4b5b
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2000-2021 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.merge
+
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vcs.FileStatus
+import com.intellij.openapi.vcs.changes.Change
+import com.intellij.openapi.vcs.changes.ChangesUtil
+import com.intellij.openapi.vcs.changes.ChangesViewNodeAction
+import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode
+import com.intellij.openapi.vcs.changes.ui.HoverIcon
+import git4idea.conflicts.showMergeWindow
+import git4idea.i18n.GitBundle
+import git4idea.index.ui.createMergeHandler
+import git4idea.index.ui.isReversedRoot
+import git4idea.repo.GitRepositoryManager
+
+class GitChangesViewNodeAction(val project: Project) : ChangesViewNodeAction {
+  override fun createNodeHoverIcon(node: ChangesBrowserNode<*>): HoverIcon? {
+    val change = node.userObject as? Change ?: return null
+    if (change.fileStatus != FileStatus.MERGED_WITH_CONFLICTS) return null
+
+    val path = ChangesUtil.getFilePath(change)
+    val stagingAreaHolder = GitRepositoryManager.getInstance(project).getRepositoryForFileQuick(path)?.stagingAreaHolder
+    if (stagingAreaHolder?.findConflict(path) == null) return null
+
+    return GitMergeHoverIcon(project)
+  }
+
+  private data class GitMergeHoverIcon(val project: Project)
+    : HoverIcon(AllIcons.Vcs.Merge, GitBundle.message("changes.view.merge.action.text")) {
+    override fun invokeAction(node: ChangesBrowserNode<*>) {
+      val change = node.userObject as? Change ?: return
+
+      val path = ChangesUtil.getFilePath(change)
+      val stagingAreaHolder = GitRepositoryManager.getInstance(project).getRepositoryForFileQuick(path)?.stagingAreaHolder
+      val conflict = stagingAreaHolder?.findConflict(path) ?: return
+
+      showMergeWindow(project, createMergeHandler(project), listOf(conflict), project::isReversedRoot)
+    }
+  }
+}
\ No newline at end of file