From 46fefbe18c4da15d6022032f4df4f3393e180c4a Mon Sep 17 00:00:00 2001 From: Anton Kozub Date: Wed, 3 Sep 2025 11:46:22 +0200 Subject: [PATCH] IDEA-378858 Rewrite Persistence TW using Logical Structure model GitOrigin-RevId: 16b1bdd15c36f99121da6ab46131e31c540c360e --- .../StructureViewComponent.java | 3 +- .../impl/LogicalStructureElementsVisitor.kt | 44 +++++++++++++++++++ .../logical/impl/LogicalStructureViewModel.kt | 32 ++------------ .../model/LogicalStructureAssembledModel.kt | 6 +++ 4 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureElementsVisitor.kt diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java index 62ae3abf565e..4a5ca67413fc 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java @@ -8,6 +8,7 @@ import com.intellij.ide.structureView.customRegions.CustomRegionTreeElement; import com.intellij.ide.structureView.impl.StructureViewFactoryImpl; import com.intellij.ide.structureView.impl.common.PsiTreeElementBase; import com.intellij.ide.structureView.logical.LogicalStructureDataKeys; +import com.intellij.ide.structureView.logical.impl.LogicalStructureElementsVisitor; import com.intellij.ide.structureView.logical.impl.LogicalStructureViewModel; import com.intellij.ide.structureView.logical.impl.LogicalStructureViewTreeElement; import com.intellij.ide.structureView.logical.model.LogicalPsiDescription; @@ -473,7 +474,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre if (psiDescriptions == null) { psiDescriptions = logicalStructureViewModel.getAssembledModel().getLogicalPsiDescriptions(); } - return logicalStructureViewModel.visitPathForLogicalElementSelection(treeElement, element, psiDescriptions); + return LogicalStructureElementsVisitor.INSTANCE.visitPathForLogicalElementSelection(treeElement, element, psiDescriptions); } return visitPathForElementSelection(path, element, editorOffset, state); } diff --git a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureElementsVisitor.kt b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureElementsVisitor.kt new file mode 100644 index 000000000000..9851be3dee1f --- /dev/null +++ b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureElementsVisitor.kt @@ -0,0 +1,44 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.ide.structureView.logical.impl + +import com.intellij.ide.structureView.StructureViewTreeElement +import com.intellij.ide.structureView.logical.ExternalElementsProvider +import com.intellij.ide.structureView.logical.model.ExtendedLogicalObject +import com.intellij.ide.structureView.logical.model.LogicalPsiDescription +import com.intellij.psi.PsiElement +import com.intellij.ui.tree.TreeVisitor +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +object LogicalStructureElementsVisitor { + + fun visitPathForLogicalElementSelection(treeElement: StructureViewTreeElement, element: Any?, psiDescriptions: Set): TreeVisitor.Action { + if (element !is PsiElement) return TreeVisitor.Action.SKIP_CHILDREN + if (treeElement is ElementsBuilder.LogicalGroupStructureElement<*>) { + if (treeElement.grouper is ExternalElementsProvider<*, *>) { + return TreeVisitor.Action.SKIP_CHILDREN + } + return TreeVisitor.Action.CONTINUE + } + if (treeElement is ElementsBuilder.OtherStructureElement<*>) { + return TreeVisitor.Action.CONTINUE + } + val targetElement = psiDescriptions.firstNotNullOfOrNull { + it.getSuitableElement(element) + } ?: return TreeVisitor.Action.SKIP_CHILDREN + if (treeElement is ElementsBuilder.PsiElementStructureElement<*>) { + if (treeElement.element == targetElement) { + return TreeVisitor.Action.INTERRUPT + } + (treeElement.getLogicalAssembledModel().model as? ExtendedLogicalObject)?.let { + if (it.canRepresentPsiElement(targetElement)) return TreeVisitor.Action.INTERRUPT + } + if (treeElement.element?.containingFile != targetElement.containingFile) { + return TreeVisitor.Action.SKIP_CHILDREN + } + return TreeVisitor.Action.CONTINUE + } + return TreeVisitor.Action.SKIP_CHILDREN + } + +} \ No newline at end of file diff --git a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureViewModel.kt b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureViewModel.kt index e31224fd9c1a..4c2b3eb6cbcd 100644 --- a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureViewModel.kt +++ b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/impl/LogicalStructureViewModel.kt @@ -18,7 +18,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiTarget import com.intellij.ui.SimpleTextAttributes -import com.intellij.ui.tree.TreeVisitor import org.jetbrains.annotations.ApiStatus import java.util.concurrent.CompletableFuture import java.util.concurrent.ConcurrentHashMap @@ -75,32 +74,6 @@ class LogicalStructureViewModel private constructor(psiFile: PsiFile, editor: Ed return null } - fun visitPathForLogicalElementSelection(treeElement: StructureViewTreeElement, element: Any?, psiDescriptions: Set): TreeVisitor.Action { - if (element !is PsiElement) return TreeVisitor.Action.SKIP_CHILDREN - if (treeElement is ElementsBuilder.LogicalGroupStructureElement<*>) { - if (treeElement.grouper is ExternalElementsProvider<*, *>) { - return TreeVisitor.Action.SKIP_CHILDREN - } - return TreeVisitor.Action.CONTINUE - } - val targetElement = psiDescriptions.firstNotNullOfOrNull { - it.getSuitableElement(element) - } ?: return TreeVisitor.Action.SKIP_CHILDREN - if (treeElement is ElementsBuilder.PsiElementStructureElement<*>) { - if (treeElement.element == targetElement) { - return TreeVisitor.Action.INTERRUPT - } - (treeElement.getLogicalAssembledModel().model as? ExtendedLogicalObject)?.let { - if (it.canRepresentPsiElement(targetElement)) return TreeVisitor.Action.INTERRUPT - } - if (treeElement.element?.containingFile != targetElement.containingFile) { - return TreeVisitor.Action.SKIP_CHILDREN - } - return TreeVisitor.Action.CONTINUE - } - return TreeVisitor.Action.SKIP_CHILDREN - } - private fun getModel(element: StructureViewTreeElement): Any? { return when (element) { is ElementsBuilder.LogicalGroupStructureElement<*> -> element.grouper @@ -123,7 +96,8 @@ interface LogicalStructureViewTreeElement : StructureViewTreeElement { } -private class ElementsBuilder { +@ApiStatus.Internal +class ElementsBuilder { private val typePresentationService = TypePresentationService.getService() private val groupElements: MutableMap, MutableMap, LogicalGroupStructureElement<*>>> = ConcurrentHashMap() @@ -197,7 +171,7 @@ private class ElementsBuilder { } } - private fun getPresentationData(model: Any): PresentationData { + fun getPresentationData(model: Any): PresentationData { val presentationProvider = LogicalModelPresentationProvider.getForObject(model) if (presentationProvider == null) { return PresentationData( diff --git a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/model/LogicalStructureAssembledModel.kt b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/model/LogicalStructureAssembledModel.kt index eff2a8a9afb3..5634737430c0 100644 --- a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/model/LogicalStructureAssembledModel.kt +++ b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/model/LogicalStructureAssembledModel.kt @@ -67,6 +67,12 @@ class LogicalStructureAssembledModel private constructor( result.add(model) } } + if (model is LogicalContainer<*>) { + model.getElements().forEach { child -> + if (child == null) return@forEach + result.addAll(getLogicalPsiDescriptions(child)) + } + } for (provider in LogicalStructureElementsProvider.getProviders(model)) { if (provider is LogicalPsiDescription) { if (!provider.isAskChildren()) {