Skip to content

Commit d38fb4e

Browse files
committed
Merge branch '2025.3' into 2026.1
2 parents fcd738d + 97ca846 commit d38fb4e

9 files changed

Lines changed: 287 additions & 1 deletion

File tree

src/main/kotlin/creator/custom/types/GradlePluginSelectorCreatorProperty.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.demonwav.mcdev.creator.custom.model.TemplateApi
3030
import com.demonwav.mcdev.creator.custom.types.GradlePluginSelectorCreatorProperty.Holder
3131
import com.demonwav.mcdev.util.SemanticVersion
3232
import com.demonwav.mcdev.util.getOrLogException
33+
import com.demonwav.mcdev.util.toBooleanLenient
3334
import com.github.kittinunf.fuel.core.Request
3435
import com.github.kittinunf.fuel.core.extensions.authentication
3536
import com.intellij.openapi.diagnostic.thisLogger
@@ -48,7 +49,6 @@ import java.util.function.Function
4849
import kotlinx.coroutines.Dispatchers
4950
import kotlinx.coroutines.launch
5051
import kotlinx.coroutines.withContext
51-
import org.jetbrains.kotlin.cli.common.toBooleanLenient
5252

5353
class GradlePluginSelectorCreatorProperty(
5454
descriptor: TemplatePropertyDescriptor,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Minecraft Development for IntelliJ
3+
*
4+
* https://mcdev.io/
5+
*
6+
* Copyright (C) 2026 minecraft-dev
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published
10+
* by the Free Software Foundation, version 3.0 only.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package com.demonwav.mcdev.platform.bukkit.completion
22+
23+
import com.intellij.codeInsight.completion.CompletionContributor
24+
import com.intellij.codeInsight.completion.CompletionType
25+
import com.intellij.patterns.PlatformPatterns
26+
import com.intellij.psi.PsiClass
27+
28+
class BukkitEventHandlerCompletionContributor : CompletionContributor() {
29+
init {
30+
extend(
31+
CompletionType.BASIC,
32+
PlatformPatterns.psiElement().inside(PsiClass::class.java),
33+
BukkitEventHandlerCompletionProvider()
34+
)
35+
}
36+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Minecraft Development for IntelliJ
3+
*
4+
* https://mcdev.io/
5+
*
6+
* Copyright (C) 2026 minecraft-dev
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published
10+
* by the Free Software Foundation, version 3.0 only.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package com.demonwav.mcdev.platform.bukkit.completion
22+
23+
import com.demonwav.mcdev.platform.bukkit.util.BukkitConstants
24+
import com.demonwav.mcdev.util.findContainingClass
25+
import com.demonwav.mcdev.util.findContainingMethod
26+
import com.intellij.codeInsight.completion.CompletionParameters
27+
import com.intellij.codeInsight.completion.CompletionProvider
28+
import com.intellij.codeInsight.completion.CompletionResultSet
29+
import com.intellij.codeInsight.completion.PrioritizedLookupElement
30+
import com.intellij.codeInsight.lookup.LookupElementBuilder
31+
import com.intellij.icons.AllIcons
32+
import com.intellij.psi.PsiModifier
33+
import com.intellij.psi.impl.JavaPsiFacadeEx
34+
import com.intellij.psi.search.GlobalSearchScope
35+
import com.intellij.psi.search.searches.ClassInheritorsSearch
36+
import com.intellij.util.ProcessingContext
37+
38+
class BukkitEventHandlerCompletionProvider : CompletionProvider<CompletionParameters>() {
39+
40+
override fun addCompletions(
41+
completionParameters: CompletionParameters,
42+
processingContext: ProcessingContext,
43+
completionResultSet: CompletionResultSet
44+
) {
45+
val prefix = completionResultSet.prefixMatcher.prefix
46+
if (!prefix.startsWith("on") || prefix.length == 2) {
47+
return
48+
}
49+
50+
val position = completionParameters.position
51+
val containingClass = position.findContainingClass() ?: return
52+
val project = position.project
53+
val facade = JavaPsiFacadeEx.getInstance(project)
54+
55+
val eventListenerClass = facade.findClass(BukkitConstants.LISTENER_CLASS, GlobalSearchScope.allScope(project)) ?: return
56+
if (!containingClass.isInheritor(eventListenerClass, true)) {
57+
return
58+
}
59+
60+
if (position.findContainingMethod() != null) {
61+
return
62+
}
63+
64+
val scope = GlobalSearchScope.allScope(project)
65+
val eventBaseClass = facade.findClass(BukkitConstants.EVENT_CLASS, scope) ?: return
66+
val eventNameFilter = prefix.substring(2).lowercase()
67+
68+
ClassInheritorsSearch.search(eventBaseClass, scope, true)
69+
.forEach { psiClass ->
70+
if (psiClass.isInterface || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
71+
return@forEach
72+
}
73+
74+
val eventSimpleName = psiClass.name ?: return@forEach
75+
if (eventNameFilter.isNotEmpty() && !eventSimpleName.lowercase().startsWith(eventNameFilter)) {
76+
return@forEach
77+
}
78+
79+
val lookupString = "on$eventSimpleName"
80+
val qualifiedName = psiClass.qualifiedName
81+
82+
val element = LookupElementBuilder
83+
.create(lookupString)
84+
.withPresentableText("$lookupString()")
85+
.withTailText(" - $qualifiedName", true)
86+
.withTypeText("@EventHandler")
87+
.withIcon(AllIcons.Nodes.Method)
88+
.withBaseLookupString(lookupString)
89+
.withBoldness(true)
90+
.withInsertHandler(BukkitEventHandlerInsertHandler(psiClass))
91+
92+
completionResultSet.addElement(
93+
PrioritizedLookupElement.withPriority(element, 100.0)
94+
)
95+
}
96+
}
97+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Minecraft Development for IntelliJ
3+
*
4+
* https://mcdev.io/
5+
*
6+
* Copyright (C) 2026 minecraft-dev
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published
10+
* by the Free Software Foundation, version 3.0 only.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package com.demonwav.mcdev.platform.bukkit.completion
22+
23+
import com.demonwav.mcdev.util.psiType
24+
import com.intellij.codeInsight.completion.InsertHandler
25+
import com.intellij.codeInsight.completion.InsertionContext
26+
import com.intellij.codeInsight.intention.impl.TypeExpression
27+
import com.intellij.codeInsight.lookup.LookupElement
28+
import com.intellij.codeInsight.template.TemplateManager
29+
import com.intellij.codeInsight.template.impl.TemplateSettings
30+
import com.intellij.codeInsight.template.impl.Variable
31+
import com.intellij.psi.PsiClass
32+
import com.jetbrains.rd.util.string.printToString
33+
34+
class BukkitEventHandlerInsertHandler(
35+
private val psiClass: PsiClass
36+
) : InsertHandler<LookupElement> {
37+
38+
override fun handleInsert(insertionContext: InsertionContext, lookupElement: LookupElement) {
39+
insertionContext.document.deleteString(
40+
insertionContext.startOffset,
41+
insertionContext.tailOffset
42+
)
43+
44+
val sourceTemplate = TemplateSettings.getInstance().getTemplate("event_handler", "Bukkit") ?: return
45+
val template = sourceTemplate.copy()
46+
47+
val classTypeExpr = TypeExpression(insertionContext.project, listOf(psiClass.psiType))
48+
49+
val index = template.variables.indexOfFirst { it.name == "EVENT_CLASS" }
50+
if (index != -1) {
51+
template.removeVariable(index)
52+
}
53+
54+
template.addVariable(Variable("EVENT_CLASS", classTypeExpr, classTypeExpr, false, false));
55+
56+
TemplateManager.getInstance(insertionContext.project).startTemplate(insertionContext.editor, template)
57+
}
58+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Minecraft Development for IntelliJ
3+
*
4+
* https://mcdev.io/
5+
*
6+
* Copyright (C) 2026 minecraft-dev
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published
10+
* by the Free Software Foundation, version 3.0 only.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package com.demonwav.mcdev.platform.bukkit.macro
22+
23+
import com.intellij.codeInsight.template.Expression
24+
import com.intellij.codeInsight.template.ExpressionContext
25+
import com.intellij.codeInsight.template.Result
26+
import com.intellij.codeInsight.template.TextResult
27+
import com.intellij.codeInsight.template.macro.MacroBase
28+
29+
class BukkitEventNameMacro : MacroBase("bukkitEventName", "Usage: bukkitEventName(ClassType)") {
30+
override fun calculateResult(
31+
params: Array<out Expression?>,
32+
context: ExpressionContext?,
33+
quick: Boolean
34+
): Result? {
35+
val text = params[0]
36+
?.calculateResult(context)
37+
?.toString() ?: return null
38+
39+
val result = text.split("\\.").last().removeSuffix("Event")
40+
return TextResult(result)
41+
}
42+
}

src/main/kotlin/util/utils.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import com.intellij.psi.PsiFile
4747
import com.intellij.psi.util.PsiUtil
4848
import java.lang.invoke.MethodHandles
4949
import java.util.Locale
50+
import java.util.Locale.getDefault
5051
import java.util.concurrent.CancellationException
5152
import java.util.regex.PatternSyntaxException
5253
import kotlin.math.min
@@ -351,6 +352,13 @@ fun String.toRegexOrDefault(@Language("RegExp") default: String): Regex {
351352
return this.toRegexOrNull() ?: default.toRegex()
352353
}
353354

355+
fun String?.toBooleanLenient(): Boolean? = when (this?.lowercase()) {
356+
null -> false
357+
in listOf("", "yes", "true", "on", "y") -> true
358+
in listOf("no", "false", "off", "n") -> false
359+
else -> null
360+
}
361+
354362
// Bit of a hack, but this allows us to get the class object for top level declarations without having to
355363
// put the whole class name in as a string (easier to refactor, etc.)
356364
@Suppress("NOTHING_TO_INLINE") // In order for this to work this function must be `inline`

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,17 @@
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+
542+
<defaultLiveTemplates file="/liveTemplates/Bukkit.xml"/>
543+
544+
<liveTemplateMacro implementation="com.demonwav.mcdev.platform.bukkit.macro.BukkitEventNameMacro"/>
545+
535546
<!--endregion-->
536547

537548
<!--region SPONGE-->
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!--
2+
Minecraft Development for IntelliJ
3+
4+
https://mcdev.io/
5+
6+
Copyright (C) 2026 minecraft-dev
7+
8+
This program is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU Lesser General Public License as published
10+
by the Free Software Foundation, version 3.0 only.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public License
18+
along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
-->
20+
21+
<templateSet group="Bukkit">
22+
<template
23+
name="event_handler"
24+
value="@org.bukkit.event.EventHandler&#10;public void on$NAME$($EVENT_CLASS$ $PARAM_NAME$) {&#10;$END$&#10;}"
25+
toReformat="true"
26+
toShortenFQNames="true"
27+
key="live.template.bukkit.event_handler.description"
28+
resource-bundle="messages.MinecraftDevelopment">
29+
<variable name="NAME" expression="bukkitEventName(EVENT_CLASS)" alwaysStopAt="true"/>
30+
<variable name="PARAM_NAME" expression="&quot;event&quot;" alwaysStopAt="true"/>
31+
</template>
32+
</templateSet>

src/main/resources/messages/MinecraftDevelopment.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,5 @@ template.provider.builtin.label=Built In
370370
template.provider.remote.label=Remote
371371
template.provider.local.label=Local
372372
template.provider.zip.label=Archive
373+
374+
live.template.bukkit.event_handler.description=Create an event handler

0 commit comments

Comments
 (0)