Skip to content

Commit a060b5b

Browse files
committed
Add fabric entrypoints completion
1 parent 638c35f commit a060b5b

File tree

1 file changed

+68
-1
lines changed

1 file changed

+68
-1
lines changed

src/main/kotlin/platform/fabric/reference/EntryPointReference.kt

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@
2020

2121
package com.demonwav.mcdev.platform.fabric.reference
2222

23+
import com.demonwav.mcdev.platform.fabric.util.FabricConstants
24+
import com.demonwav.mcdev.util.fullQualifiedName
2325
import com.demonwav.mcdev.util.manipulator
2426
import com.demonwav.mcdev.util.reference.InspectionReference
27+
import com.intellij.codeInsight.completion.JavaLookupElementBuilder
2528
import com.intellij.json.psi.JsonStringLiteral
2629
import com.intellij.openapi.util.TextRange
2730
import com.intellij.psi.JavaPsiFacade
2831
import com.intellij.psi.PsiClass
32+
import com.intellij.psi.PsiClassType
2933
import com.intellij.psi.PsiElement
3034
import com.intellij.psi.PsiElementResolveResult
3135
import com.intellij.psi.PsiField
@@ -36,6 +40,8 @@ import com.intellij.psi.PsiReference
3640
import com.intellij.psi.PsiReferenceBase
3741
import com.intellij.psi.PsiReferenceProvider
3842
import com.intellij.psi.ResolveResult
43+
import com.intellij.psi.search.searches.ClassInheritorsSearch
44+
import com.intellij.util.ArrayUtil
3945
import com.intellij.util.IncorrectOperationException
4046
import com.intellij.util.ProcessingContext
4147

@@ -130,7 +136,34 @@ object EntryPointReference : PsiReferenceProvider() {
130136

131137
fun isEntryPointReference(reference: PsiReference) = reference is Reference
132138

133-
private class Reference(
139+
fun isValidEntrypointClass(element: PsiClass): Boolean {
140+
val psiFacade = JavaPsiFacade.getInstance(element.project)
141+
var inheritsEntrypointInterface = false
142+
for (entrypoint in FabricConstants.ENTRYPOINTS) {
143+
val entrypointClass = psiFacade.findClass(entrypoint, element.resolveScope)
144+
?: continue
145+
if (element.isInheritor(entrypointClass, true)) {
146+
inheritsEntrypointInterface = true
147+
break
148+
}
149+
}
150+
return inheritsEntrypointInterface
151+
}
152+
153+
fun isValidEntrypointField(field: PsiField): Boolean {
154+
if (!field.hasModifierProperty(PsiModifier.PUBLIC) || !field.hasModifierProperty(PsiModifier.STATIC)) {
155+
return false
156+
}
157+
158+
val fieldTypeClass = (field.type as? PsiClassType)?.resolve()
159+
return fieldTypeClass != null && isValidEntrypointClass(fieldTypeClass)
160+
}
161+
162+
fun isValidEntrypointMethod(method: PsiMethod): Boolean {
163+
return method.hasModifierProperty(PsiModifier.PUBLIC) && !method.hasParameters()
164+
}
165+
166+
class Reference(
134167
element: JsonStringLiteral,
135168
range: TextRange,
136169
private val innerClassDepth: Int,
@@ -186,5 +219,39 @@ object EntryPointReference : PsiReferenceProvider() {
186219
return manipulator.handleContentChange(element, classRange, targetClass.qualifiedName)
187220
}
188221
}
222+
223+
override fun getVariants(): Array<Any> {
224+
val manipulator = element.manipulator
225+
?: return ArrayUtil.EMPTY_OBJECT_ARRAY
226+
227+
val range = manipulator.getRangeInElement(element)
228+
val text = element.text.substring(range.startOffset, range.endOffset)
229+
val parts = text.split("::", limit = 2)
230+
231+
val variants = mutableListOf<Any>()
232+
if (!isMemberReference) {
233+
val psiFacade = JavaPsiFacade.getInstance(element.project)
234+
for (entrypoint in FabricConstants.ENTRYPOINTS) {
235+
val entrypointClass = psiFacade.findClass(entrypoint, element.resolveScope)
236+
?: continue
237+
ClassInheritorsSearch.search(entrypointClass, true)
238+
.mapNotNullTo(variants) {
239+
val shortName = it.name ?: return@mapNotNullTo null
240+
val fqName = it.fullQualifiedName ?: return@mapNotNullTo null
241+
JavaLookupElementBuilder.forClass(it, fqName, true).withPresentableText(shortName)
242+
}
243+
}
244+
} else if (parts.size >= 2) {
245+
val psiFacade = JavaPsiFacade.getInstance(element.project)
246+
val className = parts[0].replace('$', '.')
247+
val clazz = psiFacade.findClass(className, element.resolveScope)
248+
if (clazz != null) {
249+
clazz.fields.filterTo(variants, ::isValidEntrypointField)
250+
clazz.methods.filterTo(variants, ::isValidEntrypointMethod)
251+
}
252+
}
253+
254+
return variants.toTypedArray()
255+
}
189256
}
190257
}

0 commit comments

Comments
 (0)