Skip to content

Commit 1d029a3

Browse files
Add dynamic selectors to method completion (#2617)
* add dynamic selector to method completion * Update src/main/kotlin/platform/mixin/reference/MixinSelectors.kt Co-authored-by: Joseph Burton <burtonjae@hotmail.co.uk> --------- Co-authored-by: Joseph Burton <burtonjae@hotmail.co.uk>
1 parent bcef038 commit 1d029a3

2 files changed

Lines changed: 76 additions & 5 deletions

File tree

src/main/kotlin/platform/mixin/reference/AbstractMethodReference.kt

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package com.demonwav.mcdev.platform.mixin.reference
2222

2323
import com.demonwav.mcdev.platform.mixin.handlers.MixinAnnotationHandler
24+
import com.demonwav.mcdev.platform.mixin.handlers.injectionPoint.InjectionPoint
2425
import com.demonwav.mcdev.platform.mixin.reference.target.TargetReference
2526
import com.demonwav.mcdev.platform.mixin.util.ClassAndMethodNode
2627
import com.demonwav.mcdev.platform.mixin.util.bytecode
@@ -39,6 +40,7 @@ import com.demonwav.mcdev.util.reference.completeToLiteral
3940
import com.demonwav.mcdev.util.toResolveResults
4041
import com.demonwav.mcdev.util.toTypedArray
4142
import com.intellij.codeInsight.completion.JavaLookupElementBuilder
43+
import com.intellij.codeInsight.completion.PrioritizedLookupElement
4244
import com.intellij.codeInsight.lookup.LookupElementBuilder
4345
import com.intellij.psi.PsiAnnotation
4446
import com.intellij.psi.PsiArrayInitializerMemberValue
@@ -193,7 +195,16 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference
193195
}
194196
}
195197

196-
return createLookup(context, methods.asSequence().map { ClassAndMethodNode(target, it) }, uniqueMethods)
198+
val dynamicSelectors = MixinSelectorParser.EP_NAME.extensionList.asSequence()
199+
.filterIsInstance<DynamicSelectorParser>()
200+
.map { "@${it.id}" }
201+
202+
return createLookup(
203+
context,
204+
methods.asSequence().map { ClassAndMethodNode(target, it) },
205+
uniqueMethods,
206+
dynamicSelectors
207+
)
197208
}
198209

199210
private fun collectVariants(context: PsiElement, targets: Collection<ClassNode>): Array<Any> {
@@ -227,13 +238,18 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference
227238
}
228239
}
229240

230-
return createLookup(context, allMethods.asSequence(), uniqueMethods)
241+
val dynamicSelectors = MixinSelectorParser.EP_NAME.extensionList.asSequence()
242+
.filterIsInstance<DynamicSelectorParser>()
243+
.map { "@${it.id}" }
244+
245+
return createLookup(context, allMethods.asSequence(), uniqueMethods, dynamicSelectors)
231246
}
232247

233248
private fun createLookup(
234249
context: PsiElement,
235250
methods: Sequence<ClassAndMethodNode>,
236251
uniqueMethods: Set<String>,
252+
dynamicSelectors: Sequence<String>
237253
): Array<Any> {
238254
return methods
239255
.map { m ->
@@ -256,8 +272,17 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference
256272
null,
257273
)
258274
.withPresentableText(m.method.name)
259-
addCompletionInfo(builder, context, targetMethodInfo)
260-
}.toTypedArray()
275+
PrioritizedLookupElement.withPriority(
276+
addCompletionInfo(builder, context, targetMethodInfo),
277+
1.0
278+
)
279+
}.plus(dynamicSelectors.map {
280+
PrioritizedLookupElement.withPriority(
281+
LookupElementBuilder.create(it).completeDynamicSelector(context),
282+
0.0
283+
)
284+
})
285+
.toTypedArray()
261286
}
262287

263288
open val requireDescriptor = false
@@ -269,4 +294,15 @@ abstract class AbstractMethodReference : PolyReferenceResolver(), MixinReference
269294
): LookupElementBuilder {
270295
return builder.completeToLiteral(context)
271296
}
297+
298+
private fun LookupElementBuilder.completeDynamicSelector(context: PsiElement): LookupElementBuilder {
299+
val id = lookupString.removePrefix("@")
300+
val parser = MixinSelectorParser.EP_NAME.extensionList.asSequence()
301+
.filterIsInstance<DynamicSelectorParser>()
302+
.firstOrNull { id in it.validIds } ?: return completeToLiteral(context)
303+
304+
return completeToLiteral(context) { editor, element ->
305+
parser.onCompleted(editor, element)
306+
}
307+
}
272308
}

src/main/kotlin/platform/mixin/reference/MixinSelectors.kt

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import com.demonwav.mcdev.util.constantStringValue
3636
import com.demonwav.mcdev.util.descriptor
3737
import com.demonwav.mcdev.util.findAnnotation
3838
import com.demonwav.mcdev.util.findContainingClass
39+
import com.demonwav.mcdev.util.findContainingModifierList
3940
import com.demonwav.mcdev.util.findField
4041
import com.demonwav.mcdev.util.findMethods
4142
import com.demonwav.mcdev.util.findQualifiedClass
@@ -45,6 +46,7 @@ import com.demonwav.mcdev.util.mapToArray
4546
import com.demonwav.mcdev.util.resolveClass
4647
import com.demonwav.mcdev.util.resolveType
4748
import com.demonwav.mcdev.util.resolveTypeArray
49+
import com.intellij.openapi.editor.Editor
4850
import com.intellij.openapi.extensions.ExtensionPointName
4951
import com.intellij.openapi.project.Project
5052
import com.intellij.openapi.util.RecursionManager
@@ -55,10 +57,14 @@ import com.intellij.psi.PsiCallExpression
5557
import com.intellij.psi.PsiClass
5658
import com.intellij.psi.PsiElement
5759
import com.intellij.psi.PsiField
60+
import com.intellij.psi.PsiLiteral
5861
import com.intellij.psi.PsiMember
5962
import com.intellij.psi.PsiMethod
63+
import com.intellij.psi.PsiModifierList
6064
import com.intellij.psi.PsiNameValuePair
6165
import com.intellij.psi.PsiTypes
66+
import com.intellij.psi.codeStyle.CodeStyleManager
67+
import com.intellij.psi.codeStyle.JavaCodeStyleManager
6268
import com.intellij.psi.search.GlobalSearchScope
6369
import com.intellij.psi.search.searches.AnnotatedMembersSearch
6470
import com.intellij.psi.search.searches.MethodReferencesSearch
@@ -418,7 +424,7 @@ private fun findNamespace(
418424

419425
private val DYNAMIC_SELECTOR_PATTERN = "(?i)^@([a-z]+(:[a-z]+)?)(\\((.*)\\))?$".toRegex()
420426

421-
abstract class DynamicSelectorParser(id: String, vararg aliases: String) : MixinSelectorParser {
427+
abstract class DynamicSelectorParser(val id: String, vararg aliases: String) : MixinSelectorParser {
422428
val validIds = aliases.toSet() + id
423429

424430
final override fun parse(value: String, context: PsiElement): MixinSelector? {
@@ -431,6 +437,9 @@ abstract class DynamicSelectorParser(id: String, vararg aliases: String) : Mixin
431437
}
432438

433439
abstract fun parseDynamic(args: String, context: PsiElement): MixinSelector?
440+
441+
open fun onCompleted(editor: Editor, reference: PsiLiteral) {
442+
}
434443
}
435444

436445
// @Desc
@@ -546,6 +555,32 @@ class DescSelectorParser : DynamicSelectorParser("Desc", "mixin:Desc") {
546555
}
547556
}
548557

558+
override fun onCompleted(editor: Editor, reference: PsiLiteral) {
559+
val modifierList = reference.findContainingModifierList() ?: return
560+
if (modifierList.hasAnnotation(DESC)) {
561+
return
562+
}
563+
564+
val project = reference.project
565+
566+
val descAnnotation = modifierList.addAfter(
567+
JavaPsiFacade.getElementFactory(project)
568+
.createAnnotationFromText("@${DESC}(\"\")", reference),
569+
null
570+
)
571+
572+
// add imports and reformat
573+
JavaCodeStyleManager.getInstance(project).shortenClassReferences(descAnnotation)
574+
JavaCodeStyleManager.getInstance(project).optimizeImports(modifierList.containingFile)
575+
val formattedModifierList = CodeStyleManager.getInstance(project).reformat(modifierList) as PsiModifierList
576+
577+
// move the caret to @Desc("<caret>")
578+
val formattedDescAnnotation = formattedModifierList.findAnnotation(DESC)
579+
?: return
580+
val descLiteral = formattedDescAnnotation.findDeclaredAttributeValue(null) ?: return
581+
editor.caretModel.moveToOffset(descLiteral.textRange.startOffset + 1)
582+
}
583+
549584
object Util {
550585
fun descSelectorFromAnnotation(descAnnotation: PsiAnnotation): DescSelector? {
551586
val explicitOwner = descAnnotation.findAttributeValue("owner")

0 commit comments

Comments
 (0)