Skip to content

Commit e7f4d43

Browse files
committed
Add completion contributor for Bukkit event handlers
1 parent 683326d commit e7f4d43

4 files changed

Lines changed: 148 additions & 0 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.demonwav.mcdev.platform.bukkit.completion
2+
3+
import com.intellij.codeInsight.completion.CompletionContributor
4+
import com.intellij.codeInsight.completion.CompletionType
5+
import com.intellij.patterns.PlatformPatterns
6+
import com.intellij.psi.PsiClass
7+
8+
class BukkitEventHandlerCompletionContributor : CompletionContributor() {
9+
init {
10+
extend(
11+
CompletionType.BASIC,
12+
PlatformPatterns.psiElement().inside(PsiClass::class.java),
13+
BukkitEventHandlerCompletionProvider()
14+
)
15+
}
16+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.demonwav.mcdev.platform.bukkit.completion
2+
3+
import com.intellij.codeInsight.completion.CompletionParameters
4+
import com.intellij.codeInsight.completion.CompletionProvider
5+
import com.intellij.codeInsight.completion.CompletionResultSet
6+
import com.intellij.codeInsight.completion.PrioritizedLookupElement
7+
import com.intellij.codeInsight.lookup.LookupElementBuilder
8+
import com.intellij.icons.AllIcons
9+
import com.intellij.openapi.project.Project
10+
import com.intellij.psi.PsiClass
11+
import com.intellij.psi.PsiMethod
12+
import com.intellij.psi.PsiModifier
13+
import com.intellij.psi.impl.JavaPsiFacadeEx
14+
import com.intellij.psi.search.GlobalSearchScope
15+
import com.intellij.psi.search.searches.ClassInheritorsSearch
16+
import com.intellij.psi.util.PsiTreeUtil
17+
import com.intellij.util.ProcessingContext
18+
import org.jetbrains.annotations.NotNull
19+
20+
class BukkitEventHandlerCompletionProvider : CompletionProvider<CompletionParameters>() {
21+
companion object {
22+
const val EVENT_LISTENER = "org.bukkit.event.Listener"
23+
private const val BUKKIT_EVENT_FQN = "org.bukkit.event.Event"
24+
}
25+
26+
override fun addCompletions(
27+
@NotNull completionParameters: CompletionParameters,
28+
@NotNull processingContext: ProcessingContext,
29+
@NotNull completionResultSet: CompletionResultSet
30+
) {
31+
val prefix = completionResultSet.prefixMatcher.prefix
32+
if (!prefix.startsWith("on") || prefix.length == 2) return
33+
34+
val position = completionParameters.position
35+
val containingClass = PsiTreeUtil.getParentOfType(position, PsiClass::class.java) ?: return
36+
val project: Project = position.project
37+
val facade = JavaPsiFacadeEx.getInstanceEx(project)
38+
39+
val eventListenerClass = facade.findClass(EVENT_LISTENER, GlobalSearchScope.allScope(project)) ?: return
40+
if (!containingClass.isInheritor(eventListenerClass, true)) return
41+
if (PsiTreeUtil.getParentOfType(position, PsiMethod::class.java) != null) return
42+
43+
val scope = GlobalSearchScope.allScope(project)
44+
val eventBaseClass = facade.findClass(BUKKIT_EVENT_FQN, scope) ?: return
45+
46+
val eventNameFilter = prefix.substring(2).lowercase()
47+
48+
ClassInheritorsSearch.search(eventBaseClass, scope, true)
49+
.forEach { psiClass ->
50+
if (psiClass.isInterface || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
51+
return@forEach
52+
}
53+
54+
val eventSimpleName = psiClass.name ?: return@forEach
55+
if (eventNameFilter.isNotEmpty() && !eventSimpleName.lowercase().startsWith(eventNameFilter)) {
56+
return@forEach
57+
}
58+
59+
val lookupString = "on$eventSimpleName"
60+
val methodName = lookupString.replace("Event", "")
61+
val qualifiedName = psiClass.qualifiedName
62+
63+
val element = LookupElementBuilder
64+
.create(lookupString)
65+
.withPresentableText("$lookupString()")
66+
.withTailText(" - $qualifiedName", true)
67+
.withTypeText("@EventHandler")
68+
.withIcon(AllIcons.Nodes.Method)
69+
.withBaseLookupString(lookupString)
70+
.withBoldness(true)
71+
.withInsertHandler(BukkitEventHandlerInsertHandler(methodName, qualifiedName))
72+
73+
completionResultSet.addElement(
74+
PrioritizedLookupElement.withPriority(element, 100.0)
75+
)
76+
}
77+
78+
completionResultSet.stopHere()
79+
}
80+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.demonwav.mcdev.platform.bukkit.completion
2+
3+
import com.intellij.codeInsight.completion.InsertHandler
4+
import com.intellij.codeInsight.completion.InsertionContext
5+
import com.intellij.codeInsight.lookup.LookupElement
6+
import com.intellij.codeInsight.template.TemplateManager
7+
import com.intellij.codeInsight.template.impl.TextExpression
8+
import com.intellij.openapi.util.NlsSafe
9+
import org.jetbrains.annotations.NotNull
10+
11+
class BukkitEventHandlerInsertHandler(
12+
private val methodName: String,
13+
private val qualifiedName: @NlsSafe String?
14+
) : InsertHandler<LookupElement> {
15+
16+
companion object {
17+
private const val EVENT_HANDLER_FQN = "org.bukkit.event.EventHandler"
18+
}
19+
20+
override fun handleInsert(@NotNull insertionContext: InsertionContext, @NotNull lookupElement: LookupElement) {
21+
val project = insertionContext.project
22+
val editor = insertionContext.editor
23+
24+
val templateManager = TemplateManager.getInstance(project)
25+
val template = templateManager.createTemplate("", "")
26+
template.isToReformat = true
27+
28+
template.addTextSegment("@${EVENT_HANDLER_FQN}\n")
29+
template.addTextSegment("public void ")
30+
template.addVariable("METHOD_NAME", TextExpression(methodName), true)
31+
template.addTextSegment("($qualifiedName ")
32+
template.addVariable("EVENT_PARAM", TextExpression("event"), true)
33+
template.addTextSegment(") { \n")
34+
template.addEndVariable()
35+
template.addTextSegment("\n}")
36+
37+
insertionContext.getDocument().deleteString(
38+
insertionContext.getStartOffset(),
39+
insertionContext.getTailOffset()
40+
);
41+
42+
templateManager.startTemplate(editor, template)
43+
44+
}
45+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,13 @@
532532
<library.presentationProvider
533533
implementation="com.demonwav.mcdev.platform.bukkit.framework.ModernPaperPresentationProvider"/>
534534

535+
<!-- Bukkit Completion Contributor -->
536+
537+
<completion.contributor
538+
language="JAVA"
539+
implementationClass="com.demonwav.mcdev.platform.bukkit.completion.BukkitEventHandlerCompletionContributor"
540+
order="first"/>
541+
535542
<!--endregion-->
536543

537544
<!--region SPONGE-->

0 commit comments

Comments
 (0)