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