diff --git a/README.md b/README.md index 0050d2e..d12c71b 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,7 @@ Features - Jump from post to subscribe and vice versa - Shows marker only for `@Subscribe` methods that have correct signatures - Fully supported for project using both Java and Kotlin + +Testing +----- +There are no unit tests yet (I am writing them, but hit a roadblock. We will soon find a way). Any changes made to the plugin should be tested against this project. This project contains all possible use cases of EventBus in both Java and Kotlin. diff --git a/build.gradle b/build.gradle index c85adf0..8c24c65 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'com.madrapps' -version '0.3.3.2018.3' +version '0.4.2.2018.3' sourceCompatibility = 1.8 @@ -34,10 +34,7 @@ compileTestKotlin { patchPluginXml { changeNotes """ - - Option to view usages in "Find" tool window
- - Improved the UI of the usages popup
- - Support for Enums
- - Support for `@file:JvmName()`
- - Performance improvement
+ - Add breakpoints to `post` or `subscribe` in a single click
+ - Option to clear added breakpoints as well
""" } \ No newline at end of file diff --git a/src/main/kotlin/com/madrapps/eventbus/FindUsages.kt b/src/main/kotlin/com/madrapps/eventbus/FindUsages.kt index 2ca10c8..1967485 100644 --- a/src/main/kotlin/com/madrapps/eventbus/FindUsages.kt +++ b/src/main/kotlin/com/madrapps/eventbus/FindUsages.kt @@ -48,4 +48,10 @@ internal fun UElement.getParentOfTypeCallExpression(): UCallExpression? { .filterIsInstance() .firstOrNull() ?.selector as? UCallExpression -} \ No newline at end of file +} + +internal fun Usage.getPostStatementSourcePsi() = toUElement()?.getParentOfTypeCallExpression()?.sourcePsi + +internal fun Usage.getSubscribeMethodSourcePsi() = getType()?.uastAnchor?.sourcePsi + +internal fun Usage.file() = toUElement()?.sourcePsi?.containingFile \ No newline at end of file diff --git a/src/main/kotlin/com/madrapps/eventbus/PopUpView.kt b/src/main/kotlin/com/madrapps/eventbus/PopUpView.kt index 191a868..6443a89 100644 --- a/src/main/kotlin/com/madrapps/eventbus/PopUpView.kt +++ b/src/main/kotlin/com/madrapps/eventbus/PopUpView.kt @@ -1,5 +1,9 @@ package com.madrapps.eventbus +import com.intellij.debugger.DebuggerManagerEx +import com.intellij.debugger.ui.breakpoints.BreakpointManager +import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter +import com.intellij.icons.AllIcons import com.intellij.icons.AllIcons.Toolwindows.ToolWindowFind import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionPlaces.USAGE_VIEW_TOOLBAR @@ -7,8 +11,10 @@ import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.DefaultActionGroup import com.intellij.openapi.actionSystem.IdeActions.ACTION_FIND_USAGES +import com.intellij.openapi.editor.Document import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory +import com.intellij.psi.PsiDocumentManager import com.intellij.ui.ScrollingUtil import com.intellij.ui.SimpleColoredComponent import com.intellij.ui.SimpleTextAttributes.REGULAR_ATTRIBUTES @@ -20,6 +26,9 @@ import com.intellij.util.PlatformIcons import com.intellij.util.ui.ColumnInfo import com.intellij.util.ui.ListTableModel import com.intellij.util.ui.UIUtil +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties +import org.jetbrains.kotlin.idea.refactoring.getLineNumber +import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.uast.UClass import org.jetbrains.uast.UFile import org.jetbrains.uast.UMethod @@ -91,7 +100,11 @@ private fun showTablePopUp(usages: List, columnInfos: Array if (usages.isNotEmpty()) { val actionGroup = DefaultActionGroup() - actionGroup.add(ShowUsagesAction(usages) { popUp?.closeOk(it) }) + val closePopUp: (InputEvent) -> Unit = { popUp?.closeOk(it) } + actionGroup.add(SetBreakpointAction(usages, closePopUp)) + actionGroup.add(RemoveBreakpointAction(usages, closePopUp)) + actionGroup.addSeparator() + actionGroup.add(ShowUsagesAction(usages, closePopUp)) val actionToolbar = ActionManager.getInstance().createActionToolbar(USAGE_VIEW_TOOLBAR, actionGroup, true) actionToolbar.setReservePlaceAutoPopupIcon(false) val toolBar = actionToolbar.component @@ -103,7 +116,7 @@ private fun showTablePopUp(usages: List, columnInfos: Array return popUp } -private fun getTitle(usages: List) = if (usages.isEmpty()) "No usages found" else "Find Usages" +private fun getTitle(usages: List) = if (usages.isEmpty()) "No usages found" else "Usages" private fun resizeColumnWidth(table: JTable) { val columnModel = table.columnModel @@ -199,4 +212,94 @@ private class ShowUsagesAction( usageViewPresentation ) } +} + +private class SetBreakpointAction( + private val usages: List, + private val closePopUp: (InputEvent) -> Unit +) : AnAction( + "Set Breakpoints", + "Set breakpoints at all usages", + AllIcons.Debugger.Db_set_breakpoint +) { + override fun actionPerformed(e: AnActionEvent) { + closePopUp(e.inputEvent) + val breakpointManager = DebuggerManagerEx.getInstanceEx(e.project!!).breakpointManager + usages.forEach { + val containingFile = it.file() + if (containingFile != null) { + val document = PsiDocumentManager.getInstance(e.project!!).getDocument(containingFile) + if (document != null) { + val isBreakpointAdded = addLineBreakpoint(it, breakpointManager, document) + if (!isBreakpointAdded) { + addMethodBreakpoint(it, breakpointManager, document) + } + } + } + } + } + + private fun addLineBreakpoint( + it: Usage, + breakpointManager: BreakpointManager, + document: Document + ): Boolean { + val sourcePsi = it.getPostStatementSourcePsi() + if (sourcePsi != null) { + val lineNumber = sourcePsi.getLineNumber(true) + breakpointManager.addLineBreakpoint(document, lineNumber) + } + return sourcePsi != null + } + + private fun addMethodBreakpoint( + it: Usage, + breakpointManager: BreakpointManager, + document: Document? + ) { + val source = it.getSubscribeMethodSourcePsi() + if (source != null) { + val lineNumber = source.getLineNumber(true) + if (breakpointManager.findBreakpoint>>( + document, + source.startOffset, + null + ) == null + ) { + breakpointManager.addMethodBreakpoint(document, lineNumber) + } + } + } +} + +private class RemoveBreakpointAction( + private val usages: List, + private val closePopUp: (InputEvent) -> Unit +) : AnAction( + "Remove Breakpoints", + "Remove breakpoints at all usages", + AllIcons.Debugger.MuteBreakpoints +) { + override fun actionPerformed(e: AnActionEvent) { + closePopUp(e.inputEvent) + val project = e.project!! + val breakpointManager = DebuggerManagerEx.getInstanceEx(project).breakpointManager + val documentManager = PsiDocumentManager.getInstance(project) + usages.forEach { + val containingFile = it.file() + if (containingFile != null) { + val document = documentManager.getDocument(containingFile) + val source = it.getPostStatementSourcePsi() ?: it.getSubscribeMethodSourcePsi() + if (source != null && document != null) { + val breakPoint = + breakpointManager.findBreakpoint>>( + document, + source.startOffset, + null + ) + breakpointManager.removeBreakpoint(breakPoint) + } + } + } + } } \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 056ea32..75fe0f0 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -10,6 +10,8 @@
  • Supports post, postSticky and @Subscribe
  • Jump from post to subscribe and vice versa
  • Shows marker only for @Subscribe methods that have correct signatures
  • +
  • Optionally show usages in 'Find' tool window
  • +
  • Add breakpoints to all usages in a single click
  • Fully supported for project using both Java and Kotlin
  • ]]>