diff --git a/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionContributor.kt b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionContributor.kt new file mode 100644 index 000000000..d7702e672 --- /dev/null +++ b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionContributor.kt @@ -0,0 +1,36 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2025 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.bukkit.completion + +import com.intellij.codeInsight.completion.CompletionContributor +import com.intellij.codeInsight.completion.CompletionType +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiClass + +class BukkitEventHandlerCompletionContributor : CompletionContributor() { + init { + extend( + CompletionType.BASIC, + PlatformPatterns.psiElement().inside(PsiClass::class.java), + BukkitEventHandlerCompletionProvider() + ) + } +} diff --git a/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionProvider.kt b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionProvider.kt new file mode 100644 index 000000000..a2f694875 --- /dev/null +++ b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionProvider.kt @@ -0,0 +1,99 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2025 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.bukkit.completion + +import com.demonwav.mcdev.platform.bukkit.util.BukkitConstants +import com.demonwav.mcdev.util.findContainingClass +import com.demonwav.mcdev.util.findContainingMethod +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionProvider +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.completion.PrioritizedLookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.icons.AllIcons +import com.intellij.psi.PsiModifier +import com.intellij.psi.impl.JavaPsiFacadeEx +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.searches.ClassInheritorsSearch +import com.intellij.util.ProcessingContext + +class BukkitEventHandlerCompletionProvider : CompletionProvider() { + + override fun addCompletions( + completionParameters: CompletionParameters, + processingContext: ProcessingContext, + completionResultSet: CompletionResultSet + ) { + val prefix = completionResultSet.prefixMatcher.prefix + if (!prefix.startsWith("on") || prefix.length == 2) { + return + } + + val position = completionParameters.position + val containingClass = position.findContainingClass() ?: return + val project = position.project + val facade = JavaPsiFacadeEx.getInstance(project) + + val eventListenerClass = facade.findClass(BukkitConstants.LISTENER_CLASS, GlobalSearchScope.allScope(project)) ?: return + if (!containingClass.isInheritor(eventListenerClass, true)) { + return + } + + if (position.findContainingMethod() != null) { + return + } + + val scope = GlobalSearchScope.allScope(project) + val eventBaseClass = facade.findClass(BukkitConstants.EVENT_CLASS, scope) ?: return + val eventNameFilter = prefix.substring(2).lowercase() + + ClassInheritorsSearch.search(eventBaseClass, scope, true) + .forEach { psiClass -> + if (psiClass.isInterface || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return@forEach + } + + val eventSimpleName = psiClass.name ?: return@forEach + if (eventNameFilter.isNotEmpty() && !eventSimpleName.lowercase().startsWith(eventNameFilter)) { + return@forEach + } + + val lookupString = "on$eventSimpleName" + val qualifiedName = psiClass.qualifiedName + + val element = LookupElementBuilder + .create(lookupString) + .withPresentableText("$lookupString()") + .withTailText(" - $qualifiedName", true) + .withTypeText("@EventHandler") + .withIcon(AllIcons.Nodes.Method) + .withBaseLookupString(lookupString) + .withBoldness(true) + .withInsertHandler(BukkitEventHandlerInsertHandler(psiClass)) + + completionResultSet.addElement( + PrioritizedLookupElement.withPriority(element, 100.0) + ) + } + + completionResultSet.stopHere() + } +} diff --git a/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerInsertHandler.kt b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerInsertHandler.kt new file mode 100644 index 000000000..c1d785e93 --- /dev/null +++ b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerInsertHandler.kt @@ -0,0 +1,58 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2025 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.bukkit.completion + +import com.demonwav.mcdev.util.psiType +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.intention.impl.TypeExpression +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.template.TemplateManager +import com.intellij.codeInsight.template.impl.TemplateSettings +import com.intellij.codeInsight.template.impl.Variable +import com.intellij.psi.PsiClass +import com.jetbrains.rd.util.string.printToString + +class BukkitEventHandlerInsertHandler( + private val psiClass: PsiClass +) : InsertHandler { + + override fun handleInsert(insertionContext: InsertionContext, lookupElement: LookupElement) { + insertionContext.document.deleteString( + insertionContext.startOffset, + insertionContext.tailOffset + ) + + val sourceTemplate = TemplateSettings.getInstance().getTemplate("event_handler", "Bukkit") ?: return + val template = sourceTemplate.copy() + + val classTypeExpr = TypeExpression(insertionContext.project, listOf(psiClass.psiType)) + + val index = template.variables.indexOfFirst { it.name == "EVENT_CLASS" } + if (index != -1) { + template.removeVariable(index) + } + + template.addVariable(Variable("EVENT_CLASS", classTypeExpr, classTypeExpr, false, false)); + + TemplateManager.getInstance(insertionContext.project).startTemplate(insertionContext.editor, template) + } +} diff --git a/src/main/kotlin/platform/bukkit/macro/BukkitEventNameMacro.kt b/src/main/kotlin/platform/bukkit/macro/BukkitEventNameMacro.kt new file mode 100644 index 000000000..bf277a621 --- /dev/null +++ b/src/main/kotlin/platform/bukkit/macro/BukkitEventNameMacro.kt @@ -0,0 +1,42 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2025 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.bukkit.macro + +import com.intellij.codeInsight.template.Expression +import com.intellij.codeInsight.template.ExpressionContext +import com.intellij.codeInsight.template.Result +import com.intellij.codeInsight.template.TextResult +import com.intellij.codeInsight.template.macro.MacroBase + +class BukkitEventNameMacro : MacroBase("bukkitEventName", "Usage: bukkitEventName(ClassType)") { + override fun calculateResult( + params: Array, + context: ExpressionContext?, + quick: Boolean + ): Result? { + val text = params[0] + ?.calculateResult(context) + ?.toString() ?: return null + + val result = text.split("\\.").last().removeSuffix("Event") + return TextResult(result) + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 05cbc4dc0..527771050 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -532,6 +532,17 @@ + + + + + + + + diff --git a/src/main/resources/liveTemplates/Bukkit.xml b/src/main/resources/liveTemplates/Bukkit.xml new file mode 100644 index 000000000..3cae6fdde --- /dev/null +++ b/src/main/resources/liveTemplates/Bukkit.xml @@ -0,0 +1,32 @@ + + + + + diff --git a/src/main/resources/messages/MinecraftDevelopment.properties b/src/main/resources/messages/MinecraftDevelopment.properties index eb1811e22..84e6d428a 100644 --- a/src/main/resources/messages/MinecraftDevelopment.properties +++ b/src/main/resources/messages/MinecraftDevelopment.properties @@ -370,3 +370,5 @@ template.provider.builtin.label=Built In template.provider.remote.label=Remote template.provider.local.label=Local template.provider.zip.label=Archive + +live.template.bukkit.event_handler.description=Create an event handler