git-index: support navigation between files in diff

GitOrigin-RevId: 49bb4d7607a7b812387ee736232cc59cf1b826cc
This commit is contained in:
Aleksey Pivovarov
2020-09-28 16:11:26 +00:00
committed by intellij-monorepo-bot
parent 70bef3e687
commit 709cabb3b5
2 changed files with 49 additions and 12 deletions
@@ -11,31 +11,35 @@ import com.intellij.util.containers.isEmpty
import git4idea.index.createThreeSidesDiffRequestProducer
import git4idea.index.createTwoSidesDiffRequestProducer
import git4idea.index.ui.GIT_FILE_STATUS_NODES_STREAM
import git4idea.index.ui.GIT_STAGE_TRACKER
import kotlin.streams.toList
import git4idea.index.ui.GIT_STAGE_TREE
class GitStageDiffAction : AnActionExtensionProvider {
override fun isActive(e: AnActionEvent): Boolean = e.getData(GIT_STAGE_TRACKER) != null
override fun isActive(e: AnActionEvent): Boolean = e.getData(GIT_STAGE_TREE) != null
override fun update(e: AnActionEvent) {
e.presentation.isEnabled = e.project != null && !e.getData(GIT_FILE_STATUS_NODES_STREAM).isEmpty()
e.presentation.isEnabled = e.project != null &&
!e.getData(GIT_FILE_STATUS_NODES_STREAM).isEmpty()
e.presentation.isVisible = e.presentation.isEnabled || e.isFromActionToolbar
}
override fun actionPerformed(e: AnActionEvent) {
val producers = e.getRequiredData(GIT_FILE_STATUS_NODES_STREAM).map { createTwoSidesDiffRequestProducer(e.project!!, it) }.toList()
DiffManager.getInstance().showDiff(e.project, ChangeDiffRequestChain(producers, 0), DiffDialogHints.DEFAULT)
val producers = e.getRequiredData(GIT_STAGE_TREE).statusNodesListSelection(true)
.map { createTwoSidesDiffRequestProducer(e.project!!, it) }
DiffManager.getInstance().showDiff(e.project, ChangeDiffRequestChain(producers.list, producers.selectedIndex), DiffDialogHints.DEFAULT)
}
}
class GitStageThreeSideDiffAction : DumbAwareAction() {
override fun update(e: AnActionEvent) {
e.presentation.isEnabled = e.project != null && !e.getData(GIT_FILE_STATUS_NODES_STREAM).isEmpty()
e.presentation.isEnabled = e.project != null &&
e.getData(GIT_STAGE_TREE) != null &&
!e.getData(GIT_FILE_STATUS_NODES_STREAM).isEmpty()
e.presentation.isVisible = e.presentation.isEnabled || e.isFromActionToolbar
}
override fun actionPerformed(e: AnActionEvent) {
val producers = e.getRequiredData(GIT_FILE_STATUS_NODES_STREAM).map { createThreeSidesDiffRequestProducer(e.project!!, it) }.toList()
DiffManager.getInstance().showDiff(e.project, ChangeDiffRequestChain(producers, 0), DiffDialogHints.DEFAULT)
val producers = e.getRequiredData(GIT_STAGE_TREE).statusNodesListSelection(false)
.map { createThreeSidesDiffRequestProducer(e.project!!, it) }
DiffManager.getInstance().showDiff(e.project, ChangeDiffRequestChain(producers.list, producers.selectedIndex), DiffDialogHints.DEFAULT)
}
}
@@ -6,6 +6,7 @@ import com.intellij.ide.dnd.DnDDragStartBean
import com.intellij.ide.dnd.DnDEvent
import com.intellij.ide.util.treeView.TreeState
import com.intellij.openapi.Disposable
import com.intellij.openapi.ListSelection
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataKey
import com.intellij.openapi.actionSystem.PlatformDataKeys
@@ -27,6 +28,7 @@ import com.intellij.ui.ClickListener
import com.intellij.ui.SimpleTextAttributes
import com.intellij.ui.components.JBLabel
import com.intellij.util.FontUtil
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.isEmpty
import git4idea.conflicts.getConflictType
import git4idea.i18n.GitBundle
@@ -50,6 +52,7 @@ import javax.swing.tree.TreePath
import kotlin.streams.toList
val GIT_FILE_STATUS_NODES_STREAM = DataKey.create<Stream<GitFileStatusNode>>("GitFileStatusNodesStream")
val GIT_STAGE_TREE = DataKey.create<GitStageTree>("GitStageTree")
abstract class GitStageTree(project: Project, parentDisposable: Disposable) : ChangesTree(project, false, true) {
private var hoverNode: ChangesBrowserNode<*>? = null
@@ -113,6 +116,7 @@ abstract class GitStageTree(project: Project, parentDisposable: Disposable) : Ch
override fun getData(dataId: String): Any? {
return when {
GIT_STAGE_TREE.`is`(dataId) -> this
GIT_FILE_STATUS_NODES_STREAM.`is`(dataId) -> selectedStatusNodes()
VcsDataKeys.FILE_PATH_STREAM.`is`(dataId) -> selectedStatusNodes().map { it.filePath }
VcsDataKeys.VIRTUAL_FILE_STREAM.`is`(dataId) -> selectedStatusNodes().map { it.filePath.virtualFile }.filter { it != null }
@@ -126,11 +130,40 @@ abstract class GitStageTree(project: Project, parentDisposable: Disposable) : Ch
}
fun selectedStatusNodes(): Stream<GitFileStatusNode> {
return VcsTreeModelData.selected(this).userObjectsStream()
.filter { it is GitFileStatusNode }
.map { it as GitFileStatusNode }
return VcsTreeModelData.selected(this).userObjectsStream(GitFileStatusNode::class.java)
}
fun statusNodesListSelection(preferLimitedContext: Boolean): ListSelection<GitFileStatusNode> {
val entries = VcsTreeModelData.selected(this).userObjects(GitFileStatusNode::class.java)
if (entries.size > 1) {
return ListSelection.createAt(entries, 0)
}
val selected = entries.singleOrNull()
val selectedKind = selected?.kind
val allEntriesData: VcsTreeModelData = when {
preferLimitedContext && (selectedKind == NodeKind.UNSTAGED || selectedKind == NodeKind.UNTRACKED) -> {
VcsTreeModelData.allUnderTag(this, NodeKind.UNSTAGED)
}
preferLimitedContext && selectedKind == NodeKind.STAGED -> {
VcsTreeModelData.allUnderTag(this, NodeKind.STAGED)
}
else -> {
VcsTreeModelData.all(this)
}
}
val allEntries = allEntriesData.userObjects(GitFileStatusNode::class.java)
return if (allEntries.size <= entries.size) {
ListSelection.createAt(entries, 0)
}
else {
ListSelection.create(allEntries, selected)
}
}
private inner class MyTreeModelBuilder internal constructor(project: Project, grouping: ChangesGroupingPolicyFactory)
: TreeModelBuilder(project, grouping) {
private val parentNodes: MutableMap<NodeKind, ChangesBrowserKindNode> = mutableMapOf()