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..f388bd0f9
--- /dev/null
+++ b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerCompletionProvider.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.openapi.project.Project
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiMethod
+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.psi.util.PsiTreeUtil
+import com.intellij.util.ProcessingContext
+import org.jetbrains.annotations.NotNull
+
+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 methodName = lookupString.removeSuffix("Event")
+ 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(methodName, qualifiedName))
+
+ 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..653e12ece
--- /dev/null
+++ b/src/main/kotlin/platform/bukkit/completion/BukkitEventHandlerInsertHandler.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.intellij.codeInsight.completion.InsertHandler
+import com.intellij.codeInsight.completion.InsertionContext
+import com.intellij.codeInsight.lookup.LookupElement
+import com.intellij.codeInsight.template.TemplateManager
+import com.intellij.codeInsight.template.impl.TextExpression
+import com.intellij.openapi.util.NlsSafe
+import org.jetbrains.annotations.NotNull
+
+class BukkitEventHandlerInsertHandler(
+ private val methodName: String,
+ private val qualifiedName: @NlsSafe String?
+) : InsertHandler {
+
+ override fun handleInsert(insertionContext: InsertionContext, lookupElement: LookupElement) {
+ val project = insertionContext.project
+ val editor = insertionContext.editor
+
+ val templateManager = TemplateManager.getInstance(project)
+ val template = templateManager.createTemplate("", "")
+ template.isToReformat = true
+
+ template.addTextSegment("@${BukkitConstants.HANDLER_ANNOTATION}\n")
+ template.addTextSegment("public void ")
+ template.addVariable("METHOD_NAME", TextExpression(methodName), true)
+ template.addTextSegment("($qualifiedName ")
+ template.addVariable("EVENT_PARAM", TextExpression("event"), true)
+ template.addTextSegment(") { \n")
+ template.addEndVariable()
+ template.addTextSegment("\n}")
+
+ insertionContext.document.deleteString(
+ insertionContext.startOffset,
+ insertionContext.tailOffset
+ )
+
+ templateManager.startTemplate(editor, template)
+
+ }
+}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 05cbc4dc0..13ca850e5 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -532,6 +532,13 @@
+
+
+
+