diff --git a/src/main/kotlin/org/arend/ArendIcons.kt b/src/main/kotlin/org/arend/ArendIcons.kt index e866178e7..ee5a0f0a2 100644 --- a/src/main/kotlin/org/arend/ArendIcons.kt +++ b/src/main/kotlin/org/arend/ArendIcons.kt @@ -41,7 +41,7 @@ object ArendIcons { val TURNSTILE = getIcon("/icons/turnstile.svg") val CHECKMARK = getIcon("/icons/checkmark.svg") - val GRAPH = getIcon("/icons/graph.svg") + val ORTHOGONAL_GRAPH = getIcon("/icons/orthogonal_graph.svg") // Source code elements diff --git a/src/main/kotlin/org/arend/actions/ArendDefinitionInverseDependenciesGraphAction.kt b/src/main/kotlin/org/arend/actions/ArendDefinitionInverseDependenciesGraphAction.kt new file mode 100644 index 000000000..6eba545c8 --- /dev/null +++ b/src/main/kotlin/org/arend/actions/ArendDefinitionInverseDependenciesGraphAction.kt @@ -0,0 +1,94 @@ +package org.arend.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import org.arend.ArendIcons +import org.arend.graph.GraphEdge +import org.arend.graph.GraphNode +import org.arend.graph.GraphSimulator +import org.arend.psi.ext.* + +class ArendDefinitionInverseDependenciesGraphAction : AnAction(ArendIcons.ORTHOGONAL_GRAPH) { + + private val usedNodes = mutableSetOf() + private val edges = mutableSetOf() + + private fun findEdge(nameFrom: String, element: PsiElement) { + element.accept(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + if (element is ArendReferenceElement) { + val resolve = element.resolve + if (resolve is ArendDefinition<*>) { + val nameTo = resolve.getName() + if (nameTo != null) { + edges.add(GraphEdge(nameFrom, nameTo)) + if (!usedNodes.contains(nameTo)) { + findEdges(resolve) + } + } + } + } + element.children.forEach { it.accept(this) } + } + }) + } + + private fun findEdges(definition: ArendDefinition<*>, optionalNameFrom: String? = null) { + val nameFrom = optionalNameFrom ?: definition.getName() ?: return + usedNodes.add(nameFrom) + + for (param in definition.parametersExt) { + (param.type as? PsiElement?)?.let { findEdge(nameFrom, it) } + } + when (definition) { + is ArendFunctionDefinition -> { + definition.returnExpr?.let { findEdge(nameFrom, it) } + definition.body?.let { findEdge(nameFrom, it) } + } + is ArendDefClass -> { + definition.fields.forEach { findEdge(nameFrom, it) } + if (optionalNameFrom == null) { + definition.superClassList.forEach { findEdges(it.longName.resolve as ArendDefinition<*>, nameFrom) } + } else { + definition.superClassList.forEach { findEdges(it.longName.resolve as ArendDefinition<*>, optionalNameFrom) } + } + } + is ArendDefData -> definition.dataBody?.let { findEdge(nameFrom, it) } + is ArendDefMeta -> definition.expr?.let { findEdge(nameFrom, it) } + } + } + + override fun actionPerformed(e: AnActionEvent) { + usedNodes.clear() + edges.clear() + + val definition = getArendDefinition(e) as? ArendDefinition<*> ?: return + findEdges(definition) + + val graphSimulator = GraphSimulator(this.toString(), edges, usedNodes.map { GraphNode(it) }.toSet()) + graphSimulator.displayOrthogonal() + } + + override fun update(e: AnActionEvent) { + e.presentation.isEnabled = getArendDefinition(e) != null + } + + private fun getArendDefinition(e: AnActionEvent): PsiElement? { + val editor = e.getData(PlatformDataKeys.EDITOR) + val psiFile = e.getData(PlatformDataKeys.PSI_FILE) + + if (editor == null || psiFile == null) { + return null + } + + val offset = editor.caretModel.offset + var currentPsiElement = psiFile.findElementAt(offset) + while (currentPsiElement != null && currentPsiElement !is ArendDefinition<*>) { + currentPsiElement = currentPsiElement.parent + } + return currentPsiElement + } +} diff --git a/src/main/kotlin/org/arend/graph/GraphSimulator.kt b/src/main/kotlin/org/arend/graph/GraphSimulator.kt index 67e16da6a..60f0cfa3c 100644 --- a/src/main/kotlin/org/arend/graph/GraphSimulator.kt +++ b/src/main/kotlin/org/arend/graph/GraphSimulator.kt @@ -12,17 +12,19 @@ import javax.swing.ImageIcon import javax.swing.JFrame import javax.swing.JLabel +data class GraphNode(val id: String) + data class GraphEdge(val from: String, val to: String) class GraphSimulator( - private val graphId: String, private val edges: Set, private val vertices: Set + private val graphId: String, private val edges: Set, private val vertices: Set ) { - fun display() { + fun displayOrthogonal() { var graph = graph(graphId).directed() for (vertex in vertices) { - graph = graph.with(node(vertex)) + graph = graph.with(node(vertex.id)) } for (edge in edges) { diff --git a/src/main/kotlin/org/arend/hierarchy/clazz/ArendClassHierarchyBrowser.kt b/src/main/kotlin/org/arend/hierarchy/clazz/ArendClassHierarchyBrowser.kt index e0a8d8339..475a8e615 100644 --- a/src/main/kotlin/org/arend/hierarchy/clazz/ArendClassHierarchyBrowser.kt +++ b/src/main/kotlin/org/arend/hierarchy/clazz/ArendClassHierarchyBrowser.kt @@ -21,6 +21,7 @@ import com.intellij.ui.tree.StructureTreeModel import com.intellij.util.ui.tree.TreeUtil import org.arend.ArendIcons import org.arend.graph.GraphEdge +import org.arend.graph.GraphNode import org.arend.graph.GraphSimulator import org.arend.hierarchy.ArendHierarchyNodeDescriptor import org.arend.psi.ext.ArendDefClass @@ -166,14 +167,14 @@ class ArendClassHierarchyBrowser(project: Project, method: PsiElement) : TypeHie } } - inner class ArendHierarchyGraphAction : AnAction(ArendIcons.GRAPH) { + inner class ArendHierarchyGraphAction : AnAction(ArendIcons.ORTHOGONAL_GRAPH) { private val usedNodes = mutableSetOf() + private val edges = mutableSetOf() - private fun findEdges(currentNode: DefaultMutableTreeNode): Set { + private fun findEdges(currentNode: DefaultMutableTreeNode) { usedNodes.add(currentNode) val from = ((currentNode.userObject as ArendHierarchyNodeDescriptor).psiElement as ArendDefClass).fullName - val edges = mutableSetOf() val children = TreeUtil.listChildren(currentNode) for (child in children) { @@ -182,25 +183,29 @@ class ArendClassHierarchyBrowser(project: Project, method: PsiElement) : TypeHie edges.add(GraphEdge(from, to)) if (!usedNodes.contains(child)) { - edges.addAll(findEdges(child)) + findEdges(child) } } - return edges } override fun actionPerformed(e: AnActionEvent) { + usedNodes.clear() + edges.clear() + val tree = getJTree(currentViewType) ?: return val root = tree.model.root as DefaultMutableTreeNode - usedNodes.clear() + findEdges(root) + val simulator = GraphSimulator( this.toString(), - findEdges(root), - usedNodes.map { (((it as DefaultMutableTreeNode).userObject as ArendHierarchyNodeDescriptor).psiElement as? ArendDefClass?)?.fullName!! } - .toSet() + edges, + usedNodes.map { + GraphNode( + (((it as DefaultMutableTreeNode).userObject as ArendHierarchyNodeDescriptor).psiElement as? ArendDefClass?)?.fullName!! + ) }.toSet() ) - - simulator.display() + simulator.displayOrthogonal() } } } diff --git a/src/main/kotlin/org/arend/module/ArendModuleDependenciesGraphAction.kt b/src/main/kotlin/org/arend/module/ArendModuleDependenciesGraphAction.kt index bee11e0d1..2435997f4 100644 --- a/src/main/kotlin/org/arend/module/ArendModuleDependenciesGraphAction.kt +++ b/src/main/kotlin/org/arend/module/ArendModuleDependenciesGraphAction.kt @@ -6,19 +6,21 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import org.arend.ArendIcons import org.arend.graph.GraphEdge +import org.arend.graph.GraphNode import org.arend.graph.GraphSimulator import org.arend.module.config.ArendModuleConfigService -class ArendModuleDependenciesGraphAction : AnAction(ArendIcons.GRAPH) { +class ArendModuleDependenciesGraphAction : AnAction(ArendIcons.ORTHOGONAL_GRAPH) { private val usedNodes = mutableSetOf() + private val edges = mutableSetOf() - private fun findEdges(currentNode: Module, modules: List): Set { + private fun findEdges(currentNode: Module, modules: List) { usedNodes.add(currentNode) val from = currentNode.name val edges = mutableSetOf() - val arendModuleConfigService = ArendModuleConfigService.getInstance(currentNode) ?: return emptySet() + val arendModuleConfigService = ArendModuleConfigService.getInstance(currentNode) ?: return val dependencyNames = arendModuleConfigService.dependencies.map { it.name } val children = modules.filter { dependencyNames.contains(it.name) } @@ -26,25 +28,24 @@ class ArendModuleDependenciesGraphAction : AnAction(ArendIcons.GRAPH) { edges.add(GraphEdge(from, child.name)) if (!usedNodes.contains(child)) { - edges.addAll(findEdges(child, modules)) + findEdges(child, modules) } } - return edges } override fun actionPerformed(e: AnActionEvent) { + usedNodes.clear() + edges.clear() + val moduleManager = e.project?.let { ModuleManager.getInstance(it) } ?: return val modules = moduleManager.modules.toList() - - usedNodes.clear() - val edges = mutableSetOf() for (module in modules) { if (!usedNodes.contains(module)) { - edges.addAll(findEdges(module, modules)) + findEdges(module, modules) } } - val simulator = GraphSimulator(this.toString(), edges, usedNodes.map { it.name }.toSet()) - simulator.display() + val simulator = GraphSimulator(this.toString(), edges, usedNodes.map { GraphNode(it.name) }.toSet()) + simulator.displayOrthogonal() } } diff --git a/src/main/kotlin/org/arend/psi/ext/ArendDefClass.kt b/src/main/kotlin/org/arend/psi/ext/ArendDefClass.kt index 9acc5d070..08a9612c0 100644 --- a/src/main/kotlin/org/arend/psi/ext/ArendDefClass.kt +++ b/src/main/kotlin/org/arend/psi/ext/ArendDefClass.kt @@ -46,6 +46,9 @@ class ArendDefClass : ArendDefinition, ClassReferable, TCDefi val extendsKw: PsiElement? get() = findChildByType(EXTENDS_KW) + override val parametersExt: List + get() = parameters + override fun getReferable() = this override fun isRecord(): Boolean = hasChildOfType(RECORD_KW) diff --git a/src/main/kotlin/org/arend/psi/ext/ArendDefMeta.kt b/src/main/kotlin/org/arend/psi/ext/ArendDefMeta.kt index aa2461a9d..c2bbc2aef 100644 --- a/src/main/kotlin/org/arend/psi/ext/ArendDefMeta.kt +++ b/src/main/kotlin/org/arend/psi/ext/ArendDefMeta.kt @@ -34,6 +34,9 @@ class ArendDefMeta : ArendDefinition, Abstract.MetaDefinition, tcReferableCache = value } + override val parametersExt: List + get() = parameters + override fun getDescription() = documentation?.toString() ?: "" private fun prepareTCRef(data: SmartPsiElementPointer?, parent: LocatedReferable?) = diff --git a/src/main/kotlin/org/arend/psi/ext/ArendDefinition.kt b/src/main/kotlin/org/arend/psi/ext/ArendDefinition.kt index e97569da7..c15e74ce8 100644 --- a/src/main/kotlin/org/arend/psi/ext/ArendDefinition.kt +++ b/src/main/kotlin/org/arend/psi/ext/ArendDefinition.kt @@ -74,7 +74,7 @@ where StubT : ArendNamedStub, StubT : StubElement<*> { return null } - protected open val parametersExt: List + open val parametersExt: List get() = emptyList() override fun getExternalParameters(): List { diff --git a/src/main/kotlin/org/arend/psi/ext/ArendFunctionDefinition.kt b/src/main/kotlin/org/arend/psi/ext/ArendFunctionDefinition.kt index 1e99b44bd..cba927799 100644 --- a/src/main/kotlin/org/arend/psi/ext/ArendFunctionDefinition.kt +++ b/src/main/kotlin/org/arend/psi/ext/ArendFunctionDefinition.kt @@ -30,6 +30,9 @@ where StubT : ArendNamedStub, StubT : StubElement<*> { val returnExpr: ArendReturnExpr? get() = childOfType() + override val parametersExt: List + get() = parameters + override fun getParameters(): List = getChildrenOfType() override fun getResultType() = returnExpr?.type diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 1ef442497..f715e3dca 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -461,7 +461,7 @@ + text="Show a Graph of Arend Modules"> @@ -563,6 +563,11 @@ + + + messages.ArendBundle diff --git a/src/main/resources/icons/graph.svg b/src/main/resources/icons/graph.svg deleted file mode 100644 index c38d84b8f..000000000 --- a/src/main/resources/icons/graph.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/src/main/resources/icons/orthogonal_graph.svg b/src/main/resources/icons/orthogonal_graph.svg new file mode 100644 index 000000000..f1448ba10 --- /dev/null +++ b/src/main/resources/icons/orthogonal_graph.svg @@ -0,0 +1,42 @@ + + + + + +