From 67e25e2b03cea9582fad97dbe2ee21b26c953c6d Mon Sep 17 00:00:00 2001 From: Mitchell Herrijgers Date: Thu, 26 Oct 2023 15:21:28 +0100 Subject: [PATCH 1/2] Move to built-in gutter renderer to prevent exception The way the gutter icon was built/customized to provides a popover even if only one item was in there, turned out to cause a lot of trouble. This PR simplifies it back to the way JetBrains recommends it. Fixes #235. --- .../plugin/api/ClassReferenceHierarcyItem.kt | 2 +- .../ide/plugin/api/PsiElementWrapper.kt | 2 +- .../ide/plugin/markers/AxonCellRenderer.kt | 66 --------------- .../AxonNavigationGutterIconRenderer.kt | 80 ------------------- .../markers/AxonNavigationTargetRenderer.kt | 50 ++++++++++++ .../plugin/markers/ClassLineMarkerProvider.kt | 30 ++++--- .../AbstractHandlerLineMarkerProvider.kt | 2 +- .../CommandHandlerMethodLineMarkerProvider.kt | 19 +++-- .../CommandInterceptorLineMarkerProvider.kt | 18 +++-- .../CommonHandlerMethodLineMarkerProvider.kt | 19 +++-- ...DeadlineHandlerMethodLineMarkerProvider.kt | 20 +++-- .../markers/handlers/ValidatingLazyValue.kt | 36 --------- .../DeadlinePublisherLineMarkerProvider.kt | 24 +++--- .../PublishMethodLineMarkerProvider.kt | 20 ++--- .../creators/DefaultMessageCreator.kt | 2 +- .../handlers/types/AggregateConstructor.kt | 3 +- .../handlers/types/CommandHandler.kt | 3 +- .../types/CommandHandlerInterceptor.kt | 3 +- .../handlers/types/DeadlineHandler.kt | 3 +- .../resolving/handlers/types/EventHandler.kt | 3 +- .../handlers/types/EventSourcingHandler.kt | 3 +- .../resolving/handlers/types/QueryHandler.kt | 3 +- .../handlers/types/SagaEventHandler.kt | 3 +- .../ide/plugin/AbstractAxonFixtureTestCase.kt | 11 ++- 24 files changed, 158 insertions(+), 267 deletions(-) delete mode 100644 src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonCellRenderer.kt delete mode 100644 src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationGutterIconRenderer.kt create mode 100644 src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationTargetRenderer.kt delete mode 100644 src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/ValidatingLazyValue.kt diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/ClassReferenceHierarcyItem.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/ClassReferenceHierarcyItem.kt index 18505666..6987b2b5 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/ClassReferenceHierarcyItem.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/ClassReferenceHierarcyItem.kt @@ -31,7 +31,7 @@ class ClassReferenceHierarcyItem( private val field: PsiField?, override val element: PsiElement = field ?: clazz, val depth: Int -) : PsiElementWrapper { +) : PsiElementWrapper, PsiElement by element { override fun getIcon(): Icon { return AxonIcons.Axon diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/PsiElementWrapper.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/PsiElementWrapper.kt index fa87563d..0aeed499 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/PsiElementWrapper.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/api/PsiElementWrapper.kt @@ -30,7 +30,7 @@ import javax.swing.Icon * @see Handler * @see MessageCreator */ -interface PsiElementWrapper { +interface PsiElementWrapper : PsiElement{ val element: PsiElement diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonCellRenderer.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonCellRenderer.kt deleted file mode 100644 index c9d02177..00000000 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonCellRenderer.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2022-(2010-2023). Axon Framework - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.axonframework.intellij.ide.plugin.markers - -import com.intellij.ide.util.PsiElementListCellRenderer -import com.intellij.openapi.util.Iconable.ICON_FLAG_VISIBILITY -import com.intellij.psi.PsiElement -import org.axonframework.intellij.ide.plugin.api.PsiElementWrapper -import java.util.function.Supplier -import javax.swing.Icon - -/** - * Renders the listed items in line markers. The texts and icons are provided by the implementations of the `Handler` - * and `MessageCreator` classes. - * - * Singleton instance. Please call `AxonCellRenderer.getInstance()` to get the instance. - * - * @see org.axonframework.intellij.ide.plugin.api.Handler - * @see org.axonframework.intellij.ide.plugin.api.MessageCreator - */ -class AxonCellRenderer( - private val elements: Supplier> -) : PsiElementListCellRenderer() { - /** - * Renders the text in the line marker popup. Contains the name of the item - * - * @return PSI element text - */ - override fun getElementText(element: PsiElement): String = onElement(element).renderText() - - /** - * Renders the container text in the line marker popup. Contains additional contextual information. - * - * @return PSI element container text - */ - override fun getContainerText(element: PsiElement, name: String?): String? = onElement(element).renderContainerText() - - override fun getIconFlags(): Int { - return ICON_FLAG_VISIBILITY - } - - /** - * Instructs the list which icon to show - * - * @return PSI element icon - */ - override fun getIcon(element: PsiElement): Icon = onElement(element).getIcon() - - private fun onElement(element: PsiElement): PsiElementWrapper { - return elements.get().first { it.element == element } - } -} diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationGutterIconRenderer.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationGutterIconRenderer.kt deleted file mode 100644 index 8048918e..00000000 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationGutterIconRenderer.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) (2010-2023). Axon Framework - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.axonframework.intellij.ide.plugin.markers - -import com.intellij.codeInsight.daemon.LineMarkerInfo -import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo -import com.intellij.codeInsight.navigation.NavigationGutterIconRenderer -import com.intellij.navigation.GotoRelatedItem -import com.intellij.openapi.util.NotNullLazyValue -import com.intellij.psi.PsiElement -import com.intellij.psi.SmartPointerManager -import org.axonframework.intellij.ide.plugin.api.PsiElementWrapper -import java.util.function.Supplier -import javax.swing.Icon - - -/** - * Gutter renderer that is modified to always show a popup list, even when there is only one option. - * - */ -class AxonNavigationGutterIconRenderer( - private val icon: Icon, - popupTitle: String, - private val tooltipText: String?, - emptyText: String?, - private val elements: Supplier>, -) : NavigationGutterIconRenderer(popupTitle, emptyText, { AxonCellRenderer(elements) }, NotNullLazyValue.createValue { - elements.get().sortedBy { it.getSortKey() }.mapNotNull { p -> - if(p.element.isValid) { - val spm = SmartPointerManager.getInstance(p.element.project) - spm.createSmartPsiElementPointer(p.element) - } else null - } -}) { - - override fun getIcon(): Icon { - return icon - } - - override fun getTooltipText(): String? { - return tooltipText - } - - override fun getAlignment(): Alignment { - return Alignment.LEFT - } - - fun createLineMarkerInfo(element: PsiElement): LineMarkerInfo<*> { - return RelatedItemLineMarkerInfo( - element, - element.textRange, - icon, - { tooltipText }, - this, - alignment, - { - elements.get() - .filter { it.element.isValid } - .map { WrappedGoToRelatedItem(it) } - } - ) - } -} - - -class WrappedGoToRelatedItem(val wrapper: PsiElementWrapper) : GotoRelatedItem(wrapper.element) diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationTargetRenderer.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationTargetRenderer.kt new file mode 100644 index 00000000..14d1770e --- /dev/null +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/AxonNavigationTargetRenderer.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) (2010-2023). Axon Framework + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.axonframework.intellij.ide.plugin.markers + +import com.intellij.codeInsight.navigation.impl.PsiTargetPresentationRenderer +import com.intellij.psi.PsiElement +import org.axonframework.intellij.ide.plugin.api.PsiElementWrapper +import javax.swing.Icon + +class AxonNavigationTargetRenderer private constructor() : PsiTargetPresentationRenderer() { + + override fun getContainerText(element: PsiElement): String? { + if (element is PsiElementWrapper) { + return element.renderContainerText() + } + return super.getContainerText(element) + } + + override fun getElementText(element: PsiElement): String { + if (element is PsiElementWrapper) { + return element.renderText() + } + return super.getElementText(element) + } + + override fun getIcon(element: PsiElement): Icon? { + if (element is PsiElementWrapper) { + return element.getIcon() + } + return super.getIcon(element) + } + + companion object { + val INSTANCE = AxonNavigationTargetRenderer() + } +} diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/ClassLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/ClassLineMarkerProvider.kt index 4ebd0726..d81d3645 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/ClassLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/ClassLineMarkerProvider.kt @@ -18,13 +18,13 @@ package org.axonframework.intellij.ide.plugin.markers import com.intellij.codeInsight.daemon.LineMarkerInfo import com.intellij.codeInsight.daemon.LineMarkerProvider +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder import com.intellij.openapi.util.NotNullLazyValue import com.intellij.psi.PsiElement import com.intellij.psi.PsiField import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.ClassReferenceHierarcyItem import org.axonframework.intellij.ide.plugin.api.Entity -import org.axonframework.intellij.ide.plugin.markers.handlers.ValidatingLazyValue import org.axonframework.intellij.ide.plugin.util.aggregateResolver import org.axonframework.intellij.ide.plugin.util.creatorResolver import org.axonframework.intellij.ide.plugin.util.handlerResolver @@ -47,29 +47,27 @@ class ClassLineMarkerProvider : LineMarkerProvider { if (!uElement.isAggregate()) { val handlers = element.handlerResolver().findHandlersForType(qualifiedName) if (handlers.isNotEmpty()) { - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Axon, - popupTitle = "Axon References To This Class", - tooltipText = "Navigate to message handlers and creations", - emptyText = "No references were found", - elements = NotNullLazyValue.createValue { + return NavigationGutterIconBuilder.create(AxonIcons.Axon) + .setPopupTitle("Axon References To This Class") + .setTooltipText("Navigate to message handlers and creations") + .setEmptyPopupText("No references were found") + .setTargets(NotNullLazyValue.lazy { val publishers = element.creatorResolver().getCreatorsForPayload(qualifiedName) handlers + publishers - }).createLineMarkerInfo(element) + }) + .createLineMarkerInfo(element) } } val owner = element.aggregateResolver().getTopEntityOfEntityWithName(qualifiedName) ?: return null val items = createHierarchy(owner, null, 0) if (items.isNotEmpty()) { - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Axon, - popupTitle = "Related Models", - tooltipText = "Navigate to entities in the same command model hierarchy", - emptyText = "No related entities were found", - elements = ValidatingLazyValue(element) { - items - }).createLineMarkerInfo(element) + return NavigationGutterIconBuilder.create(AxonIcons.Axon) + .setPopupTitle("Related Models") + .setTooltipText("Navigate to entities in the same command model hierarchy") + .setEmptyPopupText("No related entities were found") + .setTargets(NotNullLazyValue.lazy { items }) + .createLineMarkerInfo(element) } return null diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/AbstractHandlerLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/AbstractHandlerLineMarkerProvider.kt index df8cc457..a8a03e61 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/AbstractHandlerLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/AbstractHandlerLineMarkerProvider.kt @@ -50,7 +50,7 @@ abstract class AbstractHandlerLineMarkerProvider : LineMarkerProvider { // Do nothing, IntelliJ does not even want us to log it return null } - // We don't want to do anything on errors here. As is shown by Sentry exception catching, the process is error-=prone + // We don't want to do anything on errors here. As is shown by Sentry exception catching, the process is error-prone // mostly due to Kotlin plugin internals. We don't want to pester the user with it. // Generally, the issue will resolve itself on the next line marker pass anyway. logger().error("Got an exception while analyzing line markers in class {}", e, this::class.java.name) diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandHandlerMethodLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandHandlerMethodLineMarkerProvider.kt index 15086c5f..a3068b70 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandHandlerMethodLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandHandlerMethodLineMarkerProvider.kt @@ -17,11 +17,13 @@ package org.axonframework.intellij.ide.plugin.markers.handlers import com.intellij.codeInsight.daemon.LineMarkerInfo +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder +import com.intellij.openapi.util.NotNullLazyValue import com.intellij.psi.PsiElement import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.MessageHandlerType import org.axonframework.intellij.ide.plugin.api.MessageType -import org.axonframework.intellij.ide.plugin.markers.AxonNavigationGutterIconRenderer +import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer import org.axonframework.intellij.ide.plugin.resolving.handlers.types.CommandHandlerInterceptor import org.axonframework.intellij.ide.plugin.util.creatorResolver import org.axonframework.intellij.ide.plugin.util.handlerResolver @@ -43,16 +45,17 @@ class CommandHandlerMethodLineMarkerProvider : AbstractHandlerLineMarkerProvider .filterIsInstance() val icon = if (interceptingElements.isNotEmpty()) AxonIcons.HandlerIntercepted else AxonIcons.Handler - return AxonNavigationGutterIconRenderer( - icon = icon, - popupTitle = "Payload Creators", - tooltipText = "Navigate to creators of $payload", - emptyText = "No creators of this message payload were found", - elements = ValidatingLazyValue(element) { - val creatingElements = element.creatorResolver().getCreatorsForPayload(payload) + return NavigationGutterIconBuilder.create(icon) + .setTargets(NotNullLazyValue.lazy { + val creatingElements = element.creatorResolver() + .getCreatorsForPayload(payload) .distinctBy { it.parentHandler } interceptingElements + creatingElements }) + .setTargetRenderer { AxonNavigationTargetRenderer.INSTANCE } + .setPopupTitle("Payload Creators") + .setTooltipText("Navigate to creators of $payload") + .setEmptyPopupText("No creators of this message payload were found") .createLineMarkerInfo(element) } } diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandInterceptorLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandInterceptorLineMarkerProvider.kt index a4142ab2..815344c4 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandInterceptorLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommandInterceptorLineMarkerProvider.kt @@ -17,11 +17,13 @@ package org.axonframework.intellij.ide.plugin.markers.handlers import com.intellij.codeInsight.daemon.LineMarkerInfo +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder +import com.intellij.openapi.util.NotNullLazyValue import com.intellij.psi.PsiElement import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.MessageHandlerType import org.axonframework.intellij.ide.plugin.api.MessageType -import org.axonframework.intellij.ide.plugin.markers.AxonNavigationGutterIconRenderer +import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer import org.axonframework.intellij.ide.plugin.resolving.handlers.types.CommandHandler import org.axonframework.intellij.ide.plugin.util.aggregateResolver import org.axonframework.intellij.ide.plugin.util.handlerResolver @@ -48,12 +50,8 @@ class CommandInterceptorLineMarkerProvider : AbstractHandlerLineMarkerProvider() // An interceptor without payload is fine, default to Object to match all val actualPayload = payload ?: "java.lang.Object" - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Interceptor, - popupTitle = "Commands Intercepted", - tooltipText = "Navigate to command handlers that are intercepted", - emptyText = "No intercepted command handlers were found", - elements = ValidatingLazyValue(element) { + return NavigationGutterIconBuilder.create(AxonIcons.Interceptor) + .setTargets(NotNullLazyValue.lazy { val members = element.aggregateResolver().getEntityAndAllChildrenRecursively(className) element.handlerResolver().findHandlersForType(actualPayload, MessageType.COMMAND) .filterIsInstance() @@ -62,6 +60,10 @@ class CommandInterceptorLineMarkerProvider : AbstractHandlerLineMarkerProvider() members.any { member -> member.name == name } } }) - .createLineMarkerInfo(element) + .setTargetRenderer { AxonNavigationTargetRenderer.INSTANCE } + .setPopupTitle("Commands Intercepted") + .setTooltipText("Navigate to command handlers that are intercepted") + .setEmptyPopupText("No intercepted command handlers were found") + .createLineMarkerInfo(element, ) } } diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommonHandlerMethodLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommonHandlerMethodLineMarkerProvider.kt index add65b5e..6a7e3a11 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommonHandlerMethodLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/CommonHandlerMethodLineMarkerProvider.kt @@ -17,10 +17,12 @@ package org.axonframework.intellij.ide.plugin.markers.handlers import com.intellij.codeInsight.daemon.LineMarkerInfo +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder +import com.intellij.openapi.util.NotNullLazyValue import com.intellij.psi.PsiElement import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.MessageHandlerType -import org.axonframework.intellij.ide.plugin.markers.AxonNavigationGutterIconRenderer +import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer import org.axonframework.intellij.ide.plugin.util.creatorResolver /** @@ -37,14 +39,15 @@ class CommonHandlerMethodLineMarkerProvider : AbstractHandlerLineMarkerProvider( return null } - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Handler, - popupTitle = "Payload Creators", - tooltipText = "Navigate to creators of $payload", - emptyText = "No creators of this message payload were found", - elements = ValidatingLazyValue(element) { + return NavigationGutterIconBuilder.create(AxonIcons.Handler) + .setTargets(NotNullLazyValue.lazy { element.creatorResolver().getCreatorsForPayload(payload) .distinctBy { it.parentHandler } - }).createLineMarkerInfo(element) + }) + .setTargetRenderer { AxonNavigationTargetRenderer.INSTANCE } + .setPopupTitle("Payload Creators") + .setTooltipText("Navigate to creators of $payload") + .setEmptyPopupText("No creators of this message payload were found") + .createLineMarkerInfo(element) } } diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/DeadlineHandlerMethodLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/DeadlineHandlerMethodLineMarkerProvider.kt index ca9fd0be..aca10368 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/DeadlineHandlerMethodLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/DeadlineHandlerMethodLineMarkerProvider.kt @@ -17,11 +17,13 @@ package org.axonframework.intellij.ide.plugin.markers.handlers import com.intellij.codeInsight.daemon.LineMarkerInfo +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder +import com.intellij.openapi.util.NotNullLazyValue import com.intellij.psi.PsiElement import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.AxonAnnotation import org.axonframework.intellij.ide.plugin.api.MessageHandlerType -import org.axonframework.intellij.ide.plugin.markers.AxonNavigationGutterIconRenderer +import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer import org.axonframework.intellij.ide.plugin.util.deadlineReferenceResolver import org.axonframework.intellij.ide.plugin.util.resolveAnnotationStringValue import org.jetbrains.uast.UAnnotation @@ -47,14 +49,16 @@ class DeadlineHandlerMethodLineMarkerProvider : AbstractHandlerLineMarkerProvide ?: payload ?: return null - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Handler, - popupTitle = "Deadline Schedulers", - tooltipText = "Navigate to schedule invocation of this deadline", - emptyText = "No deadline schedule invocations could be found", - elements = ValidatingLazyValue(element) { + + return NavigationGutterIconBuilder.create(AxonIcons.Handler) + .setTargets(NotNullLazyValue.lazy { element.deadlineReferenceResolver().findByDeadlineName(deadlineName) .distinctBy { it.parentHandler } - }).createLineMarkerInfo(element) + }) + .setTargetRenderer { AxonNavigationTargetRenderer.INSTANCE } + .setPopupTitle("Deadline Schedulers") + .setTooltipText("Navigate to schedule invocation of this deadline") + .setEmptyPopupText("No deadline schedule invocations could be found") + .createLineMarkerInfo(element) } } diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/ValidatingLazyValue.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/ValidatingLazyValue.kt deleted file mode 100644 index b9d17fa3..00000000 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/handlers/ValidatingLazyValue.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) (2010-2023). Axon Framework - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.axonframework.intellij.ide.plugin.markers.handlers - -import com.intellij.openapi.util.NotNullLazyValue -import com.intellij.psi.PsiElement -import java.util.function.Supplier - -class ValidatingLazyValue( - private val element: PsiElement, - private val supplier: (PsiElement) -> List, -) : Supplier> { - private val lazyValue = NotNullLazyValue.lazy { - if (element.isValid) { - supplier.invoke(element) - } else emptyList() - } - - override fun get(): List { - return lazyValue.value - } -} diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/DeadlinePublisherLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/DeadlinePublisherLineMarkerProvider.kt index 74064969..b7e89251 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/DeadlinePublisherLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/DeadlinePublisherLineMarkerProvider.kt @@ -18,13 +18,16 @@ package org.axonframework.intellij.ide.plugin.markers.publishers import com.intellij.codeInsight.daemon.LineMarkerInfo import com.intellij.codeInsight.daemon.LineMarkerProvider +import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo +import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder import com.intellij.ide.highlighter.JavaFileType +import com.intellij.openapi.util.NotNullLazyValue import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.elementType import org.axonframework.intellij.ide.plugin.AxonIcons -import org.axonframework.intellij.ide.plugin.markers.AxonNavigationGutterIconRenderer -import org.axonframework.intellij.ide.plugin.markers.handlers.ValidatingLazyValue +import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer import org.axonframework.intellij.ide.plugin.resolving.handlers.types.DeadlineHandler import org.axonframework.intellij.ide.plugin.util.deadlineMethodResolver import org.axonframework.intellij.ide.plugin.util.handlerResolver @@ -55,18 +58,17 @@ class DeadlinePublisherLineMarkerProvider : LineMarkerProvider { else -> null } ?: return null - - - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Publisher, - popupTitle = "Axon Deadline Handlers", - tooltipText = "Navigate to Axon deadline handlers", - emptyText = "No deadline handlers were found", - elements = ValidatingLazyValue(element) { + return NavigationGutterIconBuilder.create(AxonIcons.Publisher) + .setTargets(NotNullLazyValue.lazy { element.project.handlerResolver().findAllHandlers() .filterIsInstance() .filter { it.deadlineName == deadlineName } - }).createLineMarkerInfo(element) + }) + .setTargetRenderer { AxonNavigationTargetRenderer.INSTANCE } + .setPopupTitle("Axon Deadline Handlers") + .setTooltipText("Navigate to Axon deadline handlers") + .setEmptyPopupText("No deadline handlers were found") + .createLineMarkerInfo(element) } /* diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/PublishMethodLineMarkerProvider.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/PublishMethodLineMarkerProvider.kt index 36150352..04721437 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/PublishMethodLineMarkerProvider.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/markers/publishers/PublishMethodLineMarkerProvider.kt @@ -18,14 +18,16 @@ package org.axonframework.intellij.ide.plugin.markers.publishers import com.intellij.codeInsight.daemon.LineMarkerInfo import com.intellij.codeInsight.daemon.LineMarkerProvider +import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo +import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder import com.intellij.ide.highlighter.JavaFileType import com.intellij.psi.PsiElement import com.intellij.psi.PsiIdentifier import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.MessageHandlerType -import org.axonframework.intellij.ide.plugin.markers.AxonNavigationGutterIconRenderer -import org.axonframework.intellij.ide.plugin.markers.handlers.ValidatingLazyValue +import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer import org.axonframework.intellij.ide.plugin.resolving.MessageHandlerResolver import org.axonframework.intellij.ide.plugin.resolving.handlers.types.CommandHandlerInterceptor import org.axonframework.intellij.ide.plugin.resolving.handlers.types.DeadlineHandler @@ -73,14 +75,12 @@ class PublishMethodLineMarkerProvider : LineMarkerProvider { return null } - return AxonNavigationGutterIconRenderer( - icon = AxonIcons.Publisher, - popupTitle = "Axon Message Handlers", - tooltipText = "Navigate to Axon message handlers", - emptyText = "No message handlers were found", - elements = ValidatingLazyValue(element) { - handlers - }) + return NavigationGutterIconBuilder.create(AxonIcons.Publisher) + .setTargets(handlers) + .setTargetRenderer { AxonNavigationTargetRenderer.INSTANCE } + .setPopupTitle("Axon Message Handlers") + .setTooltipText("Navigate to Axon message handlers") + .setEmptyPopupText("No message handlers were found") .createLineMarkerInfo(element) } diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/creators/DefaultMessageCreator.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/creators/DefaultMessageCreator.kt index a8d7b580..d55d4470 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/creators/DefaultMessageCreator.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/creators/DefaultMessageCreator.kt @@ -35,7 +35,7 @@ data class DefaultMessageCreator( override val element: PsiElement, override val payload: String, override val parentHandler: Handler?, -) : MessageCreator { +) : MessageCreator, PsiElement by element { /** * Returns the correct icon for the creator diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/AggregateConstructor.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/AggregateConstructor.kt index 640122b6..98524952 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/AggregateConstructor.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/AggregateConstructor.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -30,7 +31,7 @@ import org.axonframework.intellij.ide.plugin.util.toShortName data class AggregateConstructor( override val element: PsiMethod, override val payload: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.COMMAND override fun renderText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandler.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandler.kt index 76ad165e..343eac3f 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandler.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandler.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -31,7 +32,7 @@ data class CommandHandler( override val element: PsiMethod, override val payload: String, val componentName: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.COMMAND override fun renderContainerText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandlerInterceptor.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandlerInterceptor.kt index 2148cab4..e0bc0003 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandlerInterceptor.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/CommandHandlerInterceptor.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.AxonIcons import org.axonframework.intellij.ide.plugin.api.Handler @@ -33,7 +34,7 @@ data class CommandHandlerInterceptor( override val element: PsiMethod, override val payload: String, val componentName: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.COMMAND_INTERCEPTOR override fun renderText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/DeadlineHandler.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/DeadlineHandler.kt index 016430fd..12d77784 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/DeadlineHandler.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/DeadlineHandler.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -29,7 +30,7 @@ data class DeadlineHandler( override val element: PsiMethod, override val payload: String, val deadlineName: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.DEADLINE override fun renderText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventHandler.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventHandler.kt index e510ed09..ed0e74c5 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventHandler.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventHandler.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -36,7 +37,7 @@ data class EventHandler( override val element: PsiMethod, override val payload: String, val processingGroup: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.EVENT override fun renderText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventSourcingHandler.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventSourcingHandler.kt index 6292833b..c4b6586b 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventSourcingHandler.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/EventSourcingHandler.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -31,7 +32,7 @@ data class EventSourcingHandler( override val element: PsiMethod, override val payload: String, val entity: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.EVENT_SOURCING override fun renderText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/QueryHandler.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/QueryHandler.kt index c393f0ec..d30f7da1 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/QueryHandler.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/QueryHandler.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -31,7 +32,7 @@ data class QueryHandler( override val element: PsiMethod, override val payload: String, val componentName: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.QUERY override fun renderText(): String { diff --git a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/SagaEventHandler.kt b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/SagaEventHandler.kt index ece02351..b6b5923f 100644 --- a/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/SagaEventHandler.kt +++ b/src/main/kotlin/org/axonframework/intellij/ide/plugin/resolving/handlers/types/SagaEventHandler.kt @@ -16,6 +16,7 @@ package org.axonframework.intellij.ide.plugin.resolving.handlers.types +import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import org.axonframework.intellij.ide.plugin.api.Handler import org.axonframework.intellij.ide.plugin.api.MessageHandlerType @@ -30,7 +31,7 @@ data class SagaEventHandler( override val element: PsiMethod, override val payload: String, val processingGroup: String, -) : Handler { +) : Handler, PsiElement by element { override val handlerType: MessageHandlerType = MessageHandlerType.SAGA override fun renderText(): String { diff --git a/src/test/kotlin/org/axonframework/intellij/ide/plugin/AbstractAxonFixtureTestCase.kt b/src/test/kotlin/org/axonframework/intellij/ide/plugin/AbstractAxonFixtureTestCase.kt index 71f7e35d..5d1c1954 100644 --- a/src/test/kotlin/org/axonframework/intellij/ide/plugin/AbstractAxonFixtureTestCase.kt +++ b/src/test/kotlin/org/axonframework/intellij/ide/plugin/AbstractAxonFixtureTestCase.kt @@ -21,6 +21,7 @@ import com.intellij.codeInsight.daemon.LineMarkerInfo import com.intellij.codeInsight.daemon.LineMarkerProvider import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo import com.intellij.codeInsight.daemon.impl.LineMarkersPass +import com.intellij.navigation.GotoRelatedItem import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.vfs.VirtualFile import com.intellij.pom.java.LanguageLevel @@ -32,7 +33,7 @@ import com.intellij.util.PathUtil import org.axonframework.config.ProcessingGroup import org.axonframework.eventhandling.EventHandler import org.axonframework.eventsourcing.EventSourcingHandler -import org.axonframework.intellij.ide.plugin.markers.WrappedGoToRelatedItem +import org.axonframework.intellij.ide.plugin.api.PsiElementWrapper import org.axonframework.modelling.command.AggregateMember import javax.swing.Icon @@ -140,9 +141,11 @@ abstract class AbstractAxonFixtureTestCase : LightJavaCodeInsightFixtureTestCase val gutters = myFixture.findGuttersAtCaret() val marker = gutters.firstNotNullOf { getHandlerMethodMakerProviders(it, clazz) } ?: throw IllegalStateException("No gutter found") - val items = marker.createGotoRelatedItems() as List - return items.map { - OptionSummary(it.wrapper.renderText(), it.wrapper.renderContainerText(), it.wrapper.getIcon()) + val items = marker.createGotoRelatedItems() + return items + .map { it.element } + .filterIsInstance().map { + OptionSummary(it.renderText(), it.renderContainerText(), it.getIcon()) } } From 926b703a679f5f73d34e4e0dc07c6d35aa7528c6 Mon Sep 17 00:00:00 2001 From: Mitchell Herrijgers Date: Thu, 26 Oct 2023 15:38:33 +0100 Subject: [PATCH 2/2] Upgrade versions since API is incompatible --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0a707683..30923c9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,12 +19,12 @@ pluginGroup=io.axoniq.ide.intellij pluginName=Axon Framework -pluginVersion=0.8.2 -axonVersion=4.7.0 +pluginVersion=0.8.3 +axonVersion=4.9.0 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. -pluginSinceBuild = 231 +pluginSinceBuild = 232 pluginUntilBuild = 232.* # IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties